haraka 0.0.32 → 3.3.0
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/.claude/settings.local.json +28 -0
- package/.githooks/pre-commit +41 -0
- package/.prettierignore +6 -0
- package/.qlty/.gitignore +7 -0
- package/.qlty/configs/.shellcheckrc +1 -0
- package/.qlty/qlty.toml +15 -0
- package/CHANGELOG.md +1872 -62
- package/CLAUDE.md +40 -0
- package/CONTRIBUTORS.md +34 -0
- package/Dockerfile +50 -0
- package/GEMINI.md +38 -0
- package/LICENSE +2 -1
- package/Plugins.md +227 -0
- package/README.md +100 -115
- package/SECURITY.md +178 -0
- package/TODO +22 -0
- package/address.js +53 -0
- package/bin/haraka +593 -0
- package/bin/haraka_grep +32 -0
- package/config/aliases +2 -0
- package/config/auth_flat_file.ini +7 -0
- package/config/auth_vpopmaild.ini +9 -0
- package/config/connection.ini +79 -0
- package/config/delay_deny.ini +7 -0
- package/config/dhparams.pem +8 -0
- package/config/host_list +3 -0
- package/config/host_list_regex +6 -0
- package/config/http.ini +11 -0
- package/config/lmtp.ini +7 -0
- package/config/log.ini +11 -0
- package/config/me +1 -0
- package/config/outbound.bounce_message +18 -0
- package/config/outbound.bounce_message_html +36 -0
- package/config/outbound.bounce_message_image +106 -0
- package/config/outbound.ini +24 -0
- package/config/plugins +67 -0
- package/config/smtp.ini +37 -0
- package/config/smtp_bridge.ini +4 -0
- package/config/smtp_forward.ini +31 -0
- package/config/smtp_proxy.ini +27 -0
- package/config/tarpit.timeout +1 -0
- package/config/tls.ini +83 -0
- package/config/tls_cert.pem +23 -0
- package/config/tls_key.pem +28 -0
- package/config/watch.ini +12 -0
- package/config/xclient.hosts +2 -0
- package/connection.js +1863 -0
- package/contrib/Haraka.cf +6 -0
- package/contrib/Haraka.pm +35 -0
- package/contrib/bad_smtp_server.pl +25 -0
- package/contrib/bsd-rc.d/haraka +61 -0
- package/contrib/debian-init.d/haraka +87 -0
- package/contrib/haraka.init +96 -0
- package/contrib/haraka.service +23 -0
- package/contrib/plugin2npm.sh +81 -0
- package/contrib/ubuntu-upstart/haraka.conf +27 -0
- package/coverage/coverage-final.json +2 -0
- package/coverage/coverage-summary.json +33 -0
- package/coverage/tmp/coverage-79131-1779241025146-0.json +1 -0
- package/coverage/tmp/coverage-79132-1779240999690-0.json +1 -0
- package/coverage/tmp/coverage-79172-1779241000095-0.json +1 -0
- package/coverage/tmp/coverage-79210-1779241000156-0.json +1 -0
- package/coverage/tmp/coverage-79211-1779241000209-0.json +1 -0
- package/coverage/tmp/coverage-79212-1779241000266-0.json +1 -0
- package/coverage/tmp/coverage-79213-1779241000441-0.json +1 -0
- package/coverage/tmp/coverage-79214-1779241000626-0.json +1 -0
- package/coverage/tmp/coverage-79215-1779241000795-0.json +1 -0
- package/coverage/tmp/coverage-79216-1779241000965-0.json +1 -0
- package/coverage/tmp/coverage-79218-1779241001013-0.json +1 -0
- package/coverage/tmp/coverage-79219-1779241001179-0.json +1 -0
- package/coverage/tmp/coverage-79220-1779241006249-0.json +1 -0
- package/coverage/tmp/coverage-79227-1779241011453-0.json +1 -0
- package/coverage/tmp/coverage-79229-1779241011537-0.json +1 -0
- package/coverage/tmp/coverage-79230-1779241011647-0.json +1 -0
- package/coverage/tmp/coverage-79231-1779241011765-0.json +1 -0
- package/coverage/tmp/coverage-79232-1779241011841-0.json +1 -0
- package/coverage/tmp/coverage-79233-1779241011909-0.json +1 -0
- package/coverage/tmp/coverage-79234-1779241011984-0.json +1 -0
- package/coverage/tmp/coverage-79235-1779241012055-0.json +1 -0
- package/coverage/tmp/coverage-79236-1779241012230-0.json +1 -0
- package/coverage/tmp/coverage-79237-1779241012300-0.json +1 -0
- package/coverage/tmp/coverage-79238-1779241012368-0.json +1 -0
- package/coverage/tmp/coverage-79239-1779241012438-0.json +1 -0
- package/coverage/tmp/coverage-79240-1779241012511-0.json +1 -0
- package/coverage/tmp/coverage-79241-1779241012582-0.json +1 -0
- package/coverage/tmp/coverage-79242-1779241012652-0.json +1 -0
- package/coverage/tmp/coverage-79243-1779241012814-0.json +1 -0
- package/coverage/tmp/coverage-79244-1779241012931-0.json +1 -0
- package/coverage/tmp/coverage-79245-1779241013007-0.json +1 -0
- package/coverage/tmp/coverage-79246-1779241013106-0.json +1 -0
- package/coverage/tmp/coverage-79247-1779241013178-0.json +1 -0
- package/coverage/tmp/coverage-79248-1779241013244-0.json +1 -0
- package/coverage/tmp/coverage-79249-1779241013409-0.json +1 -0
- package/coverage/tmp/coverage-79250-1779241013697-0.json +1 -0
- package/coverage/tmp/coverage-79251-1779241013847-0.json +1 -0
- package/coverage/tmp/coverage-79252-1779241014288-0.json +1 -0
- package/coverage/tmp/coverage-79253-1779241014378-0.json +1 -0
- package/coverage/tmp/coverage-79254-1779241014428-0.json +1 -0
- package/coverage/tmp/coverage-79255-1779241021774-0.json +1 -0
- package/coverage/tmp/coverage-80382-1779241021949-0.json +1 -0
- package/coverage/tmp/coverage-80383-1779241025019-0.json +1 -0
- package/coverage/tmp/coverage-80384-1779241025133-0.json +1 -0
- package/docs/Body.md +1 -0
- package/docs/Config.md +1 -0
- package/docs/Connection.md +153 -0
- package/docs/CoreConfig.md +96 -0
- package/docs/CustomReturnCodes.md +3 -0
- package/docs/HAProxy.md +62 -0
- package/docs/Header.md +1 -0
- package/docs/Logging.md +129 -0
- package/docs/Outbound.md +210 -0
- package/docs/Plugins.md +372 -0
- package/docs/Results.md +7 -0
- package/docs/Transaction.md +135 -0
- package/docs/Tutorial.md +183 -0
- package/docs/deprecated/access.md +3 -0
- package/docs/deprecated/backscatterer.md +9 -0
- package/docs/deprecated/connect.rdns_access.md +53 -0
- package/docs/deprecated/data.headers.md +3 -0
- package/docs/deprecated/data.nomsgid.md +7 -0
- package/docs/deprecated/data.noreceived.md +11 -0
- package/docs/deprecated/data.rfc5322_header_checks.md +11 -0
- package/docs/deprecated/dkim_sign.md +97 -0
- package/docs/deprecated/dkim_verify.md +28 -0
- package/docs/deprecated/dnsbl.md +80 -0
- package/docs/deprecated/dnswl.md +73 -0
- package/docs/deprecated/lookup_rdns.strict.md +67 -0
- package/docs/deprecated/mail_from.access.md +52 -0
- package/docs/deprecated/mail_from.blocklist.md +18 -0
- package/docs/deprecated/mail_from.nobounces.md +8 -0
- package/docs/deprecated/rcpt_to.access.md +53 -0
- package/docs/deprecated/rcpt_to.blocklist.md +18 -0
- package/docs/deprecated/rcpt_to.routes.md +3 -0
- package/docs/deprecated/rdns.regexp.md +30 -0
- package/docs/plugins/aliases.md +3 -0
- package/docs/plugins/auth/auth_bridge.md +34 -0
- package/docs/plugins/auth/auth_ldap.md +4 -0
- package/docs/plugins/auth/auth_proxy.md +36 -0
- package/docs/plugins/auth/auth_vpopmaild.md +33 -0
- package/docs/plugins/auth/flat_file.md +40 -0
- package/docs/plugins/block_me.md +18 -0
- package/docs/plugins/data.signatures.md +11 -0
- package/docs/plugins/delay_deny.md +23 -0
- package/docs/plugins/max_unrecognized_commands.md +6 -0
- package/docs/plugins/prevent_credential_leaks.md +22 -0
- package/docs/plugins/process_title.md +42 -0
- package/docs/plugins/queue/deliver.md +3 -0
- package/docs/plugins/queue/discard.md +32 -0
- package/docs/plugins/queue/lmtp.md +24 -0
- package/docs/plugins/queue/qmail-queue.md +16 -0
- package/docs/plugins/queue/quarantine.md +87 -0
- package/docs/plugins/queue/smtp_bridge.md +32 -0
- package/docs/plugins/queue/smtp_forward.md +127 -0
- package/docs/plugins/queue/smtp_proxy.md +68 -0
- package/docs/plugins/queue/test.md +7 -0
- package/docs/plugins/rcpt_to.in_host_list.md +34 -0
- package/docs/plugins/rcpt_to.max_count.md +3 -0
- package/docs/plugins/record_envelope_addresses.md +20 -0
- package/docs/plugins/relay.md +3 -0
- package/docs/plugins/reseed_rng.md +16 -0
- package/docs/plugins/status.md +41 -0
- package/docs/plugins/tarpit.md +50 -0
- package/docs/plugins/tls.md +235 -0
- package/docs/plugins/toobusy.md +27 -0
- package/docs/plugins/xclient.md +10 -0
- package/docs/tutorials/Migrating_from_v1_to_v2.md +96 -0
- package/docs/tutorials/SettingUpOutbound.md +62 -0
- package/eslint.config.mjs +2 -0
- package/haraka.js +74 -0
- package/haraka.sh +2 -0
- package/http/html/404.html +58 -0
- package/http/html/index.html +47 -0
- package/http/package.json +21 -0
- package/line_socket.js +24 -0
- package/logger.js +322 -0
- package/outbound/client_pool.js +59 -0
- package/outbound/config.js +134 -0
- package/outbound/hmail.js +1504 -0
- package/outbound/index.js +349 -0
- package/outbound/qfile.js +93 -0
- package/outbound/queue.js +399 -0
- package/outbound/tls.js +85 -0
- package/outbound/todo.js +17 -0
- package/package.json +91 -29
- package/plugins/.eslintrc.yaml +3 -0
- package/plugins/auth/auth_base.js +261 -0
- package/plugins/auth/auth_bridge.js +20 -0
- package/plugins/auth/auth_proxy.js +227 -0
- package/plugins/auth/auth_vpopmaild.js +162 -0
- package/plugins/auth/flat_file.js +44 -0
- package/plugins/block_me.js +88 -0
- package/plugins/data.signatures.js +30 -0
- package/plugins/delay_deny.js +153 -0
- package/plugins/prevent_credential_leaks.js +61 -0
- package/plugins/process_title.js +197 -0
- package/plugins/profile.js +11 -0
- package/plugins/queue/deliver.js +12 -0
- package/plugins/queue/discard.js +27 -0
- package/plugins/queue/lmtp.js +45 -0
- package/plugins/queue/qmail-queue.js +93 -0
- package/plugins/queue/quarantine.js +133 -0
- package/plugins/queue/smtp_bridge.js +45 -0
- package/plugins/queue/smtp_forward.js +371 -0
- package/plugins/queue/smtp_proxy.js +142 -0
- package/plugins/queue/test.js +15 -0
- package/plugins/rcpt_to.host_list_base.js +65 -0
- package/plugins/rcpt_to.in_host_list.js +56 -0
- package/plugins/record_envelope_addresses.js +17 -0
- package/plugins/reseed_rng.js +7 -0
- package/plugins/status.js +274 -0
- package/plugins/tarpit.js +45 -0
- package/plugins/tls.js +164 -0
- package/plugins/toobusy.js +47 -0
- package/plugins/xclient.js +124 -0
- package/plugins.js +604 -0
- package/queue/1772642154987_1775581346001_4_82235_TGwgfd_2_mattbook-m3.home.simerson.net +0 -0
- package/run_tests +11 -0
- package/server.js +827 -0
- package/smtp_client.js +504 -0
- package/test/.eslintrc.yaml +11 -0
- package/test/config/auth_flat_file.ini +5 -0
- package/test/config/block_me.recipient +1 -0
- package/test/config/block_me.senders +1 -0
- package/test/config/dhparams.pem +8 -0
- package/test/config/host_list +2 -0
- package/test/config/outbound_tls_cert.pem +1 -0
- package/test/config/outbound_tls_key.pem +1 -0
- package/test/config/plugins +7 -0
- package/test/config/smtp.ini +11 -0
- package/test/config/smtp_forward.ini +30 -0
- package/test/config/tls/example.com/_.example.com.key +28 -0
- package/test/config/tls/example.com/example.com.crt +25 -0
- package/test/config/tls/haraka.local.pem +51 -0
- package/test/config/tls.ini +45 -0
- package/test/config/tls_cert.pem +21 -0
- package/test/config/tls_key.pem +28 -0
- package/test/connection.js +817 -0
- package/test/fixtures/haproxy_allowed/config/connection.ini +3 -0
- package/test/fixtures/haproxy_disabled/config/connection.ini +3 -0
- package/test/fixtures/haproxy_untrusted/config/connection.ini +3 -0
- package/test/fixtures/line_socket.js +21 -0
- package/test/fixtures/todo_qfile.txt +0 -0
- package/test/fixtures/util_hmailitem.js +156 -0
- package/test/installation/config/test-plugin-flat +1 -0
- package/test/installation/config/test-plugin.ini +10 -0
- package/test/installation/config/tls.ini +1 -0
- package/test/installation/node_modules/load_first/index.js +5 -0
- package/test/installation/node_modules/load_first/package.json +11 -0
- package/test/installation/node_modules/test-plugin/config/test-plugin-flat +1 -0
- package/test/installation/node_modules/test-plugin/config/test-plugin.ini +9 -0
- package/test/installation/node_modules/test-plugin/package.json +5 -0
- package/test/installation/node_modules/test-plugin/test-plugin.js +5 -0
- package/test/installation/plugins/base_plugin.js +3 -0
- package/test/installation/plugins/folder_plugin/index.js +3 -0
- package/test/installation/plugins/folder_plugin/package.json +11 -0
- package/test/installation/plugins/inherits.js +7 -0
- package/test/installation/plugins/load_first.js +3 -0
- package/test/installation/plugins/plugin.js +1 -0
- package/test/installation/plugins/tls.js +3 -0
- package/test/logger.js +217 -0
- package/test/loud/config/dhparams.pem +0 -0
- package/test/loud/config/tls/goobered.pem +45 -0
- package/test/loud/config/tls.ini +43 -0
- package/test/mail_specimen/base64-root-part.txt +23 -0
- package/test/mail_specimen/varied-fold-lengths-preserve-data.txt +283 -0
- package/test/outbound/bounce_net_errors.js +133 -0
- package/test/outbound/bounce_rfc3464.js +226 -0
- package/test/outbound/hmail.js +210 -0
- package/test/outbound/index.js +385 -0
- package/test/outbound/qfile.js +124 -0
- package/test/outbound/queue.js +325 -0
- package/test/plugins/auth/auth_base.js +620 -0
- package/test/plugins/auth/auth_bridge.js +80 -0
- package/test/plugins/auth/auth_vpopmaild.js +81 -0
- package/test/plugins/auth/flat_file.js +123 -0
- package/test/plugins/block_me.js +141 -0
- package/test/plugins/data.signatures.js +111 -0
- package/test/plugins/delay_deny.js +262 -0
- package/test/plugins/prevent_credential_leaks.js +174 -0
- package/test/plugins/process_title.js +141 -0
- package/test/plugins/queue/deliver.js +98 -0
- package/test/plugins/queue/discard.js +78 -0
- package/test/plugins/queue/lmtp.js +137 -0
- package/test/plugins/queue/qmail-queue.js +98 -0
- package/test/plugins/queue/quarantine.js +80 -0
- package/test/plugins/queue/smtp_bridge.js +152 -0
- package/test/plugins/queue/smtp_forward.js +1023 -0
- package/test/plugins/queue/smtp_proxy.js +138 -0
- package/test/plugins/rcpt_to.host_list_base.js +102 -0
- package/test/plugins/rcpt_to.in_host_list.js +186 -0
- package/test/plugins/record_envelope_addresses.js +66 -0
- package/test/plugins/reseed_rng.js +34 -0
- package/test/plugins/status.js +207 -0
- package/test/plugins/tarpit.js +90 -0
- package/test/plugins/tls.js +86 -0
- package/test/plugins/toobusy.js +21 -0
- package/test/plugins/xclient.js +119 -0
- package/test/plugins.js +230 -0
- package/test/queue/1507509981169_1507509981169_0_61403_e0Y0Ym_1_fixed +0 -0
- package/test/queue/1507509981169_1507509981169_0_61403_e0Y0Ym_1_haraka +0 -0
- package/test/queue/1508269674999_1508269674999_0_34002_socVUF_1_haraka +0 -0
- package/test/queue/1508455115683_1508455115683_0_90253_9Q4o4V_1_haraka +0 -0
- package/test/queue/zero-length +0 -0
- package/test/server.js +1012 -0
- package/test/smtp_client.js +1303 -0
- package/test/tls_socket.js +321 -0
- package/test/transaction.js +554 -0
- package/tls_socket.js +771 -0
- package/transaction.js +267 -0
- package/lib/index.js +0 -371
package/bin/haraka
ADDED
|
@@ -0,0 +1,593 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// this script takes inspiration from:
|
|
4
|
+
// https://github.com/tnantoka/LooseLeaf/blob/master/bin/looseleaf
|
|
5
|
+
|
|
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')
|
|
11
|
+
|
|
12
|
+
const nopt = require('nopt')
|
|
13
|
+
const utils = require('haraka-utils')
|
|
14
|
+
const base = path.join(__dirname, '..')
|
|
15
|
+
const ver = utils.getVersion(base)
|
|
16
|
+
const knownOpts = {
|
|
17
|
+
version: Boolean,
|
|
18
|
+
verbose: Boolean,
|
|
19
|
+
help: [String, null],
|
|
20
|
+
configs: path,
|
|
21
|
+
install: path,
|
|
22
|
+
list: Boolean,
|
|
23
|
+
plugin: Array,
|
|
24
|
+
force: Boolean,
|
|
25
|
+
qlist: Boolean,
|
|
26
|
+
qstat: Boolean,
|
|
27
|
+
qempty: Boolean,
|
|
28
|
+
qunstick: [String, null],
|
|
29
|
+
graceful: Boolean,
|
|
30
|
+
order: Boolean,
|
|
31
|
+
test: [String, Array],
|
|
32
|
+
ip: String,
|
|
33
|
+
helo: String,
|
|
34
|
+
ehlo: String,
|
|
35
|
+
envfrom: String,
|
|
36
|
+
envrcpt: [String, Array],
|
|
37
|
+
message: path,
|
|
38
|
+
'dump-mime': Boolean,
|
|
39
|
+
'dump-stream': Boolean,
|
|
40
|
+
'skip-deny': Boolean,
|
|
41
|
+
'set-relay': Boolean,
|
|
42
|
+
}
|
|
43
|
+
const shortHands = {
|
|
44
|
+
v: ['--version'],
|
|
45
|
+
h: ['--help'],
|
|
46
|
+
c: ['--configs'],
|
|
47
|
+
i: ['--install'],
|
|
48
|
+
l: ['--list'],
|
|
49
|
+
p: ['--plugin'],
|
|
50
|
+
f: ['--force'],
|
|
51
|
+
o: ['--order'],
|
|
52
|
+
t: ['--test'],
|
|
53
|
+
}
|
|
54
|
+
const parsed = nopt(knownOpts, shortHands, process.argv, 2)
|
|
55
|
+
|
|
56
|
+
const usage = `\x1B[32;40mHaraka.js\x1B[0m — A Node.js Email Server project
|
|
57
|
+
Usage: haraka [options] [path]
|
|
58
|
+
Options:
|
|
59
|
+
-v, --version \t\tOutputs version number
|
|
60
|
+
-h, --help \t\tOutputs this help message
|
|
61
|
+
-h NAME \t\tShows help for NAME
|
|
62
|
+
-c, --configs \t\tPath to your config directory
|
|
63
|
+
-i, --install \t\tCopies the default configs to a specified dir
|
|
64
|
+
-l, --list \t\tList the plugins bundled with Haraka
|
|
65
|
+
-p, --plugin \t\tGenerate a new plugin with the given name
|
|
66
|
+
-f, --force \t\tForce overwriting of old files
|
|
67
|
+
--qlist \t\tList the outbound queue
|
|
68
|
+
--qstat \t\tGet statistics on the outbound queue
|
|
69
|
+
--qunstick \t\tUnstick (force delivery) for a given domain
|
|
70
|
+
-o, --order \t\tShow all registered plugins and their run order
|
|
71
|
+
-t PLUGIN \t\tPlugin test mode
|
|
72
|
+
--------------- PLUGIN TEST MODE OPTIONS (all optional) --------------
|
|
73
|
+
--ip IP \t\tIP address to use
|
|
74
|
+
--helo HELO \t\tHELO to use
|
|
75
|
+
--ehlo EHLO \t\tEHLO to use
|
|
76
|
+
--envfrom FROM\t\tMAIL FROM to use
|
|
77
|
+
--envfrom TO \t\tRCPT TO(s) to use
|
|
78
|
+
--message FILE\t\tMessage file to use
|
|
79
|
+
--dump-mime \t\tDump the MIME structure and body text
|
|
80
|
+
--dump-stream \t\tDump the MessageStream to stdout
|
|
81
|
+
--skip-deny \t\tContinue running hooks after DENY/DENYSOFT
|
|
82
|
+
--set-relay \t\tSet connection.relaying
|
|
83
|
+
`
|
|
84
|
+
|
|
85
|
+
function listPlugins(b, dir = 'plugins/') {
|
|
86
|
+
const inital_dir = path.join(b ?? base, dir)
|
|
87
|
+
const plugin_dirs = [inital_dir]
|
|
88
|
+
|
|
89
|
+
for (const d of fs.readdirSync(inital_dir)) {
|
|
90
|
+
if (fs.statSync(path.join(inital_dir, d)).isDirectory()) {
|
|
91
|
+
plugin_dirs.push(path.join(inital_dir, d))
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
let plugin_list = ``
|
|
96
|
+
for (const pd of plugin_dirs) {
|
|
97
|
+
plugin_list += `\n${pd.match(/plugins.*$/)[0]}\n`
|
|
98
|
+
|
|
99
|
+
for (const d of fs.readdirSync(pd)) {
|
|
100
|
+
if (fs.statSync(path.join(pd, d)).isFile() && ~d.search('.js')) {
|
|
101
|
+
plugin_list += `\t${d.replace('.js', '')}\n`
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
plugin_list += `\nNPM packages (${b ?? base})\n`
|
|
107
|
+
const npm_plugins = []
|
|
108
|
+
for (const entry of fs.readdirSync(path.join(b ?? base, 'node_modules'))) {
|
|
109
|
+
if (!/^haraka-plugin-/.test(entry)) continue
|
|
110
|
+
npm_plugins.push(entry.split('-').slice(2).join('-'))
|
|
111
|
+
}
|
|
112
|
+
plugin_list += `\t${npm_plugins.join('\n\t')}\n`
|
|
113
|
+
|
|
114
|
+
return plugin_list
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// Warning messsage
|
|
118
|
+
function warning(msg) {
|
|
119
|
+
console.error(`\x1b[31mwarning\x1b[0m: ${msg}`)
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
function fail(msg) {
|
|
123
|
+
console.error(`\x1b[31merror\x1b[0m: ${msg}`)
|
|
124
|
+
process.exit(-1)
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
function setupHostname(confPath) {
|
|
128
|
+
utils.mkDir(confPath)
|
|
129
|
+
|
|
130
|
+
const hostname = `${os.hostname()}${os.EOL}`
|
|
131
|
+
|
|
132
|
+
;['me', 'host_list'].forEach((f) => {
|
|
133
|
+
const cfPath = path.join(confPath, f)
|
|
134
|
+
|
|
135
|
+
try {
|
|
136
|
+
if (fs.statSync(cfPath).isFile()) return
|
|
137
|
+
} catch (ignore) {}
|
|
138
|
+
|
|
139
|
+
try {
|
|
140
|
+
fs.writeFileSync(cfPath, hostname)
|
|
141
|
+
} catch (err) {
|
|
142
|
+
warning(`Unable to write to config/${f}: ${err.message}`)
|
|
143
|
+
}
|
|
144
|
+
})
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
function setupBaseConfig(confPath) {
|
|
148
|
+
utils.copyFile(path.join(base, 'config', 'connection.ini'), path.join(confPath, 'connection.ini'))
|
|
149
|
+
utils.copyFile(path.join(base, 'config', 'smtp.ini'), path.join(confPath, 'smtp.ini'))
|
|
150
|
+
utils.copyFile(path.join(base, 'config', 'log.ini'), path.join(confPath, 'log.ini'))
|
|
151
|
+
utils.copyFile(path.join(base, 'config', 'plugins'), path.join(confPath, 'plugins'))
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
function setupRequire() {
|
|
155
|
+
process.env.HARAKA = parsed.configs
|
|
156
|
+
try {
|
|
157
|
+
require.paths.push(path.join(process.env.HARAKA, 'node_modules'))
|
|
158
|
+
} catch (e) {
|
|
159
|
+
process.env.NODE_PATH = process.env.NODE_PATH
|
|
160
|
+
? `${process.env.NODE_PATH}:${path.join(process.env.HARAKA, 'node_modules')}`
|
|
161
|
+
: path.join(process.env.HARAKA, 'node_modules')
|
|
162
|
+
require('module')._initPaths() // Horrible hack
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
function noop() {}
|
|
167
|
+
|
|
168
|
+
function tryCreateFile(filePath, data, info = {}, force = false) {
|
|
169
|
+
try {
|
|
170
|
+
utils.createFile(...arguments)
|
|
171
|
+
} catch (e) {
|
|
172
|
+
warning(`EEXIST, File exists '${filePath}'`)
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
const readme = `Haraka
|
|
177
|
+
|
|
178
|
+
Congratulations on creating a new installation of Haraka.
|
|
179
|
+
|
|
180
|
+
This directory contains two key directories for how Haraka will function:
|
|
181
|
+
|
|
182
|
+
- config
|
|
183
|
+
|
|
184
|
+
This directory contains configuration files for Haraka. The
|
|
185
|
+
directory contains the default configuration. You probably want
|
|
186
|
+
to modify some files in here, particularly 'smtp.ini'.
|
|
187
|
+
|
|
188
|
+
- plugins
|
|
189
|
+
|
|
190
|
+
This directory contains custom plugins which you write to run in
|
|
191
|
+
Haraka. The plugins which ship with Haraka are still available
|
|
192
|
+
to use.
|
|
193
|
+
|
|
194
|
+
- docs/plugins
|
|
195
|
+
|
|
196
|
+
This directory contains documentation for your plugins.
|
|
197
|
+
|
|
198
|
+
Documentation for Haraka is available via 'haraka -h <name>' where the name
|
|
199
|
+
is either the name of a plugin (without the .js extension) or the name of
|
|
200
|
+
a core Haraka module, such as 'Connection' or 'Transaction'.
|
|
201
|
+
|
|
202
|
+
To get documentation on writing a plugin type 'haraka -h Plugins'.
|
|
203
|
+
`
|
|
204
|
+
|
|
205
|
+
const packageJson = JSON.stringify(
|
|
206
|
+
{
|
|
207
|
+
name: 'haraka_local',
|
|
208
|
+
description: 'An SMTP Server',
|
|
209
|
+
version: '0.0.1',
|
|
210
|
+
dependencies: {},
|
|
211
|
+
repository: '',
|
|
212
|
+
license: 'MIT',
|
|
213
|
+
},
|
|
214
|
+
null,
|
|
215
|
+
2,
|
|
216
|
+
)
|
|
217
|
+
|
|
218
|
+
const plugin_src = [
|
|
219
|
+
'// %plugin%',
|
|
220
|
+
'',
|
|
221
|
+
'// documentation via: haraka -c %config% -h plugins/%plugin%',
|
|
222
|
+
'',
|
|
223
|
+
'// Put your plugin code here',
|
|
224
|
+
'// type: `haraka -h Plugins` for documentation on how to create a plugin',
|
|
225
|
+
'',
|
|
226
|
+
].join('\n')
|
|
227
|
+
|
|
228
|
+
const plugin_doc = [
|
|
229
|
+
'%plugin%',
|
|
230
|
+
'========',
|
|
231
|
+
'',
|
|
232
|
+
'Describe what your plugin does here.',
|
|
233
|
+
'',
|
|
234
|
+
'Configuration',
|
|
235
|
+
'-------------',
|
|
236
|
+
'',
|
|
237
|
+
'* `config/some_file` - describe what effect this config file has',
|
|
238
|
+
'',
|
|
239
|
+
].join('\n')
|
|
240
|
+
|
|
241
|
+
function getHooks() {
|
|
242
|
+
// see haraka/Haraka#3306
|
|
243
|
+
const pi_path = path.resolve(parsed.configs, 'docs', 'Plugins.md')
|
|
244
|
+
return fs
|
|
245
|
+
.readFileSync(pi_path)
|
|
246
|
+
.toString()
|
|
247
|
+
.split('## Available Hooks')[1] // discard everything before this string
|
|
248
|
+
.split('### rcpt')[0] // discard everything after this string
|
|
249
|
+
.match(/^-\s+\w+/gmu) // grab hook names from lines starting with '- '
|
|
250
|
+
.map((a) => a.replace(/^-\s+/u, '')) // strip list prefix
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
let config
|
|
254
|
+
let logger
|
|
255
|
+
let outbound
|
|
256
|
+
let plugins
|
|
257
|
+
if (parsed.version) {
|
|
258
|
+
console.log(`\x1B[32;40mHaraka.js\x1B[0m — Version: ${ver}`)
|
|
259
|
+
} else if (parsed.list) {
|
|
260
|
+
console.log(`\x1B[32;40m*global\x1B[0m\n${listPlugins()}`)
|
|
261
|
+
if (parsed.configs) {
|
|
262
|
+
console.log(`\x1B[32;40m*local\x1B[0m\n${listPlugins(parsed.configs)}`)
|
|
263
|
+
}
|
|
264
|
+
} else if (parsed.help) {
|
|
265
|
+
if (parsed.help === 'true') {
|
|
266
|
+
console.log(usage)
|
|
267
|
+
return
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
let md_path
|
|
271
|
+
const md_paths = [
|
|
272
|
+
path.join(base, 'docs', `${parsed.help}.md`),
|
|
273
|
+
path.join(base, 'docs', 'plugins', `${parsed.help}.md`),
|
|
274
|
+
path.join(base, 'docs', 'deprecated', `${parsed.help}.md`),
|
|
275
|
+
path.join(base, 'node_modules', `haraka-plugin-${parsed.help}`, 'README.md'),
|
|
276
|
+
]
|
|
277
|
+
if (parsed.configs) {
|
|
278
|
+
md_paths.unshift(path.join(parsed.configs, 'docs', 'plugins', `${parsed.help}.md`))
|
|
279
|
+
md_paths.unshift(path.join(parsed.configs, 'docs', `${parsed.help}.md`))
|
|
280
|
+
}
|
|
281
|
+
for (let i = 0, j = md_paths.length; i < j; i++) {
|
|
282
|
+
const _md_path = md_paths[i]
|
|
283
|
+
if (fs.existsSync(_md_path)) {
|
|
284
|
+
md_path = [_md_path]
|
|
285
|
+
break
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
if (!md_path) {
|
|
289
|
+
warning(`No documentation found for: ${parsed.help}`)
|
|
290
|
+
process.exit()
|
|
291
|
+
}
|
|
292
|
+
let pager = 'less'
|
|
293
|
+
if (process.env.PAGER) {
|
|
294
|
+
const pager_split = process.env.PAGER.split(/ +/)
|
|
295
|
+
pager = pager_split.shift()
|
|
296
|
+
md_path = [...pager_split, ...md_path]
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
const less = child.spawn(pager, md_path, { stdio: 'inherit' })
|
|
300
|
+
less.on('exit', function () {
|
|
301
|
+
process.exit(0)
|
|
302
|
+
})
|
|
303
|
+
} else if (parsed.configs && parsed.plugin) {
|
|
304
|
+
const js_path = path.join(parsed.configs, 'plugins', `${parsed.plugin}.js`)
|
|
305
|
+
utils.createFile(js_path, plugin_src, { plugin: parsed.plugin, config: parsed.configs }, parsed.force)
|
|
306
|
+
|
|
307
|
+
const doc_path = path.join(parsed.configs, 'docs', 'plugins', `${parsed.plugin}.md`)
|
|
308
|
+
utils.createFile(doc_path, plugin_doc, { plugin: parsed.plugin, config: parsed.configs }, parsed.force)
|
|
309
|
+
|
|
310
|
+
console.log(`Plugin ${parsed.plugin} created`)
|
|
311
|
+
console.log(`Now edit javascript in: ${js_path}`)
|
|
312
|
+
console.log(`Add the plugin to config: ${path.join(parsed.configs, 'config', 'plugins')}`)
|
|
313
|
+
console.log(`And edit documentation in: ${doc_path}`)
|
|
314
|
+
} else if (parsed.qlist) {
|
|
315
|
+
if (!parsed.configs) fail('qlist option requires config path')
|
|
316
|
+
process.env.HARAKA = parsed.configs
|
|
317
|
+
logger = require(path.join(base, 'logger'))
|
|
318
|
+
if (!parsed.verbose) logger.log = noop // disable logging
|
|
319
|
+
outbound = require(path.join(base, 'outbound'))
|
|
320
|
+
;(async () => {
|
|
321
|
+
const qlist = await outbound.list_queue()
|
|
322
|
+
for (const todo of qlist) {
|
|
323
|
+
console.log(`Q: ${todo.file} rcpt:${todo.rcpt_to.length} from:${todo.mail_from} domain:${todo.domain}`)
|
|
324
|
+
}
|
|
325
|
+
process.exit()
|
|
326
|
+
})()
|
|
327
|
+
} else if (parsed.qstat) {
|
|
328
|
+
if (!parsed.configs) fail('qstat option requires config path')
|
|
329
|
+
|
|
330
|
+
process.env.HARAKA = parsed.configs
|
|
331
|
+
logger = require(path.join(base, 'logger'))
|
|
332
|
+
if (!parsed.verbose) logger.log = noop // disable logging
|
|
333
|
+
outbound = require(path.join(base, 'outbound'))
|
|
334
|
+
;(async () => {
|
|
335
|
+
const stats = await outbound.stat_queue()
|
|
336
|
+
console.log(stats)
|
|
337
|
+
process.exit()
|
|
338
|
+
})()
|
|
339
|
+
} else if (parsed.qunstick) {
|
|
340
|
+
if (!parsed.configs) fail('qunstick option requires config path')
|
|
341
|
+
const domain = parsed.qunstick.toLowerCase()
|
|
342
|
+
process.env.HARAKA = parsed.configs
|
|
343
|
+
logger = require(path.join(base, 'logger'))
|
|
344
|
+
if (!parsed.verbose) logger.log = noop // disable logging
|
|
345
|
+
const cb = function () {
|
|
346
|
+
process.exit()
|
|
347
|
+
}
|
|
348
|
+
if (domain == 'true') {
|
|
349
|
+
send_internal_command('flushQueue', cb)
|
|
350
|
+
} else {
|
|
351
|
+
send_internal_command(`flushQueue ${domain}`, cb)
|
|
352
|
+
}
|
|
353
|
+
} else if (parsed.graceful) {
|
|
354
|
+
if (!parsed.configs) fail('graceful option requires config path')
|
|
355
|
+
|
|
356
|
+
process.env.HARAKA = parsed.configs
|
|
357
|
+
logger = require(path.join(base, 'logger'))
|
|
358
|
+
if (!parsed.verbose) logger.log = noop // disable logging
|
|
359
|
+
config = require('haraka-config')
|
|
360
|
+
if (!config.get('smtp.ini').main.nodes) {
|
|
361
|
+
console.log('Graceful restart not possible without `nodes` value in smtp.ini')
|
|
362
|
+
process.exit()
|
|
363
|
+
} else {
|
|
364
|
+
send_internal_command('gracefulRestart', () => {
|
|
365
|
+
process.exit()
|
|
366
|
+
})
|
|
367
|
+
}
|
|
368
|
+
} else if (parsed.qempty) {
|
|
369
|
+
if (!parsed.configs) fail('qempty option requires config path')
|
|
370
|
+
fail('qempty is unimplemented')
|
|
371
|
+
} else if (parsed.order) {
|
|
372
|
+
if (!parsed.configs) fail('order option requires config path')
|
|
373
|
+
setupRequire()
|
|
374
|
+
logger = require(path.join(base, 'logger'))
|
|
375
|
+
if (!parsed.verbose) logger.log = noop // disable logging
|
|
376
|
+
plugins = require(path.join(base, 'plugins'))
|
|
377
|
+
plugins.load_plugins()
|
|
378
|
+
console.log('')
|
|
379
|
+
for (const hook of getHooks()) {
|
|
380
|
+
if (!plugins.registered_hooks[hook]) continue
|
|
381
|
+
console.log(`Hook: ${hook} `.padEnd(80, '-'))
|
|
382
|
+
console.log(`${'Plugin'.padEnd(35)} ${'Method'.padEnd(35)} ${'Prio'.padEnd(4)} T/O`)
|
|
383
|
+
console.log('-'.repeat(80))
|
|
384
|
+
for (let p = 0; p < plugins.registered_hooks[hook].length; p++) {
|
|
385
|
+
const item = plugins.registered_hooks[hook][p]
|
|
386
|
+
console.log(
|
|
387
|
+
`${item.plugin.padEnd(35)} ${item.method.padEnd(35)} ${String(item.priority).padStart(4)} ${String(item.timeout).padStart(3)}`,
|
|
388
|
+
)
|
|
389
|
+
}
|
|
390
|
+
console.log('')
|
|
391
|
+
}
|
|
392
|
+
process.exit()
|
|
393
|
+
} else if (parsed.test) {
|
|
394
|
+
if (!parsed.configs) fail('test option requires config path')
|
|
395
|
+
|
|
396
|
+
setupRequire()
|
|
397
|
+
|
|
398
|
+
logger = require(path.join(base, 'logger'))
|
|
399
|
+
logger.loglevel = logger.levels.PROTOCOL
|
|
400
|
+
|
|
401
|
+
// Attempt to load message early
|
|
402
|
+
let msg
|
|
403
|
+
if (parsed.message) {
|
|
404
|
+
try {
|
|
405
|
+
msg = fs.readFileSync(parsed.message)
|
|
406
|
+
} catch (e) {
|
|
407
|
+
logger.crit(e.message)
|
|
408
|
+
logger.dump_logs(1)
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
plugins = require(path.join(base, 'plugins'))
|
|
413
|
+
plugins.server = { notes: {} }
|
|
414
|
+
plugins.load_plugins(parsed.test && parsed.test[0] !== 'all' ? parsed.test : null)
|
|
415
|
+
const Connection = require(path.join(base, 'connection'))
|
|
416
|
+
// var Transaction = require(path.join(base, "transaction"));
|
|
417
|
+
const Address = require('../address').Address
|
|
418
|
+
const Notes = require('haraka-notes')
|
|
419
|
+
const constants = require('haraka-constants')
|
|
420
|
+
const client = {
|
|
421
|
+
remote: {
|
|
422
|
+
address: parsed.ip ? parsed.ip : '1.2.3.4',
|
|
423
|
+
port: 1234,
|
|
424
|
+
},
|
|
425
|
+
destroy() {},
|
|
426
|
+
on(event) {},
|
|
427
|
+
end() {
|
|
428
|
+
process.exit()
|
|
429
|
+
},
|
|
430
|
+
write(buf) {},
|
|
431
|
+
resume() {},
|
|
432
|
+
pause() {},
|
|
433
|
+
}
|
|
434
|
+
const server = {
|
|
435
|
+
address() {
|
|
436
|
+
return { port: 25, family: 'ipv4', address: '127.0.0.1' }
|
|
437
|
+
},
|
|
438
|
+
cfg: require('haraka-config').get('smtp.ini'),
|
|
439
|
+
notes: new Notes(),
|
|
440
|
+
}
|
|
441
|
+
const connection = Connection.createConnection(client, server, server.cfg)
|
|
442
|
+
if (parsed['set-relay']) connection.relaying = true
|
|
443
|
+
|
|
444
|
+
const run_next_hook = function () {
|
|
445
|
+
const args = Array.prototype.slice.call(arguments)
|
|
446
|
+
const code = args.shift()
|
|
447
|
+
if (!parsed['skip-deny'] && code !== constants.ok && code !== constants.cont) {
|
|
448
|
+
plugins.run_hooks('quit', connection)
|
|
449
|
+
} else {
|
|
450
|
+
plugins.run_hooks.apply(this, args)
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
connection.connect_respond = function () {
|
|
455
|
+
let helo = 'test.example.com'
|
|
456
|
+
let mode = 'ehlo'
|
|
457
|
+
if (parsed.ehlo) {
|
|
458
|
+
helo = parsed.ehlo
|
|
459
|
+
} else if (parsed.helo) {
|
|
460
|
+
helo = parsed.helo
|
|
461
|
+
mode = 'helo'
|
|
462
|
+
}
|
|
463
|
+
connection.hello.host = helo
|
|
464
|
+
run_next_hook(arguments[0], mode, connection, helo)
|
|
465
|
+
}
|
|
466
|
+
connection.helo_respond = connection.ehlo_respond = function () {
|
|
467
|
+
const args = arguments
|
|
468
|
+
const mail = new Address(parsed.envfrom ? parsed.envfrom : 'test@example.com')
|
|
469
|
+
connection.init_transaction(function () {
|
|
470
|
+
connection.transaction.mail_from = mail
|
|
471
|
+
run_next_hook(args[0], 'mail', connection, [mail, null])
|
|
472
|
+
})
|
|
473
|
+
}
|
|
474
|
+
connection.mail_respond = function () {
|
|
475
|
+
const rcpt = new Address(parsed.envrcpt ? parsed.envrcpt : 'test@example.com')
|
|
476
|
+
this.transaction.rcpt_to.push(rcpt)
|
|
477
|
+
run_next_hook(arguments[0], 'rcpt', connection, [rcpt, null])
|
|
478
|
+
}
|
|
479
|
+
connection.rcpt_respond = function () {
|
|
480
|
+
connection.transaction.parse_body = true
|
|
481
|
+
run_next_hook(arguments[0], 'data', connection)
|
|
482
|
+
}
|
|
483
|
+
connection.data_respond = function () {
|
|
484
|
+
const args = arguments
|
|
485
|
+
// Add data to stream
|
|
486
|
+
if (msg) {
|
|
487
|
+
let buf = msg
|
|
488
|
+
let offset
|
|
489
|
+
while ((offset = utils.indexOfLF(buf)) !== -1) {
|
|
490
|
+
const line = buf.slice(0, offset + 1)
|
|
491
|
+
if (buf.length > offset) {
|
|
492
|
+
buf = buf.slice(offset + 1)
|
|
493
|
+
}
|
|
494
|
+
connection.transaction.add_data(line)
|
|
495
|
+
connection.transaction.data_bytes += line.length
|
|
496
|
+
}
|
|
497
|
+
} else {
|
|
498
|
+
// Add empty data to initialize message_stream
|
|
499
|
+
connection.transaction.add_data('')
|
|
500
|
+
}
|
|
501
|
+
connection.data_done(function () {
|
|
502
|
+
run_next_hook(args[0], 'data_post', connection)
|
|
503
|
+
})
|
|
504
|
+
}
|
|
505
|
+
connection.data_post_respond = function () {
|
|
506
|
+
const args = arguments
|
|
507
|
+
// Dump MIME structure and decoded body text?
|
|
508
|
+
function dump_mime_structure(body) {
|
|
509
|
+
console.log(`Found MIME part ${body.ct}`)
|
|
510
|
+
console.log(body.bodytext)
|
|
511
|
+
for (let m = 0, l = body.children.length; m < l; m++) {
|
|
512
|
+
dump_mime_structure(body.children[m])
|
|
513
|
+
}
|
|
514
|
+
}
|
|
515
|
+
if (parsed['dump-mime']) {
|
|
516
|
+
dump_mime_structure(connection.transaction.body)
|
|
517
|
+
}
|
|
518
|
+
if (parsed['dump-stream']) {
|
|
519
|
+
console.log('STREAM:')
|
|
520
|
+
connection.transaction.message_stream.on('end', function () {
|
|
521
|
+
run_next_hook(args[0], 'queue', connection)
|
|
522
|
+
})
|
|
523
|
+
connection.transaction.message_stream.pipe(process.stdout)
|
|
524
|
+
} else {
|
|
525
|
+
run_next_hook(args[0], 'queue', connection)
|
|
526
|
+
}
|
|
527
|
+
}
|
|
528
|
+
connection.queue_respond = function () {
|
|
529
|
+
run_next_hook(arguments[0], 'queue_ok', connection)
|
|
530
|
+
}
|
|
531
|
+
connection.queue_ok_respond = function () {
|
|
532
|
+
run_next_hook(arguments[0], 'quit', connection)
|
|
533
|
+
}
|
|
534
|
+
} else if (parsed.configs) {
|
|
535
|
+
const haraka_path = path.join(base, 'haraka.js')
|
|
536
|
+
|
|
537
|
+
const base_dir = process.argv[3]
|
|
538
|
+
const err_msg = `Did you install a Haraka config? (haraka -i ${base_dir})`
|
|
539
|
+
if (!fs.existsSync(base_dir)) {
|
|
540
|
+
fail(`No such directory: ${base_dir}\n${err_msg}`)
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
const smtp_ini_path = path.join(base_dir, 'config', 'smtp.ini')
|
|
544
|
+
const smtp_json = path.join(base_dir, 'config', 'smtp.json')
|
|
545
|
+
const smtp_yaml = path.join(base_dir, 'config', 'smtp.yaml')
|
|
546
|
+
if (!fs.existsSync(smtp_ini_path) && !fs.existsSync(smtp_json) && !fs.existsSync(smtp_yaml)) {
|
|
547
|
+
fail(`No smtp.ini at: ${smtp_ini_path}\n${err_msg}`)
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
process.argv[1] = haraka_path
|
|
551
|
+
process.env.HARAKA = parsed.configs
|
|
552
|
+
require(haraka_path)
|
|
553
|
+
} else if (parsed.install) {
|
|
554
|
+
const pa = parsed.install
|
|
555
|
+
utils.mkDir(parsed.install)
|
|
556
|
+
for (const d of ['plugins', 'docs', 'config']) {
|
|
557
|
+
utils.mkDir(path.join(pa, d))
|
|
558
|
+
}
|
|
559
|
+
utils.copyFile(path.join(base, 'docs', 'Plugins.md'), path.join(pa, 'docs', 'Plugins.md'))
|
|
560
|
+
tryCreateFile(path.join(pa, 'README'), readme, {}, parsed.force)
|
|
561
|
+
tryCreateFile(path.join(pa, 'package.json'), packageJson, {}, parsed.force)
|
|
562
|
+
const bytes = require('crypto').randomBytes(32)
|
|
563
|
+
tryCreateFile(path.join(pa, 'config', 'internalcmd_key'), bytes.toString('hex'), {}, parsed.force)
|
|
564
|
+
setupHostname(path.join(pa, 'config'))
|
|
565
|
+
setupBaseConfig(path.join(pa, 'config'))
|
|
566
|
+
} else {
|
|
567
|
+
console.log('\033[31;40mError\033[0m: Undefined or erroneous arguments\n')
|
|
568
|
+
console.log(usage)
|
|
569
|
+
}
|
|
570
|
+
|
|
571
|
+
function send_internal_command(cmd, done) {
|
|
572
|
+
config = require('haraka-config')
|
|
573
|
+
const key = config.get('internalcmd_key')
|
|
574
|
+
const smtp_ini = config.get('smtp.ini')
|
|
575
|
+
const listen_addrs = require(path.join(base, 'server')).get_listen_addrs(smtp_ini.main)
|
|
576
|
+
const hp = /^\[?([^\]]+)\]?:(\d+)$/.exec(listen_addrs[0])
|
|
577
|
+
if (!hp) throw 'No listen address in smtp.ini'
|
|
578
|
+
// console.log("Connecting to " + listen_addrs[0]);
|
|
579
|
+
const sock = net.connect(hp[2], hp[1], function () {
|
|
580
|
+
sock.once('data', function (data) {
|
|
581
|
+
// this is the greeting. Ignore it...
|
|
582
|
+
sock.write(`INTERNALCMD ${key ? `key:${key} ` : ''}${cmd}\r\n`)
|
|
583
|
+
sock.once('data', function (data2) {
|
|
584
|
+
console.log(data2.toString().replace(/\r?\n$/, ''))
|
|
585
|
+
sock.write('QUIT\r\n')
|
|
586
|
+
sock.once('data', function (data3) {
|
|
587
|
+
sock.end()
|
|
588
|
+
})
|
|
589
|
+
})
|
|
590
|
+
})
|
|
591
|
+
})
|
|
592
|
+
sock.on('end', done)
|
|
593
|
+
}
|
package/bin/haraka_grep
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
#!/bin/sh
|
|
2
|
+
|
|
3
|
+
if [ -z $1 ]; then
|
|
4
|
+
echo "$0 email@example.com"
|
|
5
|
+
exit
|
|
6
|
+
fi
|
|
7
|
+
|
|
8
|
+
LOG="/var/log/maillog"
|
|
9
|
+
UUIDS=$(grep $1 $LOG | awk '{ print $7 }' | cut -d. -f1 | cut -f2 -d[ | sort -u)
|
|
10
|
+
echo $UUIDS
|
|
11
|
+
|
|
12
|
+
ARCHIVES=0
|
|
13
|
+
if [ -z $UUIDS ]; then
|
|
14
|
+
echo "no recent matches, checking archives"
|
|
15
|
+
UUIDS=$(/usr/bin/bzgrep $1 $LOG.?.bz2 | awk '{ print $7 }' | cut -d. -f1 | cut -f2 -d[ | sort -u)
|
|
16
|
+
ARCHIVES=1
|
|
17
|
+
#echo "$UUIDS"
|
|
18
|
+
fi
|
|
19
|
+
|
|
20
|
+
show_uuids()
|
|
21
|
+
{
|
|
22
|
+
for u in $UUIDS
|
|
23
|
+
do
|
|
24
|
+
echo; echo
|
|
25
|
+
echo $u
|
|
26
|
+
grep $u $LOG
|
|
27
|
+
if [ "$ARCHIVES" = "1" ]; then
|
|
28
|
+
bzgrep $u $LOG.0.bz2
|
|
29
|
+
fi
|
|
30
|
+
done
|
|
31
|
+
}
|
|
32
|
+
show_uuids
|
package/config/aliases
ADDED