Haraka 3.0.3 → 3.0.4
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.
- package/.eslintrc.yaml +5 -9
- package/.prettierrc.yml +1 -0
- package/CONTRIBUTORS.md +11 -0
- package/Changes.md +1365 -1214
- package/Plugins.md +117 -105
- package/README.md +4 -13
- package/bin/haraka +197 -298
- package/config/auth_flat_file.ini +1 -0
- package/config/dhparams.pem +8 -0
- package/config/mail_from.is_resolvable.ini +4 -2
- package/config/me +1 -0
- package/config/outbound.ini +0 -2
- package/config/plugins +36 -35
- package/config/smtp.ini +0 -1
- package/config/smtp.json +17 -0
- package/config/tls_cert.pem +23 -0
- package/config/tls_key.pem +28 -0
- package/connection.js +46 -73
- package/contrib/bsd-rc.d/haraka +3 -1
- package/contrib/plugin2npm.sh +6 -36
- package/docs/CoreConfig.md +2 -2
- package/docs/Logging.md +7 -21
- package/docs/Outbound.md +104 -201
- package/docs/Plugins.md +2 -2
- package/docs/Transaction.md +59 -82
- package/docs/plugins/queue/smtp_proxy.md +5 -10
- package/docs/plugins/tls.md +29 -9
- package/endpoint.js +16 -13
- package/haraka.js +10 -14
- package/host_pool.js +5 -5
- package/line_socket.js +3 -4
- package/logger.js +44 -28
- package/outbound/client_pool.js +27 -23
- package/outbound/config.js +4 -6
- package/outbound/fsync_writestream.js +1 -1
- package/outbound/hmail.js +178 -218
- package/outbound/index.js +86 -99
- package/outbound/qfile.js +1 -1
- package/outbound/queue.js +51 -44
- package/outbound/timer_queue.js +3 -2
- package/outbound/tls.js +19 -7
- package/package.json +59 -48
- package/plugins/.eslintrc.yaml +0 -6
- package/plugins/auth/auth_base.js +4 -2
- package/plugins/auth/auth_proxy.js +14 -12
- package/plugins/auth/auth_vpopmaild.js +1 -1
- package/plugins/block_me.js +1 -1
- package/plugins/data.signatures.js +2 -4
- package/plugins/early_talker.js +2 -1
- package/plugins/mail_from.is_resolvable.js +65 -135
- package/plugins/queue/deliver.js +4 -5
- package/plugins/queue/lmtp.js +11 -14
- package/plugins/queue/qmail-queue.js +2 -2
- package/plugins/queue/quarantine.js +2 -2
- package/plugins/queue/rabbitmq.js +16 -17
- package/plugins/queue/smtp_forward.js +3 -3
- package/plugins/queue/smtp_proxy.js +10 -1
- package/plugins/queue/test.js +2 -2
- package/plugins/rcpt_to.host_list_base.js +5 -5
- package/plugins/rcpt_to.in_host_list.js +2 -2
- package/plugins/relay.js +6 -7
- package/plugins/reseed_rng.js +1 -1
- package/plugins/status.js +37 -33
- package/plugins/tls.js +2 -2
- package/plugins/xclient.js +3 -2
- package/plugins.js +50 -54
- package/run_tests +3 -30
- package/server.js +190 -190
- package/smtp_client.js +30 -23
- package/{tests → test}/config/plugins +0 -2
- package/{tests → test}/config/smtp.ini +1 -1
- package/test/config/tls/example.com/_.example.com.key +28 -0
- package/test/config/tls/example.com/example.com.crt +25 -0
- package/test/connection.js +302 -0
- package/test/endpoint.js +94 -0
- package/{tests → test}/fixtures/line_socket.js +1 -1
- package/{tests → test}/fixtures/util_hmailitem.js +19 -25
- package/{tests → test}/host_pool.js +42 -57
- package/test/logger.js +258 -0
- package/test/outbound/hmail.js +141 -0
- package/test/outbound/index.js +220 -0
- package/test/outbound/qfile.js +126 -0
- package/test/outbound_bounce_net_errors.js +142 -0
- package/{tests → test}/outbound_bounce_rfc3464.js +110 -122
- package/test/plugins/auth/auth_base.js +484 -0
- package/test/plugins/auth/auth_vpopmaild.js +83 -0
- package/test/plugins/early_talker.js +104 -0
- package/test/plugins/mail_from.is_resolvable.js +35 -0
- package/test/plugins/queue/smtp_forward.js +206 -0
- package/test/plugins/rcpt_to.host_list_base.js +122 -0
- package/test/plugins/rcpt_to.in_host_list.js +193 -0
- package/test/plugins/relay.js +303 -0
- package/test/plugins/status.js +130 -0
- package/test/plugins/tls.js +70 -0
- package/test/plugins.js +228 -0
- package/test/rfc1869.js +73 -0
- package/test/server.js +491 -0
- package/test/smtp_client.js +299 -0
- package/test/tls_socket.js +273 -0
- package/test/transaction.js +270 -0
- package/tls_socket.js +202 -252
- package/transaction.js +8 -23
- package/CONTRIBUTING.md +0 -1
- package/bin/dkimverify +0 -40
- package/config/access.domains +0 -13
- package/config/attachment.ctype.regex +0 -2
- package/config/attachment.filename.regex +0 -1
- package/config/avg.ini +0 -5
- package/config/bounce.ini +0 -15
- package/config/data.headers.ini +0 -61
- package/config/dkim/dkim_key_gen.sh +0 -78
- package/config/dkim_sign.ini +0 -4
- package/config/dkim_verify.ini +0 -7
- package/config/dnsbl.ini +0 -23
- package/config/greylist.ini +0 -43
- package/config/helo.checks.ini +0 -52
- package/config/messagesniffer.ini +0 -18
- package/config/spamassassin.ini +0 -56
- package/dkim.js +0 -614
- package/docs/plugins/avg.md +0 -35
- package/docs/plugins/bounce.md +0 -69
- package/docs/plugins/clamd.md +0 -147
- package/docs/plugins/esets.md +0 -8
- package/docs/plugins/greylist.md +0 -90
- package/docs/plugins/helo.checks.md +0 -135
- package/docs/plugins/messagesniffer.md +0 -163
- package/docs/plugins/spamassassin.md +0 -180
- package/outbound/mx_lookup.js +0 -70
- package/plugins/auth/auth_ldap.js +0 -3
- package/plugins/avg.js +0 -162
- package/plugins/backscatterer.js +0 -25
- package/plugins/bounce.js +0 -381
- package/plugins/clamd.js +0 -382
- package/plugins/data.uribl.js +0 -4
- package/plugins/dkim_sign.js +0 -395
- package/plugins/dkim_verify.js +0 -62
- package/plugins/dns_list_base.js +0 -221
- package/plugins/dnsbl.js +0 -146
- package/plugins/dnswl.js +0 -58
- package/plugins/esets.js +0 -71
- package/plugins/graph.js +0 -5
- package/plugins/greylist.js +0 -645
- package/plugins/helo.checks.js +0 -533
- package/plugins/messagesniffer.js +0 -381
- package/plugins/rcpt_to.ldap.js +0 -3
- package/plugins/rcpt_to.max_count.js +0 -24
- package/plugins/spamassassin.js +0 -384
- package/tests/config/dkim/example.com/dns +0 -29
- package/tests/config/dkim/example.com/private +0 -6
- package/tests/config/dkim/example.com/public +0 -4
- package/tests/config/dkim/example.com/selector +0 -1
- package/tests/config/dkim.private.key +0 -6
- package/tests/config/dkim_sign.ini +0 -4
- package/tests/config/helo.checks.ini +0 -52
- package/tests/connection.js +0 -327
- package/tests/endpoint.js +0 -128
- package/tests/fixtures/vm_harness.js +0 -59
- package/tests/logger.js +0 -327
- package/tests/outbound/hmail.js +0 -112
- package/tests/outbound/index.js +0 -324
- package/tests/outbound/qfile.js +0 -67
- package/tests/outbound_bounce_net_errors.js +0 -173
- package/tests/plugins/auth/auth_base.js +0 -463
- package/tests/plugins/auth/auth_vpopmaild.js +0 -91
- package/tests/plugins/bounce.js +0 -307
- package/tests/plugins/clamd.js +0 -224
- package/tests/plugins/deprecated/relay_acl.js +0 -140
- package/tests/plugins/deprecated/relay_all.js +0 -59
- package/tests/plugins/dkim_sign.js +0 -315
- package/tests/plugins/dkim_signer.js +0 -108
- package/tests/plugins/dns_list_base.js +0 -259
- package/tests/plugins/dnsbl.js +0 -101
- package/tests/plugins/early_talker.js +0 -115
- package/tests/plugins/greylist.js +0 -58
- package/tests/plugins/helo.checks.js +0 -525
- package/tests/plugins/mail_from.is_resolvable.js +0 -116
- package/tests/plugins/queue/smtp_forward.js +0 -221
- package/tests/plugins/rcpt_to.host_list_base.js +0 -132
- package/tests/plugins/rcpt_to.in_host_list.js +0 -218
- package/tests/plugins/relay.js +0 -339
- package/tests/plugins/spamassassin.js +0 -171
- package/tests/plugins/status.js +0 -138
- package/tests/plugins/tls.js +0 -84
- package/tests/plugins.js +0 -247
- package/tests/rfc1869.js +0 -61
- package/tests/server.js +0 -510
- package/tests/smtp_client/auth.js +0 -105
- package/tests/smtp_client/basic.js +0 -101
- package/tests/smtp_client.js +0 -80
- package/tests/tls_socket.js +0 -333
- package/tests/transaction.js +0 -284
- /package/docs/{plugins → deprecated}/dkim_sign.md +0 -0
- /package/docs/{plugins → deprecated}/dkim_verify.md +0 -0
- /package/docs/{plugins → deprecated}/dnsbl.md +0 -0
- /package/docs/{plugins → deprecated}/dnswl.md +0 -0
- /package/{tests → test}/.eslintrc.yaml +0 -0
- /package/{tests → test}/config/auth_flat_file.ini +0 -0
- /package/{tests → test}/config/dhparams.pem +0 -0
- /package/{tests → test}/config/host_list +0 -0
- /package/{tests → test}/config/outbound_tls_cert.pem +0 -0
- /package/{tests → test}/config/outbound_tls_key.pem +0 -0
- /package/{tests → test}/config/smtp_forward.ini +0 -0
- /package/{tests → test}/config/tls/ec.pem +0 -0
- /package/{tests → test}/config/tls/haraka.local.pem +0 -0
- /package/{tests → test}/config/tls/mismatched.pem +0 -0
- /package/{tests → test}/config/tls.ini +0 -0
- /package/{tests → test}/config/tls_cert.pem +0 -0
- /package/{tests → test}/config/tls_key.pem +0 -0
- /package/{tests → test}/fixtures/todo_qfile.txt +0 -0
- /package/{tests → test}/installation/config/test-plugin-flat +0 -0
- /package/{tests → test}/installation/config/test-plugin.ini +0 -0
- /package/{tests → test}/installation/config/tls.ini +0 -0
- /package/{tests → test}/installation/node_modules/load_first/index.js +0 -0
- /package/{tests → test}/installation/node_modules/load_first/package.json +0 -0
- /package/{tests → test}/installation/node_modules/test-plugin/config/test-plugin-flat +0 -0
- /package/{tests → test}/installation/node_modules/test-plugin/config/test-plugin.ini +0 -0
- /package/{tests → test}/installation/node_modules/test-plugin/package.json +0 -0
- /package/{tests → test}/installation/node_modules/test-plugin/test-plugin.js +0 -0
- /package/{tests → test}/installation/plugins/base_plugin.js +0 -0
- /package/{tests → test}/installation/plugins/folder_plugin/index.js +0 -0
- /package/{tests → test}/installation/plugins/folder_plugin/package.json +0 -0
- /package/{tests → test}/installation/plugins/inherits.js +0 -0
- /package/{tests → test}/installation/plugins/load_first.js +0 -0
- /package/{tests → test}/installation/plugins/plugin.js +0 -0
- /package/{tests → test}/installation/plugins/tls.js +0 -0
- /package/{tests → test}/loud/config/dhparams.pem +0 -0
- /package/{tests → test}/loud/config/tls/goobered.pem +0 -0
- /package/{tests → test}/loud/config/tls.ini +0 -0
- /package/{tests → test}/mail_specimen/base64-root-part.txt +0 -0
- /package/{tests → test}/mail_specimen/varied-fold-lengths-preserve-data.txt +0 -0
- /package/{tests → test}/queue/1507509981169_1507509981169_0_61403_e0Y0Ym_1_fixed +0 -0
- /package/{tests → test}/queue/1507509981169_1507509981169_0_61403_e0Y0Ym_1_haraka +0 -0
- /package/{tests → test}/queue/1508269674999_1508269674999_0_34002_socVUF_1_haraka +0 -0
- /package/{tests → test}/queue/1508455115683_1508455115683_0_90253_9Q4o4V_1_haraka +0 -0
- /package/{tests → test}/queue/multibyte +0 -0
- /package/{tests → test}/queue/plain +0 -0
- /package/{tests → test}/queue/zero-length +0 -0
- /package/{tests → test}/test-queue/delete-me +0 -0
package/bin/haraka
CHANGED
|
@@ -1,19 +1,19 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
// this script takes inspiration from:
|
|
4
|
-
// https://github.com/visionmedia/express/blob/master/bin/express
|
|
5
4
|
// https://github.com/tnantoka/LooseLeaf/blob/master/bin/looseleaf
|
|
6
5
|
|
|
7
|
-
const
|
|
8
|
-
const
|
|
9
|
-
const
|
|
10
|
-
const path = require('path');
|
|
11
|
-
const os = require('os');
|
|
6
|
+
const child = require('node:child_process');
|
|
7
|
+
const fs = require('node:fs');
|
|
8
|
+
const net = require('node:net');
|
|
9
|
+
const path = require('node:path');
|
|
10
|
+
const os = require('node:os');
|
|
12
11
|
|
|
12
|
+
const nopt = require('nopt');
|
|
13
13
|
const utils = require('haraka-utils');
|
|
14
14
|
const sprintf = require('sprintf-js').sprintf;
|
|
15
15
|
const base = path.join(__dirname, '..');
|
|
16
|
-
const ver =
|
|
16
|
+
const ver = utils.getVersion(base)
|
|
17
17
|
const knownOpts = {
|
|
18
18
|
"version": Boolean,
|
|
19
19
|
"verbose": Boolean,
|
|
@@ -54,67 +54,66 @@ const shortHands = {
|
|
|
54
54
|
}
|
|
55
55
|
const parsed = nopt(knownOpts, shortHands, process.argv, 2);
|
|
56
56
|
|
|
57
|
-
const usage = [
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
const gl = path.join((b ? b : base), dir);
|
|
95
|
-
const pd = fs.readdirSync(gl);
|
|
96
|
-
|
|
97
|
-
pd.forEach(function (p) {
|
|
98
|
-
const stat = fs.statSync(`${gl}/${p}`);
|
|
99
|
-
if (stat.isFile() && ~p.search('.js')) {
|
|
100
|
-
plist += `\t${p.replace('.js', '')}\n`;
|
|
101
|
-
}
|
|
102
|
-
else if (stat.isDirectory()) {
|
|
103
|
-
subdirs.push(`${dir + p}/`);
|
|
57
|
+
const usage = `\x1B[32;40mHaraka.js\x1B[0m — A Node.js Email Server project
|
|
58
|
+
Usage: haraka [options] [path]
|
|
59
|
+
Options:
|
|
60
|
+
-v, --version \t\tOutputs version number
|
|
61
|
+
-h, --help \t\tOutputs this help message
|
|
62
|
+
-h NAME \t\tShows help for NAME
|
|
63
|
+
-c, --configs \t\tPath to your config directory
|
|
64
|
+
-i, --install \t\tCopies the default configs to a specified dir
|
|
65
|
+
-l, --list \t\tList the plugins bundled with Haraka
|
|
66
|
+
-p, --plugin \t\tGenerate a new plugin with the given name
|
|
67
|
+
-f, --force \t\tForce overwriting of old files
|
|
68
|
+
--qlist \t\tList the outbound queue
|
|
69
|
+
--qstat \t\tGet statistics on the outbound queue
|
|
70
|
+
--qunstick \t\tUnstick (force delivery) for a given domain
|
|
71
|
+
-o, --order \t\tShow all registered plugins and their run order
|
|
72
|
+
-t PLUGIN \t\tPlugin test mode
|
|
73
|
+
--------------- PLUGIN TEST MODE OPTIONS (all optional) --------------
|
|
74
|
+
--ip IP \t\tIP address to use
|
|
75
|
+
--helo HELO \t\tHELO to use
|
|
76
|
+
--ehlo EHLO \t\tEHLO to use
|
|
77
|
+
--envfrom FROM\t\tMAIL FROM to use
|
|
78
|
+
--envfrom TO \t\tRCPT TO(s) to use
|
|
79
|
+
--message FILE\t\tMessage file to use
|
|
80
|
+
--dump-mime \t\tDump the MIME structure and body text
|
|
81
|
+
--dump-stream \t\tDump the MessageStream to stdout
|
|
82
|
+
--skip-deny \t\tContinue running hooks after DENY/DENYSOFT
|
|
83
|
+
--set-relay \t\tSet connection.relaying
|
|
84
|
+
`;
|
|
85
|
+
|
|
86
|
+
function listPlugins (b, dir = 'plugins/') {
|
|
87
|
+
|
|
88
|
+
const inital_dir = path.join((b ?? base), dir);
|
|
89
|
+
const plugin_dirs = [ inital_dir ]
|
|
90
|
+
|
|
91
|
+
for (const d of fs.readdirSync(inital_dir)) {
|
|
92
|
+
if (fs.statSync(path.join(inital_dir, d)).isDirectory()) {
|
|
93
|
+
plugin_dirs.push(path.join(inital_dir, d));
|
|
104
94
|
}
|
|
105
|
-
}
|
|
95
|
+
}
|
|
106
96
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
97
|
+
let plugin_list = ``
|
|
98
|
+
for (const pd of plugin_dirs) {
|
|
99
|
+
plugin_list += `\n${pd.match(/plugins.*$/)[0]}\n`;
|
|
110
100
|
|
|
111
|
-
|
|
112
|
-
|
|
101
|
+
for (const d of fs.readdirSync(pd)) {
|
|
102
|
+
if (fs.statSync(path.join(pd, d)).isFile() && ~d.search('.js')) {
|
|
103
|
+
plugin_list += `\t${d.replace('.js', '')}\n`;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
113
107
|
|
|
108
|
+
plugin_list += `\nNPM packages (${b ?? base})\n`
|
|
109
|
+
const npm_plugins = []
|
|
110
|
+
for (const entry of fs.readdirSync(path.join(b ?? base, 'node_modules'))) {
|
|
111
|
+
if (!/^haraka-plugin-/.test(entry)) continue
|
|
112
|
+
npm_plugins.push(entry.split('-').slice(2).join('-'))
|
|
113
|
+
}
|
|
114
|
+
plugin_list += `\t${npm_plugins.join('\n\t')}\n`
|
|
114
115
|
|
|
115
|
-
|
|
116
|
-
function create (dirPath) {
|
|
117
|
-
console.log(`\x1b[32mcreate\x1b[0m: ${dirPath}`);
|
|
116
|
+
return plugin_list;
|
|
118
117
|
}
|
|
119
118
|
|
|
120
119
|
// Warning messsage
|
|
@@ -127,128 +126,73 @@ function fail (msg) {
|
|
|
127
126
|
process.exit(-1);
|
|
128
127
|
}
|
|
129
128
|
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
try {
|
|
133
|
-
if (fs.statSync(dstPath).isDirectory()) return;
|
|
134
|
-
}
|
|
135
|
-
catch (ignore) {}
|
|
136
|
-
|
|
137
|
-
try {
|
|
138
|
-
fs.mkdirSync(dstPath, { recursive: true });
|
|
139
|
-
create(dstPath);
|
|
140
|
-
}
|
|
141
|
-
catch (e) {
|
|
142
|
-
// File exists
|
|
143
|
-
console.error(e);
|
|
144
|
-
if (e.errno == 17) {
|
|
145
|
-
warning(e.message);
|
|
146
|
-
}
|
|
147
|
-
else {
|
|
148
|
-
throw e;
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
// Copy directory
|
|
154
|
-
function copyDir (srcPath, dstPath) {
|
|
155
|
-
|
|
156
|
-
mkDir(dstPath);
|
|
157
|
-
const files = fs.readdirSync(srcPath);
|
|
129
|
+
function setupHostname (confPath) {
|
|
130
|
+
utils.mkDir(confPath);
|
|
158
131
|
|
|
159
|
-
|
|
132
|
+
const hostname = `${os.hostname()}${os.EOL}`;
|
|
160
133
|
|
|
161
|
-
|
|
162
|
-
|
|
134
|
+
['me','host_list'].forEach(f => {
|
|
135
|
+
const cfPath = path.join(confPath, f);
|
|
163
136
|
|
|
164
|
-
|
|
165
|
-
|
|
137
|
+
try { if (fs.statSync(cfPath).isFile()) return; }
|
|
138
|
+
catch (ignore) { }
|
|
166
139
|
|
|
167
|
-
|
|
140
|
+
try { fs.writeFileSync(cfPath, hostname); }
|
|
141
|
+
catch (err) { warning(`Unable to write to config/${f}: ${err.message}`); }
|
|
142
|
+
})
|
|
143
|
+
}
|
|
168
144
|
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
// Copy to dstPath if file
|
|
174
|
-
else if (srcStat.isFile()) {
|
|
175
|
-
// NOT overwrite file
|
|
176
|
-
copyFile(srcFile, dstFile);
|
|
177
|
-
}
|
|
178
|
-
}
|
|
145
|
+
function setupBaseConfig (confPath) {
|
|
146
|
+
utils.copyFile(path.join(base, 'config', 'smtp.ini'), path.join(confPath, 'smtp.ini'));
|
|
147
|
+
utils.copyFile(path.join(base, 'config', 'log.ini'), path.join(confPath, 'log.ini'));
|
|
148
|
+
utils.copyFile(path.join(base, 'config', 'plugins'), path.join(confPath, 'plugins'));
|
|
179
149
|
}
|
|
180
150
|
|
|
181
|
-
function
|
|
151
|
+
function setupRequire () {
|
|
182
152
|
|
|
153
|
+
process.env.HARAKA = parsed.configs;
|
|
183
154
|
try {
|
|
184
|
-
|
|
185
|
-
warning(`EEXIST, File exists '${dstFile}'`);
|
|
186
|
-
return;
|
|
187
|
-
}
|
|
188
|
-
throw `EEXIST but not a file: '${dstFile}'`;
|
|
155
|
+
require.paths.push(path.join(process.env.HARAKA, 'node_modules'));
|
|
189
156
|
}
|
|
190
157
|
catch (e) {
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
}
|
|
197
|
-
else {
|
|
198
|
-
console.log(`copy ${srcFile} to ${dstFile}`);
|
|
199
|
-
throw e;
|
|
200
|
-
}
|
|
158
|
+
process.env.NODE_PATH = process.env.NODE_PATH ?
|
|
159
|
+
(`${process.env.NODE_PATH}:${path.join(process.env.HARAKA, 'node_modules')}`)
|
|
160
|
+
:
|
|
161
|
+
(path.join(process.env.HARAKA, 'node_modules'));
|
|
162
|
+
require('module')._initPaths(); // Horrible hack
|
|
201
163
|
}
|
|
202
164
|
}
|
|
203
165
|
|
|
204
|
-
function
|
|
205
|
-
mkDir(confPath);
|
|
166
|
+
function noop () {}
|
|
206
167
|
|
|
207
|
-
|
|
168
|
+
const readme = `Haraka
|
|
208
169
|
|
|
209
|
-
|
|
210
|
-
const cfPath = path.join(confPath, f);
|
|
170
|
+
Congratulations on creating a new installation of Haraka.
|
|
211
171
|
|
|
212
|
-
|
|
213
|
-
catch (ignore) { }
|
|
172
|
+
This directory contains two key directories for how Haraka will function:
|
|
214
173
|
|
|
215
|
-
|
|
216
|
-
catch (err) { warning(`Unable to write to config/${f}: ${err.message}`); }
|
|
217
|
-
})
|
|
218
|
-
}
|
|
174
|
+
- config
|
|
219
175
|
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
copyFile(path.join(base, 'config', 'plugins'), path.join(confPath, 'plugins'));
|
|
224
|
-
copyDir(path.join(base, 'config', 'dkim'), path.join(confPath, 'dkim'));
|
|
225
|
-
}
|
|
176
|
+
This directory contains configuration files for Haraka. The
|
|
177
|
+
directory contains the default configuration. You probably want
|
|
178
|
+
to modify some files in here, particularly 'smtp.ini'.
|
|
226
179
|
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
" This directory contains documentation for your plugins.",
|
|
244
|
-
"",
|
|
245
|
-
"Documentation for Haraka is available via `haraka -h <name> where the name",
|
|
246
|
-
"is either the name of a plugin (without the .js extension) or the name of",
|
|
247
|
-
"a core Haraka module, such as `Connection` or `Transaction`.",
|
|
248
|
-
"",
|
|
249
|
-
"To get documentation on writing a plugin type `haraka -h Plugins`.",
|
|
250
|
-
"",
|
|
251
|
-
].join("\n");
|
|
180
|
+
- plugins
|
|
181
|
+
|
|
182
|
+
This directory contains custom plugins which you write to run in
|
|
183
|
+
Haraka. The plugins which ship with Haraka are still available
|
|
184
|
+
to use.
|
|
185
|
+
|
|
186
|
+
- docs/plugins
|
|
187
|
+
|
|
188
|
+
This directory contains documentation for your plugins.
|
|
189
|
+
|
|
190
|
+
Documentation for Haraka is available via 'haraka -h <name>' where the name
|
|
191
|
+
is either the name of a plugin (without the .js extension) or the name of
|
|
192
|
+
a core Haraka module, such as 'Connection' or 'Transaction'.
|
|
193
|
+
|
|
194
|
+
To get documentation on writing a plugin type 'haraka -h Plugins'.
|
|
195
|
+
`;
|
|
252
196
|
|
|
253
197
|
const packageJson = JSON.stringify({
|
|
254
198
|
"name": "haraka_local",
|
|
@@ -282,19 +226,13 @@ const plugin_doc = [
|
|
|
282
226
|
"",
|
|
283
227
|
].join("\n");
|
|
284
228
|
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
const output = data.replace(/%(\w+)%/g, function (i, m1) { return info[m1] });
|
|
293
|
-
fs.writeSync(fd, output, null);
|
|
294
|
-
}
|
|
295
|
-
catch (e) {
|
|
296
|
-
warning(`Unable to create file: ${e}`);
|
|
297
|
-
}
|
|
229
|
+
|
|
230
|
+
function getHooks () { // see haraka/Haraka#3306
|
|
231
|
+
fs.readFileSync('docs/Plugins.md').toString()
|
|
232
|
+
.split('## Available Hooks')[1] // discard everything before this string
|
|
233
|
+
.split('### rcpt')[0] // discard everything after this string
|
|
234
|
+
.match(/\*\s(\S+)/gm) // grab the first word of lines starting with '* '
|
|
235
|
+
.map(a => a.replace(/^\* /, '').replace(/\\/g, '')) // strip list prefix and escapes
|
|
298
236
|
}
|
|
299
237
|
|
|
300
238
|
let config;
|
|
@@ -313,52 +251,49 @@ else if (parsed.list) {
|
|
|
313
251
|
else if (parsed.help) {
|
|
314
252
|
if (parsed.help === 'true') {
|
|
315
253
|
console.log(usage);
|
|
254
|
+
return
|
|
316
255
|
}
|
|
317
|
-
else {
|
|
318
|
-
let md_path;
|
|
319
|
-
const md_paths = [
|
|
320
|
-
path.join(base, 'docs', `${parsed.help}.md`),
|
|
321
|
-
path.join(base, 'docs', 'plugins', `${parsed.help}.md`),
|
|
322
|
-
path.join(base, 'docs', 'deprecated', `${parsed.help}.md`),
|
|
323
|
-
path.join(base, 'node_modules', `haraka-plugin-${parsed.help}`, 'README.md'),
|
|
324
|
-
];
|
|
325
|
-
if (parsed.configs) {
|
|
326
|
-
md_paths.unshift(path.join(parsed.configs, 'docs', 'plugins', `${parsed.help}.md`));
|
|
327
|
-
md_paths.unshift(path.join(parsed.configs, 'docs', `${parsed.help}.md`));
|
|
328
|
-
}
|
|
329
|
-
for (let i=0, j=md_paths.length; i<j; i++) {
|
|
330
|
-
const _md_path = md_paths[i];
|
|
331
|
-
if (fs.existsSync(_md_path)) {
|
|
332
|
-
md_path = [_md_path];
|
|
333
|
-
break;
|
|
334
|
-
}
|
|
335
|
-
}
|
|
336
|
-
if (!md_path) {
|
|
337
|
-
warning(`No documentation found for: ${parsed.help}`);
|
|
338
|
-
process.exit();
|
|
339
|
-
}
|
|
340
|
-
let pager = 'less';
|
|
341
|
-
const spawn = require('child_process').spawn;
|
|
342
|
-
if (process.env.PAGER) {
|
|
343
|
-
const pager_split = process.env.PAGER.split(/ +/);
|
|
344
|
-
pager = pager_split.shift();
|
|
345
|
-
md_path = pager_split.concat(md_path);
|
|
346
|
-
}
|
|
347
256
|
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
})
|
|
257
|
+
let md_path;
|
|
258
|
+
const md_paths = [
|
|
259
|
+
path.join(base, 'docs', `${parsed.help}.md`),
|
|
260
|
+
path.join(base, 'docs', 'plugins', `${parsed.help}.md`),
|
|
261
|
+
path.join(base, 'docs', 'deprecated', `${parsed.help}.md`),
|
|
262
|
+
path.join(base, 'node_modules', `haraka-plugin-${parsed.help}`, 'README.md'),
|
|
263
|
+
];
|
|
264
|
+
if (parsed.configs) {
|
|
265
|
+
md_paths.unshift(path.join(parsed.configs, 'docs', 'plugins', `${parsed.help}.md`));
|
|
266
|
+
md_paths.unshift(path.join(parsed.configs, 'docs', `${parsed.help}.md`));
|
|
267
|
+
}
|
|
268
|
+
for (let i=0, j=md_paths.length; i<j; i++) {
|
|
269
|
+
const _md_path = md_paths[i];
|
|
270
|
+
if (fs.existsSync(_md_path)) {
|
|
271
|
+
md_path = [_md_path];
|
|
272
|
+
break;
|
|
273
|
+
}
|
|
352
274
|
}
|
|
275
|
+
if (!md_path) {
|
|
276
|
+
warning(`No documentation found for: ${parsed.help}`);
|
|
277
|
+
process.exit();
|
|
278
|
+
}
|
|
279
|
+
let pager = 'less';
|
|
280
|
+
if (process.env.PAGER) {
|
|
281
|
+
const pager_split = process.env.PAGER.split(/ +/);
|
|
282
|
+
pager = pager_split.shift();
|
|
283
|
+
md_path = pager_split.concat(md_path);
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
const less = child.spawn( pager, md_path, { stdio: 'inherit' } );
|
|
287
|
+
less.on('exit', function () {
|
|
288
|
+
process.exit(0);
|
|
289
|
+
});
|
|
353
290
|
}
|
|
354
291
|
else if (parsed.configs && parsed.plugin) {
|
|
355
292
|
const js_path = path.join(parsed.configs, 'plugins', `${parsed.plugin}.js`);
|
|
356
|
-
createFile(js_path,
|
|
357
|
-
plugin_src, { plugin: parsed.plugin, config: parsed.configs });
|
|
293
|
+
utils.createFile(js_path, plugin_src, { plugin: parsed.plugin, config: parsed.configs}, parsed.force);
|
|
358
294
|
|
|
359
295
|
const doc_path = path.join(parsed.configs, 'docs', 'plugins', `${parsed.plugin}.md`);
|
|
360
|
-
createFile(doc_path,
|
|
361
|
-
plugin_doc, { plugin: parsed.plugin, config: parsed.configs });
|
|
296
|
+
utils.createFile(doc_path, plugin_doc, { plugin: parsed.plugin, config: parsed.configs}, parsed.force);
|
|
362
297
|
|
|
363
298
|
console.log(`Plugin ${parsed.plugin} created`);
|
|
364
299
|
console.log(`Now edit javascript in: ${js_path}`);
|
|
@@ -366,29 +301,24 @@ else if (parsed.configs && parsed.plugin) {
|
|
|
366
301
|
console.log(`And edit documentation in: ${doc_path}`);
|
|
367
302
|
}
|
|
368
303
|
else if (parsed.qlist) {
|
|
369
|
-
if (!parsed.configs)
|
|
370
|
-
fail("qlist option requires config path");
|
|
371
|
-
}
|
|
304
|
+
if (!parsed.configs) fail("qlist option requires config path");
|
|
372
305
|
process.env.HARAKA = parsed.configs;
|
|
373
|
-
logger = require(path.join(base,
|
|
374
|
-
if (!parsed.verbose)
|
|
375
|
-
|
|
376
|
-
outbound = require(path.join(base, "outbound"));
|
|
306
|
+
logger = require(path.join(base, 'logger'));
|
|
307
|
+
if (!parsed.verbose) logger.log = noop // disable logging
|
|
308
|
+
outbound = require(path.join(base, 'outbound'));
|
|
377
309
|
outbound.list_queue(function (err, qlist) {
|
|
378
|
-
|
|
310
|
+
for (const todo of qlist) {
|
|
379
311
|
console.log(sprintf("Q: %s rcpt:%d from:%s domain:%s", todo.file, todo.rcpt_to.length, todo.mail_from.toString(), todo.domain));
|
|
380
|
-
}
|
|
312
|
+
}
|
|
381
313
|
process.exit();
|
|
382
|
-
})
|
|
314
|
+
})
|
|
383
315
|
}
|
|
384
316
|
else if (parsed.qstat) {
|
|
385
|
-
if (!parsed.configs)
|
|
386
|
-
|
|
387
|
-
}
|
|
317
|
+
if (!parsed.configs) fail("qstat option requires config path");
|
|
318
|
+
|
|
388
319
|
process.env.HARAKA = parsed.configs;
|
|
389
320
|
logger = require(path.join(base, "logger"));
|
|
390
|
-
if (!parsed.verbose)
|
|
391
|
-
logger.log = function () {} // disable logging for this
|
|
321
|
+
if (!parsed.verbose) logger.log = noop // disable logging
|
|
392
322
|
outbound = require(path.join(base, "outbound"));
|
|
393
323
|
outbound.stat_queue(function (err, stats) {
|
|
394
324
|
console.log(stats);
|
|
@@ -396,17 +326,12 @@ else if (parsed.qstat) {
|
|
|
396
326
|
});
|
|
397
327
|
}
|
|
398
328
|
else if (parsed.qunstick) {
|
|
399
|
-
if (!parsed.configs)
|
|
400
|
-
fail("qunstick option requires config path");
|
|
401
|
-
}
|
|
329
|
+
if (!parsed.configs) fail('qunstick option requires config path');
|
|
402
330
|
const domain = parsed.qunstick.toLowerCase();
|
|
403
331
|
process.env.HARAKA = parsed.configs;
|
|
404
|
-
logger = require(path.join(base,
|
|
405
|
-
if (!parsed.verbose)
|
|
406
|
-
|
|
407
|
-
const cb = function () {
|
|
408
|
-
process.exit();
|
|
409
|
-
};
|
|
332
|
+
logger = require(path.join(base, 'logger'));
|
|
333
|
+
if (!parsed.verbose) logger.log = noop // disable logging
|
|
334
|
+
const cb = function () { process.exit(); }
|
|
410
335
|
if (domain == 'true') {
|
|
411
336
|
send_internal_command('flushQueue', cb);
|
|
412
337
|
}
|
|
@@ -415,54 +340,36 @@ else if (parsed.qunstick) {
|
|
|
415
340
|
}
|
|
416
341
|
}
|
|
417
342
|
else if (parsed.graceful) {
|
|
418
|
-
if (!parsed.configs)
|
|
419
|
-
|
|
420
|
-
}
|
|
343
|
+
if (!parsed.configs) fail("graceful option requires config path");
|
|
344
|
+
|
|
421
345
|
process.env.HARAKA = parsed.configs;
|
|
422
|
-
logger = require(path.join(base,
|
|
423
|
-
if (!parsed.verbose)
|
|
424
|
-
logger.log = function () {} // disable logging for this
|
|
346
|
+
logger = require(path.join(base, 'logger'));
|
|
347
|
+
if (!parsed.verbose) logger.log = noop // disable logging
|
|
425
348
|
config = require('haraka-config');
|
|
426
349
|
if (!config.get("smtp.ini").main.nodes) {
|
|
427
350
|
console.log("Graceful restart not possible without `nodes` value in smtp.ini");
|
|
428
351
|
process.exit();
|
|
429
352
|
}
|
|
430
353
|
else {
|
|
431
|
-
send_internal_command('gracefulRestart',
|
|
354
|
+
send_internal_command('gracefulRestart', () => {
|
|
432
355
|
process.exit();
|
|
433
356
|
});
|
|
434
357
|
}
|
|
435
358
|
}
|
|
436
359
|
else if (parsed.qempty) {
|
|
437
|
-
if (!parsed.configs)
|
|
438
|
-
|
|
439
|
-
}
|
|
440
|
-
fail("qempty is unimplemented");
|
|
360
|
+
if (!parsed.configs) fail('qempty option requires config path');
|
|
361
|
+
fail('qempty is unimplemented');
|
|
441
362
|
}
|
|
442
363
|
else if (parsed.order) {
|
|
443
|
-
if (!parsed.configs)
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
require.paths.push(path.join(process.env.HARAKA, 'node_modules'));
|
|
449
|
-
}
|
|
450
|
-
catch (e) {
|
|
451
|
-
process.env.NODE_PATH = process.env.NODE_PATH ?
|
|
452
|
-
(`${process.env.NODE_PATH}:${path.join(process.env.HARAKA, 'node_modules')}`)
|
|
453
|
-
:
|
|
454
|
-
(path.join(process.env.HARAKA, 'node_modules'));
|
|
455
|
-
require('module')._initPaths(); // Horrible hack
|
|
456
|
-
}
|
|
457
|
-
logger = require(path.join(base, "logger"));
|
|
458
|
-
if (!parsed.verbose)
|
|
459
|
-
logger.log = function () {} // disable logging for this
|
|
460
|
-
plugins = require(path.join(base, "plugins"));
|
|
364
|
+
if (!parsed.configs) fail('order option requires config path');
|
|
365
|
+
setupRequire();
|
|
366
|
+
logger = require(path.join(base, 'logger'));
|
|
367
|
+
if (!parsed.verbose) logger.log = noop // disable logging
|
|
368
|
+
plugins = require(path.join(base, 'plugins'));
|
|
461
369
|
plugins.load_plugins();
|
|
462
370
|
console.log('');
|
|
463
|
-
const
|
|
464
|
-
|
|
465
|
-
const hook = hooks[h];
|
|
371
|
+
for (const hook of getHooks()) {
|
|
372
|
+
if (!plugins.registered_hooks[hook]) continue;
|
|
466
373
|
console.log(sprintf('%\'--80s', `Hook: ${hook} `));
|
|
467
374
|
console.log(sprintf('%-35s %-35s %-4s %-3s', 'Plugin', 'Method', 'Prio', 'T/O'));
|
|
468
375
|
console.log(sprintf("%'-80s",''));
|
|
@@ -475,21 +382,11 @@ else if (parsed.order) {
|
|
|
475
382
|
process.exit();
|
|
476
383
|
}
|
|
477
384
|
else if (parsed.test) {
|
|
478
|
-
if (!parsed.configs)
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
require.paths.push(path.join(process.env.HARAKA, 'node_modules'));
|
|
484
|
-
}
|
|
485
|
-
catch (e) {
|
|
486
|
-
process.env.NODE_PATH = process.env.NODE_PATH ?
|
|
487
|
-
(`${process.env.NODE_PATH}:${path.join(process.env.HARAKA, 'node_modules')}`)
|
|
488
|
-
:
|
|
489
|
-
(path.join(process.env.HARAKA, 'node_modules'));
|
|
490
|
-
require('module')._initPaths(); // Horrible hack
|
|
491
|
-
}
|
|
492
|
-
logger = require(path.join(base, "logger"));
|
|
385
|
+
if (!parsed.configs) fail("test option requires config path");
|
|
386
|
+
|
|
387
|
+
setupRequire();
|
|
388
|
+
|
|
389
|
+
logger = require(path.join(base, 'logger'));
|
|
493
390
|
logger.loglevel = logger.levels.PROTOCOL;
|
|
494
391
|
|
|
495
392
|
// Attempt to load message early
|
|
@@ -499,7 +396,7 @@ else if (parsed.test) {
|
|
|
499
396
|
msg = fs.readFileSync(parsed.message);
|
|
500
397
|
}
|
|
501
398
|
catch (e) {
|
|
502
|
-
logger.
|
|
399
|
+
logger.crit(e.message);
|
|
503
400
|
logger.dump_logs(1);
|
|
504
401
|
}
|
|
505
402
|
}
|
|
@@ -513,10 +410,12 @@ else if (parsed.test) {
|
|
|
513
410
|
const Notes = require('haraka-notes');
|
|
514
411
|
const constants = require('haraka-constants');
|
|
515
412
|
const client = {
|
|
516
|
-
|
|
517
|
-
|
|
413
|
+
remote: {
|
|
414
|
+
address: ((parsed.ip) ? parsed.ip : '1.2.3.4'),
|
|
415
|
+
port: 1234,
|
|
416
|
+
},
|
|
518
417
|
destroy () {},
|
|
519
|
-
on (event
|
|
418
|
+
on (event) {},
|
|
520
419
|
end () {
|
|
521
420
|
process.exit();
|
|
522
421
|
},
|
|
@@ -651,14 +550,14 @@ else if (parsed.configs) {
|
|
|
651
550
|
}
|
|
652
551
|
else if (parsed.install) {
|
|
653
552
|
const pa = parsed.install;
|
|
654
|
-
mkDir(parsed.install);
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
createFile(path.join(pa, 'README'), readme);
|
|
659
|
-
createFile(path.join(pa, 'package.json'), packageJson);
|
|
553
|
+
utils.mkDir(parsed.install);
|
|
554
|
+
for (const d of ['plugins', 'docs', 'config']) {
|
|
555
|
+
utils.mkDir(path.join(pa, d));
|
|
556
|
+
}
|
|
557
|
+
utils.createFile(path.join(pa, 'README'), readme, {}, parsed.force);
|
|
558
|
+
utils.createFile(path.join(pa, 'package.json'), packageJson, {}, parsed.force);
|
|
660
559
|
const bytes = require('crypto').randomBytes(32);
|
|
661
|
-
createFile(path.join(pa, 'config', 'internalcmd_key'), bytes.toString('hex'));
|
|
560
|
+
utils.createFile(path.join(pa, 'config', 'internalcmd_key'), bytes.toString('hex'), {}, parsed.force);
|
|
662
561
|
setupHostname(path.join(pa, 'config'));
|
|
663
562
|
setupBaseConfig(path.join(pa, 'config'));
|
|
664
563
|
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
-----BEGIN DH PARAMETERS-----
|
|
2
|
+
MIIBDAKCAQEApFk8xNOjLnepwoVTwGBOtmR25KqRjdF3A/DPb+enmE6Kmwtr5KCP
|
|
3
|
+
EwdaSyjLVFMqE9DQzMdfl5mpU+1HghTBRmiUIWnpUWhkXJsGVYvMN/ny6aVO8zuO
|
|
4
|
+
K+7RtqqPo0Cop6ayMmMYg+cFKTEdP6B3LDZgrTRUy1jLVq2RsZajOn+pQMQjCgjK
|
|
5
|
+
bF44ctsUgc3RRL5bO/bsyh+N+KC0LpwcsnvNxX8lwVry9+4uPwH1j/PORAt1AxvT
|
|
6
|
+
AEW4PET1C44IoocclLKXA4jaGxLW8Bhhf875KnH8ACzi24Wn0doIbPzm5KY2nSEw
|
|
7
|
+
e5tD4DLWs6jk66lRKJ/WtEKMwxgum8SFDwIBAgICAOE=
|
|
8
|
+
-----END DH PARAMETERS-----
|