Haraka 3.1.3 → 3.1.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/.prettierignore +2 -0
- package/CONTRIBUTORS.md +23 -1
- package/Changes.md +38 -0
- package/Plugins.md +81 -64
- package/README.md +1 -1
- package/bin/haraka +7 -5
- package/connection.js +15 -19
- package/docs/Plugins.md +1 -1
- package/docs/plugins/aliases.md +0 -2
- package/docs/plugins/queue/qmail-queue.md +0 -1
- package/logger.js +2 -2
- package/outbound/hmail.js +76 -83
- package/outbound/index.js +36 -34
- package/outbound/queue.js +231 -176
- package/package.json +25 -26
- package/plugins/prevent_credential_leaks.js +2 -2
- package/plugins/process_title.js +1 -1
- package/plugins/queue/smtp_forward.js +1 -1
- package/plugins/status.js +8 -5
- package/plugins/tls.js +1 -1
- package/plugins.js +19 -14
- package/rfc1869.js +10 -10
- package/run_tests +20 -2
- package/server.js +15 -10
- package/smtp_client.js +2 -9
- package/test/config/tls/haraka.local.pem +47 -47
- package/test/connection.js +286 -147
- package/test/fixtures/line_socket.js +1 -0
- package/test/fixtures/util_hmailitem.js +1 -1
- package/test/outbound/bounce_net_errors.js +176 -0
- package/test/outbound/bounce_rfc3464.js +303 -0
- package/test/outbound/hmail.js +140 -104
- package/test/outbound/index.js +61 -101
- package/test/outbound/qfile.js +25 -25
- package/test/outbound/queue.js +233 -0
- package/test/plugins/queue/smtp_forward.js +1 -1
- package/test/plugins/record_envelope_addresses.js +93 -0
- package/test/plugins/tls.js +2 -2
- package/test/plugins/xclient.js +137 -0
- package/test/rfc1869.js +43 -0
- package/test/smtp_client.js +6 -6
- package/test/transaction.js +486 -201
- package/tls_socket.js +3 -3
- package/transaction.js +33 -10
- package/config/rabbitmq.ini +0 -10
- package/config/rabbitmq_amqplib.ini +0 -19
- package/docs/plugins/queue/rabbitmq.md +0 -34
- package/docs/plugins/queue/rabbitmq_amqplib.md +0 -51
- package/plugins/queue/rabbitmq.js +0 -141
- package/plugins/queue/rabbitmq_amqplib.js +0 -96
- package/test/config/tls/ec.pem +0 -23
- package/test/config/tls/mismatched.pem +0 -49
- package/test/outbound_bounce_net_errors.js +0 -157
- package/test/outbound_bounce_rfc3464.js +0 -366
- package/test/tls_socket.js +0 -273
|
@@ -25,8 +25,8 @@ exports.hook_data_post = (next, connection) => {
|
|
|
25
25
|
if (idx) {
|
|
26
26
|
// If the username is qualified (e.g. user@domain.com)
|
|
27
27
|
// then we make the @domain.com part optional in the regexp.
|
|
28
|
-
domain = user.
|
|
29
|
-
user = user.
|
|
28
|
+
domain = user.substring(idx)
|
|
29
|
+
user = user.substring(0, idx)
|
|
30
30
|
}
|
|
31
31
|
const passwd = connection.notes.auth_passwd
|
|
32
32
|
const bound_regexp = '(?:\\b|\\B)'
|
package/plugins/process_title.js
CHANGED
package/plugins/status.js
CHANGED
|
@@ -92,8 +92,9 @@ exports.pool_list = (cb) => {
|
|
|
92
92
|
cb(null, result)
|
|
93
93
|
}
|
|
94
94
|
|
|
95
|
-
exports.queue_list = function (cb) {
|
|
96
|
-
|
|
95
|
+
exports.queue_list = async function (cb) {
|
|
96
|
+
try {
|
|
97
|
+
const qlist = await this.outbound.list_queue()
|
|
97
98
|
const result = []
|
|
98
99
|
|
|
99
100
|
for (const todo of qlist) {
|
|
@@ -107,8 +108,10 @@ exports.queue_list = function (cb) {
|
|
|
107
108
|
})
|
|
108
109
|
}
|
|
109
110
|
|
|
110
|
-
cb(
|
|
111
|
-
})
|
|
111
|
+
cb(null, result)
|
|
112
|
+
} catch (err) {
|
|
113
|
+
cb(err)
|
|
114
|
+
}
|
|
112
115
|
}
|
|
113
116
|
|
|
114
117
|
exports.queue_stats = function (cb) {
|
|
@@ -116,7 +119,7 @@ exports.queue_stats = function (cb) {
|
|
|
116
119
|
}
|
|
117
120
|
|
|
118
121
|
exports.queue_inspect = function (cb) {
|
|
119
|
-
const delivery_queue_items = this.outbound.delivery_queue.
|
|
122
|
+
const delivery_queue_items = this.outbound.delivery_queue.tasks
|
|
120
123
|
const fail_queue_items = this.outbound.temp_fail_queue.queue
|
|
121
124
|
|
|
122
125
|
cb(null, {
|
package/plugins/tls.js
CHANGED
package/plugins.js
CHANGED
|
@@ -33,10 +33,6 @@ class Plugin {
|
|
|
33
33
|
return require(`./${name}`)
|
|
34
34
|
}
|
|
35
35
|
|
|
36
|
-
core_require(name) {
|
|
37
|
-
return this.haraka_require(name)
|
|
38
|
-
}
|
|
39
|
-
|
|
40
36
|
_get_plugin_path() {
|
|
41
37
|
/* From https://github.com/haraka/Haraka/pull/1278#issuecomment-168856528
|
|
42
38
|
In Development mode, or install via a plain "git clone":
|
|
@@ -56,13 +52,13 @@ class Plugin {
|
|
|
56
52
|
*/
|
|
57
53
|
|
|
58
54
|
this.hasPackageJson = false
|
|
59
|
-
const name = this.name.startsWith('haraka-plugin-') ? this.name.
|
|
55
|
+
const name = this.name.startsWith('haraka-plugin-') ? this.name.slice(14) : this.name
|
|
60
56
|
if (this.name !== name) this.name = name
|
|
61
57
|
|
|
62
58
|
let paths = []
|
|
63
59
|
if (process.env.HARAKA) {
|
|
64
60
|
// Installed mode - started via bin/haraka
|
|
65
|
-
paths = paths
|
|
61
|
+
paths = [...paths, ...plugin_search_paths(process.env.HARAKA, name)]
|
|
66
62
|
|
|
67
63
|
// permit local "folder" plugins (/$name/package.json) (see #1649)
|
|
68
64
|
paths.push(
|
|
@@ -72,7 +68,7 @@ class Plugin {
|
|
|
72
68
|
}
|
|
73
69
|
|
|
74
70
|
// development mode
|
|
75
|
-
paths = paths
|
|
71
|
+
paths = [...paths, ...plugin_search_paths(__dirname, name)]
|
|
76
72
|
for (const pp of paths) {
|
|
77
73
|
if (this.plugin_path) continue
|
|
78
74
|
try {
|
|
@@ -91,11 +87,13 @@ class Plugin {
|
|
|
91
87
|
// haraka/config folder for overrides
|
|
92
88
|
return exports.config.module_config(path.dirname(this.plugin_path), process.env.HARAKA || __dirname)
|
|
93
89
|
}
|
|
90
|
+
|
|
94
91
|
if (process.env.HARAKA) {
|
|
95
92
|
// Plain .js file, installed mode - look in core folder for defaults,
|
|
96
93
|
// install dir for overrides
|
|
97
94
|
return exports.config.module_config(__dirname, process.env.HARAKA)
|
|
98
95
|
}
|
|
96
|
+
|
|
99
97
|
if (process.env.HARAKA_TEST_DIR) {
|
|
100
98
|
return exports.config.module_config(process.env.HARAKA_TEST_DIR)
|
|
101
99
|
}
|
|
@@ -158,17 +156,19 @@ class Plugin {
|
|
|
158
156
|
return require(module)
|
|
159
157
|
}
|
|
160
158
|
|
|
161
|
-
|
|
162
|
-
|
|
159
|
+
for (const ext of [`${module}.js`, module]) {
|
|
160
|
+
if (fs.existsSync(path.join(__dirname, ext))) {
|
|
161
|
+
return require(module)
|
|
162
|
+
}
|
|
163
163
|
}
|
|
164
164
|
|
|
165
165
|
return require(path.join(path.dirname(this.plugin_path), module))
|
|
166
166
|
}
|
|
167
167
|
}
|
|
168
168
|
|
|
169
|
-
_get_code(
|
|
169
|
+
_get_code(pi_path) {
|
|
170
170
|
if (this.hasPackageJson) {
|
|
171
|
-
let packageDir = path.dirname(
|
|
171
|
+
let packageDir = path.dirname(pi_path)
|
|
172
172
|
if (/^win(32|64)/.test(process.platform)) {
|
|
173
173
|
// escape the c:\path\back\slashes else they disappear
|
|
174
174
|
packageDir = packageDir.replace(/\\/g, '\\\\')
|
|
@@ -177,7 +177,7 @@ class Plugin {
|
|
|
177
177
|
}
|
|
178
178
|
|
|
179
179
|
try {
|
|
180
|
-
return `"use strict";${fs.readFileSync(
|
|
180
|
+
return `"use strict";${fs.readFileSync(pi_path)}`
|
|
181
181
|
} catch (err) {
|
|
182
182
|
if (exports.config.get('smtp.ini').main.ignore_bad_plugins) {
|
|
183
183
|
plugins.logcrit(`Loading ${this.name} failed: ${err}`)
|
|
@@ -241,8 +241,13 @@ process.on('message', (msg) => {
|
|
|
241
241
|
|
|
242
242
|
function plugin_search_paths(prefix, name) {
|
|
243
243
|
return [
|
|
244
|
+
// Haraka/plugins/*.js
|
|
244
245
|
path.resolve(prefix, 'plugins', `${name}.js`),
|
|
246
|
+
|
|
247
|
+
// Haraka/node_modules/haraka-plugin-*/package.json
|
|
245
248
|
path.resolve(prefix, 'node_modules', `haraka-plugin-${name}`, 'package.json'),
|
|
249
|
+
|
|
250
|
+
// global node_modules/haraka-plugin-*/package.json
|
|
246
251
|
path.resolve(prefix, '..', `haraka-plugin-${name}`, 'package.json'),
|
|
247
252
|
]
|
|
248
253
|
}
|
|
@@ -281,7 +286,7 @@ plugins.load_plugins = (override) => {
|
|
|
281
286
|
}
|
|
282
287
|
|
|
283
288
|
for (let plugin of plugin_list) {
|
|
284
|
-
if (plugin.startsWith('haraka-plugin-')) plugin = plugin.
|
|
289
|
+
if (plugin.startsWith('haraka-plugin-')) plugin = plugin.substring(14)
|
|
285
290
|
if (plugins.deprecated[plugin]) {
|
|
286
291
|
plugins.lognotice(
|
|
287
292
|
`${plugin} has been replaced by '${plugins.deprecated[plugin]}'. Please update config/plugins`,
|
|
@@ -467,7 +472,7 @@ plugins.run_next_hook = (hook, object, params) => {
|
|
|
467
472
|
}
|
|
468
473
|
|
|
469
474
|
const respond_method = `${hook}_respond`
|
|
470
|
-
if (item && is_deny_retval(retval) && hook.
|
|
475
|
+
if (item && is_deny_retval(retval) && hook.substring(0, 5) !== 'init_') {
|
|
471
476
|
object.deny_respond = get_denyfn(object, hook, params, retval, msg, respond_method)
|
|
472
477
|
plugins.run_hooks('deny', object, [retval, msg, item[0].name, item[1], params, hook])
|
|
473
478
|
} else {
|
package/rfc1869.js
CHANGED
|
@@ -33,7 +33,7 @@ exports.parse = (type, line, strict) => {
|
|
|
33
33
|
|
|
34
34
|
while (1) {
|
|
35
35
|
const old_length = line.length
|
|
36
|
-
line = line.replace(chew_regexp,
|
|
36
|
+
line = line.replace(chew_regexp, (str, p1) => {
|
|
37
37
|
params.push(p1)
|
|
38
38
|
return ''
|
|
39
39
|
})
|
|
@@ -73,17 +73,17 @@ exports.parse = (type, line, strict) => {
|
|
|
73
73
|
throw new Error('Syntax error in parameters')
|
|
74
74
|
}
|
|
75
75
|
} else {
|
|
76
|
-
// console.log(`Looking at ${line}
|
|
76
|
+
// console.log(`Looking at ${line}`);
|
|
77
77
|
if (line.match(/@.*\s/)) {
|
|
78
78
|
throw new Error('Syntax error in parameters')
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
}
|
|
79
|
+
}
|
|
80
|
+
if (line.match(/\s/)) {
|
|
81
|
+
throw new Error('Syntax error in parameters')
|
|
82
|
+
}
|
|
83
|
+
if (line.match(/@/)) {
|
|
84
|
+
if (!line.match(/^<.*>$/)) line = `<${line}>`
|
|
85
|
+
} else if (!line.match(/^<(postmaster|abuse)>$/i)) {
|
|
86
|
+
throw new Error(`Syntax error in address: ${line}`)
|
|
87
87
|
}
|
|
88
88
|
}
|
|
89
89
|
|
package/run_tests
CHANGED
|
@@ -1,5 +1,23 @@
|
|
|
1
1
|
#!/bin/sh
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
# Files using node:test
|
|
4
|
+
NODE_TEST_FILES="test/transaction.js test/connection.js test/outbound/*.js"
|
|
4
5
|
|
|
5
|
-
|
|
6
|
+
# Mocha scans test/ but skips transaction.js, connection.js, and outbound/
|
|
7
|
+
MOCHA_IGNORE="--ignore=test/transaction.js --ignore=test/connection.js"
|
|
8
|
+
MOCHA_TESTS="test test/plugins/auth test/plugins/queue test/plugins"
|
|
9
|
+
|
|
10
|
+
if [ -n "$1" ]; then
|
|
11
|
+
case "$1" in
|
|
12
|
+
test/transaction.js | test/connection.js | test/outbound/*)
|
|
13
|
+
node --test "$1"
|
|
14
|
+
;;
|
|
15
|
+
*)
|
|
16
|
+
npx mocha --exit --timeout=4000 "$1"
|
|
17
|
+
;;
|
|
18
|
+
esac
|
|
19
|
+
else
|
|
20
|
+
# default, run 'em all
|
|
21
|
+
node --test --test-concurrency=1 $NODE_TEST_FILES && \
|
|
22
|
+
npx mocha --exit --timeout=4000 $MOCHA_IGNORE $MOCHA_TESTS
|
|
23
|
+
fi
|
package/server.js
CHANGED
|
@@ -92,9 +92,9 @@ Server.daemonize = function () {
|
|
|
92
92
|
}
|
|
93
93
|
}
|
|
94
94
|
|
|
95
|
-
Server.flushQueue = (domain) => {
|
|
95
|
+
Server.flushQueue = async (domain) => {
|
|
96
96
|
if (!Server.cluster) {
|
|
97
|
-
outbound.flush_queue(domain)
|
|
97
|
+
await outbound.flush_queue(domain)
|
|
98
98
|
return
|
|
99
99
|
}
|
|
100
100
|
|
|
@@ -506,7 +506,7 @@ Server.setup_http_listeners = async () => {
|
|
|
506
506
|
app.use(Server.handle404)
|
|
507
507
|
}
|
|
508
508
|
|
|
509
|
-
Server.init_master_respond = (retval, msg) => {
|
|
509
|
+
Server.init_master_respond = async (retval, msg) => {
|
|
510
510
|
if (!(retval === constants.ok || retval === constants.cont)) {
|
|
511
511
|
Server.logerror(`init_master returned error${msg ? `: ${msg}` : ''}`)
|
|
512
512
|
return logger.dump_and_exit(1)
|
|
@@ -517,18 +517,20 @@ Server.init_master_respond = (retval, msg) => {
|
|
|
517
517
|
|
|
518
518
|
// Load the queue if we're just one process
|
|
519
519
|
if (!(cluster && c.nodes)) {
|
|
520
|
-
|
|
520
|
+
try {
|
|
521
|
+
await outbound.init_queue()
|
|
522
|
+
} catch (err) {
|
|
523
|
+
Server.logcrit('Loading queue failed. Shutting down.')
|
|
524
|
+
return logger.dump_and_exit(1)
|
|
525
|
+
}
|
|
521
526
|
Server.setup_http_listeners()
|
|
522
527
|
return
|
|
523
528
|
}
|
|
524
529
|
|
|
525
530
|
// Running under cluster, fork children here, so that
|
|
526
531
|
// cluster events can be registered in init_master hooks.
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
Server.logcrit('Scanning queue failed. Shutting down.')
|
|
530
|
-
return logger.dump_and_exit(1)
|
|
531
|
-
}
|
|
532
|
+
try {
|
|
533
|
+
const pids = await outbound.scan_queue_pids()
|
|
532
534
|
Server.daemonize()
|
|
533
535
|
// Fork workers
|
|
534
536
|
const workers = c.nodes === 'cpus' ? os.cpus().length : c.nodes
|
|
@@ -552,7 +554,10 @@ Server.init_master_respond = (retval, msg) => {
|
|
|
552
554
|
Server.lognotice(`worker ${worker.id} listening on ${endpoint(address)}`)
|
|
553
555
|
})
|
|
554
556
|
cluster.on('exit', cluster_exit_listener)
|
|
555
|
-
})
|
|
557
|
+
} catch (err) {
|
|
558
|
+
Server.logcrit('Scanning queue failed. Shutting down.')
|
|
559
|
+
logger.dump_and_exit(1)
|
|
560
|
+
}
|
|
556
561
|
}
|
|
557
562
|
|
|
558
563
|
function cluster_exit_listener(worker, code, signal) {
|
package/smtp_client.js
CHANGED
|
@@ -192,13 +192,8 @@ class SMTPClient extends events.EventEmitter {
|
|
|
192
192
|
client.socket.on('end', closed('ended'))
|
|
193
193
|
}
|
|
194
194
|
|
|
195
|
-
load_tls_config(opts) {
|
|
196
|
-
|
|
197
|
-
if (opts) {
|
|
198
|
-
Object.assign(tls_options, opts)
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
this.tls_options = tls_options
|
|
195
|
+
load_tls_config(opts = {}) {
|
|
196
|
+
this.tls_options = { servername: this.host, ...opts }
|
|
202
197
|
}
|
|
203
198
|
|
|
204
199
|
send_command(command, data) {
|
|
@@ -212,10 +207,8 @@ class SMTPClient extends events.EventEmitter {
|
|
|
212
207
|
start_data(data) {
|
|
213
208
|
this.response = []
|
|
214
209
|
this.command = 'dot'
|
|
215
|
-
// SUNSET: dot_stuffing was renamed to dot_stuffed, remove it after 2026-01
|
|
216
210
|
data.pipe(this.socket, {
|
|
217
211
|
dot_stuffed: false,
|
|
218
|
-
dot_stuffing: true,
|
|
219
212
|
ending_dot: true,
|
|
220
213
|
end: false,
|
|
221
214
|
})
|
|
@@ -1,51 +1,51 @@
|
|
|
1
1
|
-----BEGIN PRIVATE KEY-----
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
2
|
+
MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQDCdI9wQHH4zJzr
|
|
3
|
+
Kjd4/a4AV8uPnvZwOHC/mhFnAS2V4+oPLgBZYG/yiktsmTcsYl3Cgf3n8X1eMsRl
|
|
4
|
+
i91kdC1+2txMsn/Y6DDAxW+qbYWIvWWPQlCr+eweGAYf3HkWAd3nAiKB1qfnUvL5
|
|
5
|
+
y0werjQFV9cAeK9xqtC7HqaTOYtNnAmipIGLK7y4RQfnzf20Qqu9yv3uC2Gaj3Vk
|
|
6
|
+
EhGFRaIvKxVmnvCmRYa8UM3HKtF4q+ApkoeslJjqK68vSXtDQFZ6qHatotWeYVzt
|
|
7
|
+
luX66f925pKBTU6AVJJQxrCWjQ/KLLLW7qbytaMjagz4IBpRNpb3Wfc7c7/51nDm
|
|
8
|
+
TyECGKMnAgMBAAECggEAFbpmiLl6wr1CT3ixKCDYf4tP4KV3jgSQfKhfh233RQdp
|
|
9
|
+
kPan7VS8TZKsaN8Z7iizp1dVIsS2KH9tuJcPTvk4WDNmaF+Nr5QKVo/5MUb5o9Td
|
|
10
|
+
80sKrpzHiHlQveCp2w6sV/LCHlX4/v0iz0yrHcaDY5F0IcZafE4E8tOy80J70VkL
|
|
11
|
+
NmWb9bP5CKFs7bAknGzXSGonhOVH1Yf7WTE7OYGi5XfBoLWLozTzL19YKez6Je4m
|
|
12
|
+
KHlSzVSmXqmYgZ/48U+RIRp0m31zswAdvmkg6qGNr8F4kXcySDzhQjdeojIj8sho
|
|
13
|
+
MVy9dl+qjSxIBGDjmZz/MfySyEfJABJVf6anx3JE4QKBgQDuQi3x3w/utdtmfI4l
|
|
14
|
+
9n1SsgB3uu/eNl/5LuWyQBKoKO1iyR86LfGo9nqbsiFtg72IfuCy1QSklm5ZVFqL
|
|
15
|
+
vyRb77YH1fbah0BM4JCj2JhKgJMPJTWJ3woC5tJu67nKO3W6yB9TjMOFFl1y41tl
|
|
16
|
+
NJuvoVUNZO1dYMtDJynLJ0GI8QKBgQDQ72EMozJTvS3VDGemXDimkyJyYGKyqV/f
|
|
17
|
+
KzCfW66lLUREPEYN6NaG49jwR/dQfPqBPtTQqLy/HA1ZYNeQR5QdeklQiRVWs0tn
|
|
18
|
+
/Nfbb1DkSPZWebX2o+hPVPUH5XVVZXOR89v8oKvajVE37hKhYK7fHxKgC8gY1zkP
|
|
19
|
+
H6kUD0atlwKBgG9RhF3ptmv1k9jCgTfDfrJQcF+Ae+n6xcSK4M7zmMPwu1jYVzq7
|
|
20
|
+
lJk47/gmte+RCdDoVtu3I0Ay+MPL4bJBUB+UVBw9H+TiJGzGz01+OUk14X/GBsmv
|
|
21
|
+
5+GLLu6cPGX8efkW32wN7JwV4vt2tpEGj2bzneVwLmbefpmVhrVgVgJBAoGAD/WZ
|
|
22
|
+
BiwZFghnTdTKvgxhT2gBw5bVMyx45EUaS7HnHzrb8hJgj4Nvj5Ir6f61R3Kkd+bi
|
|
23
|
+
vqWE9VwhMOiSzrSI/c9vdjViaeL8KY9ItbxFA4sHNgfJ/HL8tcKZjObcFY/QSh/E
|
|
24
|
+
eAGV3vXYdFs9FRKbiPOIqqz7tdoKw7r5YUzhazUCgYBYWwvYgeccNBPeamROwt73
|
|
25
|
+
C1hWbjcrHhMRrB84vcM0j6EHIk689HJu7VobwJooQOALvyh7VSlD1b5V2DstsBiX
|
|
26
|
+
cD2uKAwdLlRJuThTxgq81qW4h8KnDpdFYrwFsevaA+r4c7ihy/2oeASY6SMqUC89
|
|
27
|
+
jAJOkfhhCdoj6D85HLIMNw==
|
|
28
28
|
-----END PRIVATE KEY-----
|
|
29
29
|
-----BEGIN CERTIFICATE-----
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
30
|
+
MIID3TCCAsWgAwIBAgIUaYxDRJxsA5vqHEHzLkRzYlYJhGwwDQYJKoZIhvcNAQEL
|
|
31
|
+
BQAwfjELMAkGA1UEBhMCVVMxEzARBgNVBAgMCldhc2hpbmd0b24xEDAOBgNVBAcM
|
|
32
|
+
B1NlYXR0bGUxDzANBgNVBAoMBkhhcmFrYTEVMBMGA1UEAwwMaGFyYWthLmxvY2Fs
|
|
33
|
+
MSAwHgYJKoZIhvcNAQkBFhFtYXR0QGhhcmFrYS5sb2NhbDAeFw0yNjAzMjUwNDI1
|
|
34
|
+
MzJaFw0yOTAzMjQwNDI1MzJaMH4xCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApXYXNo
|
|
35
|
+
aW5ndG9uMRAwDgYDVQQHDAdTZWF0dGxlMQ8wDQYDVQQKDAZIYXJha2ExFTATBgNV
|
|
36
|
+
BAMMDGhhcmFrYS5sb2NhbDEgMB4GCSqGSIb3DQEJARYRbWF0dEBoYXJha2EubG9j
|
|
37
|
+
YWwwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDCdI9wQHH4zJzrKjd4
|
|
38
|
+
/a4AV8uPnvZwOHC/mhFnAS2V4+oPLgBZYG/yiktsmTcsYl3Cgf3n8X1eMsRli91k
|
|
39
|
+
dC1+2txMsn/Y6DDAxW+qbYWIvWWPQlCr+eweGAYf3HkWAd3nAiKB1qfnUvL5y0we
|
|
40
|
+
rjQFV9cAeK9xqtC7HqaTOYtNnAmipIGLK7y4RQfnzf20Qqu9yv3uC2Gaj3VkEhGF
|
|
41
|
+
RaIvKxVmnvCmRYa8UM3HKtF4q+ApkoeslJjqK68vSXtDQFZ6qHatotWeYVztluX6
|
|
42
|
+
6f925pKBTU6AVJJQxrCWjQ/KLLLW7qbytaMjagz4IBpRNpb3Wfc7c7/51nDmTyEC
|
|
43
|
+
GKMnAgMBAAGjUzBRMB0GA1UdDgQWBBSzcvDenCZgIgox2IXTubXgLv/6xTAfBgNV
|
|
44
|
+
HSMEGDAWgBSzcvDenCZgIgox2IXTubXgLv/6xTAPBgNVHRMBAf8EBTADAQH/MA0G
|
|
45
|
+
CSqGSIb3DQEBCwUAA4IBAQAQK28lJKzpDm7LZHPPxGczn4jaBYtSYZ2aM1SP+fRv
|
|
46
|
+
TMyl6QEm4atyQCETWngVEHw9zM2uVH9lUvqxRQVLxQL0Hdi05l+PGc5c/UNGsOa6
|
|
47
|
+
4LJSP8f0OPvvWiMc1coWAxM9UCtAByTiMWyqbdhm9huZ8XWCBWjZ6HJswMxrFFs8
|
|
48
|
+
WE0Zrdh+lutDilL9af6FF0vI1PW7dyo8a5tKZ13tYI3C4feyQoao0xZZZSvw+v50
|
|
49
|
+
Pq/HLEre2zfxy11QbKVTco8ipwxRVsF3XfKKco6Vh3APp03v3QhlRovbxJsV2ZE0
|
|
50
|
+
F8a2QrvoPLEBqyDPFyRc5+EgJFJcNBzrbBYbGLGA7sJ+
|
|
51
51
|
-----END CERTIFICATE-----
|