Haraka 3.1.3 → 3.1.5
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 +52 -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 +26 -29
- package/plugins/prevent_credential_leaks.js +2 -2
- package/plugins/process_title.js +1 -1
- package/plugins/queue/smtp_forward.js +5 -5
- 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 +8 -2
- package/server.js +15 -10
- package/smtp_client.js +10 -15
- package/test/config/tls/haraka.local.pem +47 -47
- package/test/connection.js +286 -147
- package/test/endpoint.js +5 -4
- package/test/fixtures/line_socket.js +1 -0
- package/test/fixtures/util_hmailitem.js +1 -1
- package/test/host_pool.js +57 -31
- package/test/logger.js +75 -135
- package/test/outbound/bounce_net_errors.js +132 -0
- package/test/outbound/bounce_rfc3464.js +226 -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/auth/auth_base.js +39 -44
- package/test/plugins/auth/auth_vpopmaild.js +8 -9
- package/test/plugins/queue/smtp_forward.js +953 -183
- package/test/plugins/rcpt_to.host_list_base.js +58 -93
- package/test/plugins/rcpt_to.in_host_list.js +126 -175
- package/test/plugins/record_envelope_addresses.js +93 -0
- package/test/plugins/status.js +10 -10
- package/test/plugins/tls.js +11 -21
- package/test/plugins/xclient.js +102 -0
- package/test/plugins.js +10 -13
- package/test/rfc1869.js +71 -48
- package/test/server.js +281 -436
- package/test/smtp_client.js +1194 -220
- package/test/tls_socket.js +74 -243
- package/test/transaction.js +486 -201
- package/tls_socket.js +19 -23
- 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
|
@@ -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
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|
const url = require('node:url')
|
|
8
8
|
|
|
9
|
-
const smtp_client_mod = require('
|
|
9
|
+
const smtp_client_mod = require('../../smtp_client')
|
|
10
10
|
|
|
11
11
|
exports.register = function () {
|
|
12
12
|
this.load_errs = []
|
|
@@ -247,7 +247,7 @@ exports.queue_forward = function (next, connection) {
|
|
|
247
247
|
)
|
|
248
248
|
|
|
249
249
|
function get_rs() {
|
|
250
|
-
return
|
|
250
|
+
return txn?.results ?? connection.results
|
|
251
251
|
}
|
|
252
252
|
|
|
253
253
|
function dead_sender() {
|
|
@@ -320,10 +320,10 @@ exports.get_mx_next_hop = (next_hop) => {
|
|
|
320
320
|
exchange: dest.hostname,
|
|
321
321
|
}
|
|
322
322
|
if (dest.protocol === 'lmtp:') mx.using_lmtp = true
|
|
323
|
-
if (dest.
|
|
323
|
+
if (dest.username) {
|
|
324
324
|
mx.auth_type = 'plain'
|
|
325
|
-
mx.auth_user = dest.
|
|
326
|
-
mx.auth_pass = dest.
|
|
325
|
+
mx.auth_user = dest.username
|
|
326
|
+
mx.auth_pass = dest.password
|
|
327
327
|
}
|
|
328
328
|
return mx
|
|
329
329
|
}
|
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,11 @@
|
|
|
1
1
|
#!/bin/sh
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
# Files using node:test
|
|
4
|
+
NODE_TEST_FILES="test/*.js test/outbound/*.js test/plugins/*.js test/plugins/auth/*.js test/plugins/queue/*.js"
|
|
4
5
|
|
|
5
|
-
|
|
6
|
+
if [ -n "$1" ]; then
|
|
7
|
+
node --test "$1"
|
|
8
|
+
else
|
|
9
|
+
# default, run 'em all
|
|
10
|
+
node --test --test-concurrency=1 $NODE_TEST_FILES
|
|
11
|
+
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
|
})
|
|
@@ -223,8 +216,7 @@ class SMTPClient extends events.EventEmitter {
|
|
|
223
216
|
|
|
224
217
|
release() {
|
|
225
218
|
if (this.state === STATE.DESTROYED) return
|
|
226
|
-
|
|
227
|
-
;[
|
|
219
|
+
const listeners = [
|
|
228
220
|
'auth',
|
|
229
221
|
'bad_code',
|
|
230
222
|
'capabilities',
|
|
@@ -240,9 +232,11 @@ class SMTPClient extends events.EventEmitter {
|
|
|
240
232
|
'rset',
|
|
241
233
|
'server_protocol',
|
|
242
234
|
'xclient',
|
|
243
|
-
]
|
|
235
|
+
]
|
|
236
|
+
logger.debug(`[smtp_client] ${this.uuid} releasing, state=${this.state}`)
|
|
237
|
+
for (const l of listeners) {
|
|
244
238
|
this.removeAllListeners(l)
|
|
245
|
-
}
|
|
239
|
+
}
|
|
246
240
|
|
|
247
241
|
if (this.connected) this.send_command('QUIT')
|
|
248
242
|
this.destroy()
|
|
@@ -356,7 +350,7 @@ exports.get_client_plugin = (plugin, connection, c, callback) => {
|
|
|
356
350
|
}
|
|
357
351
|
}
|
|
358
352
|
|
|
359
|
-
const hostport = get_hostport(connection,
|
|
353
|
+
const hostport = get_hostport(connection, c)
|
|
360
354
|
const smtp_client = new SMTPClient(hostport)
|
|
361
355
|
logger.info(`[smtp_client] uuid=${smtp_client.uuid} host=${hostport.host} port=${hostport.port} created`)
|
|
362
356
|
|
|
@@ -475,7 +469,8 @@ exports.get_client_plugin = (plugin, connection, c, callback) => {
|
|
|
475
469
|
callback(null, smtp_client)
|
|
476
470
|
}
|
|
477
471
|
|
|
478
|
-
function get_hostport(connection,
|
|
472
|
+
function get_hostport(connection, cfg) {
|
|
473
|
+
const server = connection.server
|
|
479
474
|
if (cfg.forwarding_host_pool) {
|
|
480
475
|
if (!server.notes.host_pool) {
|
|
481
476
|
connection.logwarn(`creating host_pool from ${cfg.forwarding_host_pool}`)
|
|
@@ -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-----
|