miolo 2.0.0-beta.1 → 2.0.0-beta.3
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/dist/cli/miolo.cli.umd.js +1 -1
- package/dist/cli-react/miolo.cli-react.umd.js +1 -1
- package/dist/server/miolo.server.node.mjs +1 -1
- package/package.json +18 -18
- package/src/cli/catcher/index.mjs +75 -0
- package/src/cli/fetcher/fetcher.mjs +214 -0
- package/src/cli/fetcher/index.mjs +7 -0
- package/src/cli/fetcher/utils.mjs +51 -0
- package/src/cli/fetcher/v1.tar.gz +0 -0
- package/src/cli/index.mjs +30 -0
- package/src/cli/socket/index.mjs +6 -0
- package/src/cli-react/AppBrowser.jsx +14 -0
- package/src/cli-react/AppBrowser.mjs +14 -0
- package/src/cli-react/AppServer.jsx +17 -0
- package/src/cli-react/AppServer.mjs +16 -0
- package/src/cli-react/_jsx.tar.gz +0 -0
- package/src/cli-react/context/MioloContext.mjs +5 -0
- package/src/cli-react/context/MioloContextProvider.jsx +87 -0
- package/src/cli-react/context/MioloContextProvider.mjs +80 -0
- package/src/cli-react/context/useMioloContext.jsx +6 -0
- package/src/cli-react/context/useMioloContext.mjs +6 -0
- package/src/cli-react/context/withMioloContext.jsx +15 -0
- package/src/cli-react/context/withMioloContext.mjs +17 -0
- package/src/cli-react/index.mjs +7 -0
- package/src/cli-react/ssr/getSsrDataFromContext.mjs +33 -0
- package/src/cli-react/ssr/hooks.tar.gz +0 -0
- package/src/cli-react/ssr/useSsrDataOrReload.mjs +43 -0
- package/src/server/config/defaults.mjs +418 -0
- package/src/server/config/index.mjs +32 -0
- package/src/server/engines/cron/emails.mjs +10 -0
- package/src/server/engines/cron/index.mjs +153 -0
- package/src/server/engines/cron/init.mjs +53 -0
- package/src/server/engines/cron/ipsum.mjs +151 -0
- package/src/server/engines/cron/syscheck.mjs +56 -0
- package/src/server/engines/emailer/index.mjs +2 -0
- package/src/server/engines/emailer/queue.mjs +54 -0
- package/src/server/engines/emailer/transporter.mjs +149 -0
- package/src/server/engines/geoip/index.mjs +66 -0
- package/src/server/engines/http/index.mjs +79 -0
- package/src/server/engines/logger/index.mjs +313 -0
- package/src/server/engines/logger/logger_mail.mjs +89 -0
- package/src/server/engines/logger/reopenTransportOnHupSignal.mjs +57 -0
- package/src/server/engines/logger/verify.mjs +22 -0
- package/src/server/engines/parser/Parser.mjs +126 -0
- package/src/server/engines/parser/index.mjs +6 -0
- package/src/server/engines/socket/index.mjs +67 -0
- package/src/server/index.mjs +16 -0
- package/src/server/middleware/auth/basic.mjs +90 -0
- package/src/server/middleware/auth/credentials/index.mjs +151 -0
- package/src/server/middleware/auth/credentials/session/index.mjs +24 -0
- package/src/server/middleware/auth/credentials/session/store.mjs +59 -0
- package/src/server/middleware/auth/credentials/session/store_koa_redis.mjs +3 -0
- package/src/server/middleware/auth/custom.mjs +29 -0
- package/src/server/middleware/auth/guest.mjs +75 -0
- package/src/server/middleware/context/cache/index.mjs +61 -0
- package/src/server/middleware/context/cache/options.mjs +66 -0
- package/src/server/middleware/context/db.mjs +58 -0
- package/src/server/middleware/context/index.mjs +35 -0
- package/src/server/middleware/extra.mjs +12 -0
- package/src/server/middleware/http/body.mjs +31 -0
- package/src/server/middleware/http/catcher.mjs +81 -0
- package/src/server/middleware/http/custom_blacklist.mjs +16 -0
- package/src/server/middleware/http/headers.mjs +73 -0
- package/src/server/middleware/http/ratelimit.mjs +66 -0
- package/src/server/middleware/http/request.mjs +146 -0
- package/src/server/middleware/routes/catch_js_error.mjs +41 -0
- package/src/server/middleware/routes/robots.mjs +21 -0
- package/src/server/middleware/routes/router/crud/attachCrudRoutes.mjs +214 -0
- package/src/server/middleware/routes/router/crud/getCrudConfig.mjs +129 -0
- package/src/server/middleware/routes/router/defaults.mjs +29 -0
- package/src/server/middleware/routes/router/index.mjs +49 -0
- package/src/server/middleware/routes/router/queries/attachQueriesRoutes.mjs +102 -0
- package/src/server/middleware/routes/router/queries/getQueriesConfig.mjs +113 -0
- package/src/server/middleware/routes/router/utils.mjs +38 -0
- package/src/server/middleware/ssr/_old.tar.gz +0 -0
- package/src/server/middleware/ssr/context.mjs +21 -0
- package/src/server/middleware/ssr/fallbackIndex.mjs +29 -0
- package/src/server/middleware/ssr/html.mjs +64 -0
- package/src/server/middleware/ssr/loader.mjs +24 -0
- package/src/server/middleware/ssr/ssr_render.mjs +49 -0
- package/src/server/middleware/static/afialapis.ico +0 -0
- package/src/server/middleware/static/index.mjs +27 -0
- package/src/server/middleware/static/miolo.ico +0 -0
- package/src/server/middleware/vite/devserver.mjs +34 -0
- package/src/server/server-dev.mjs +41 -0
- package/src/server/server.mjs +135 -0
- package/src/server/static/img/afialapis.ico +0 -0
- package/src/server/static/img/miolo.ico +0 -0
- package/src/server/static/robots.txt +2 -0
- package/dist/cli/miolo.cli.iife.bundle.js +0 -968
- package/dist/cli/miolo.cli.iife.bundle.js.map +0 -1
- package/dist/cli/miolo.cli.iife.bundle.min.js +0 -13
- package/dist/cli/miolo.cli.iife.js +0 -968
- package/dist/cli/miolo.cli.iife.js.map +0 -1
- package/dist/cli/miolo.cli.iife.min.js +0 -13
- package/dist/cli/miolo.cli.min.mjs +0 -13
- package/dist/cli/miolo.cli.mjs +0 -485
- package/dist/cli/miolo.cli.mjs.map +0 -1
- package/dist/cli/miolo.cli.umd.bundle.js +0 -969
- package/dist/cli/miolo.cli.umd.bundle.js.map +0 -1
- package/dist/cli/miolo.cli.umd.bundle.min.js +0 -13
- package/dist/cli/miolo.cli.umd.min.js +0 -13
- package/dist/cli-react/miolo.cli-react.iife.bundle.js +0 -1232
- package/dist/cli-react/miolo.cli-react.iife.bundle.js.map +0 -1
- package/dist/cli-react/miolo.cli-react.iife.bundle.min.js +0 -13
- package/dist/cli-react/miolo.cli-react.iife.js +0 -1174
- package/dist/cli-react/miolo.cli-react.iife.js.map +0 -1
- package/dist/cli-react/miolo.cli-react.iife.min.js +0 -13
- package/dist/cli-react/miolo.cli-react.min.mjs +0 -13
- package/dist/cli-react/miolo.cli-react.mjs +0 -655
- package/dist/cli-react/miolo.cli-react.mjs.map +0 -1
- package/dist/cli-react/miolo.cli-react.umd.bundle.js +0 -1233
- package/dist/cli-react/miolo.cli-react.umd.bundle.js.map +0 -1
- package/dist/cli-react/miolo.cli-react.umd.bundle.min.js +0 -13
- package/dist/cli-react/miolo.cli-react.umd.min.js +0 -13
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
import {
|
|
2
|
+
init_cron_job
|
|
3
|
+
} from './init.mjs'
|
|
4
|
+
import {
|
|
5
|
+
sys_check_config
|
|
6
|
+
} from './syscheck.mjs'
|
|
7
|
+
import {
|
|
8
|
+
ipsum_config
|
|
9
|
+
} from './ipsum.mjs'
|
|
10
|
+
import { cyan, green_bold, yellow_bold } from 'tinguir'
|
|
11
|
+
import { sys_email_queue_config } from './emails.mjs'
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
export function init_cron(app, custom) {
|
|
15
|
+
const miolo = app.context.miolo
|
|
16
|
+
const logger= miolo.logger
|
|
17
|
+
|
|
18
|
+
const jobConfigs= [
|
|
19
|
+
sys_check_config(),
|
|
20
|
+
ipsum_config(),
|
|
21
|
+
sys_email_queue_config(),
|
|
22
|
+
...custom || []
|
|
23
|
+
]
|
|
24
|
+
|
|
25
|
+
// Keep trace of conr jobs to be accessible later
|
|
26
|
+
const jobInfos= [
|
|
27
|
+
// {name: 'name', job: <job>, isActive: true/false}
|
|
28
|
+
]
|
|
29
|
+
|
|
30
|
+
jobConfigs.map(config => {
|
|
31
|
+
const name = config.name
|
|
32
|
+
const job= init_cron_job(miolo, config)
|
|
33
|
+
jobInfos.push({
|
|
34
|
+
name,
|
|
35
|
+
job,
|
|
36
|
+
isActive: false
|
|
37
|
+
})
|
|
38
|
+
})
|
|
39
|
+
|
|
40
|
+
const _find_job_by_idx_or_name = (idxOrName) => {
|
|
41
|
+
let jobInfo
|
|
42
|
+
if (typeof idxOrName == 'number') {
|
|
43
|
+
jobInfo= jobInfos[idxOrName]
|
|
44
|
+
} else {
|
|
45
|
+
jobInfo= jobInfos.filter(j => j.name == idxOrName)[0]
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
if (!jobInfo) {
|
|
49
|
+
logger.error(`[cron] Job ${cyan(idxOrName)} Not Found`)
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
return jobInfo
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const _start_job = (jobInfo) => {
|
|
56
|
+
try {
|
|
57
|
+
jobInfo.job.start()
|
|
58
|
+
jobInfo.isActive= true
|
|
59
|
+
logger.debug(`[cron][Job ${cyan(jobInfo.name)}] ${green_bold('started!')}`)
|
|
60
|
+
return 1
|
|
61
|
+
} catch(e) {
|
|
62
|
+
logger.error(`[cron][Job ${cyan(jobInfo.name)}] Error starting it`)
|
|
63
|
+
logger.error(e)
|
|
64
|
+
return 0
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
const _start_job_by_idx_or_name = (idxOrName) => {
|
|
69
|
+
const jobInfo = _find_job_by_idx_or_name(idxOrName)
|
|
70
|
+
if (jobInfo) {
|
|
71
|
+
const done = _start_job(jobInfo)
|
|
72
|
+
return [done, jobInfo.name]
|
|
73
|
+
}
|
|
74
|
+
return [0, '']
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const _start_all_jobs = () => {
|
|
78
|
+
try {
|
|
79
|
+
let started= [], errors= []
|
|
80
|
+
jobInfos.map(jobInfo => {
|
|
81
|
+
const done= _start_job(jobInfo)
|
|
82
|
+
if (done == 1) {
|
|
83
|
+
started.push(jobInfo.name)
|
|
84
|
+
} else {
|
|
85
|
+
errors.push(jobInfo.name)
|
|
86
|
+
}
|
|
87
|
+
})
|
|
88
|
+
if (started.length > 0) {
|
|
89
|
+
logger.info(`[cron] Started ${started.length} jobs: ${started}`)
|
|
90
|
+
}
|
|
91
|
+
if (errors.length > 0) {
|
|
92
|
+
logger.warn(`[cron] Could not start ${errors.length} jobs: ${errors}`)
|
|
93
|
+
}
|
|
94
|
+
} catch(error) {
|
|
95
|
+
logger.error(`[cron] start() error: ${error}`)
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
const _stop_job = (jobInfo) => {
|
|
101
|
+
try {
|
|
102
|
+
jobInfo.job.stop()
|
|
103
|
+
jobInfo.isActive= false
|
|
104
|
+
logger.debug(`[cron][Job ${cyan(jobInfo.name)}] ${yellow_bold('stopped!')}`)
|
|
105
|
+
return 1
|
|
106
|
+
} catch(e) {
|
|
107
|
+
logger.error(`[cron][Job ${cyan(jobInfo.name)}] Error stopping it`)
|
|
108
|
+
logger.error(e)
|
|
109
|
+
return 0
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
const _stop_job_by_idx_or_name = (idxOrName) => {
|
|
114
|
+
const jobInfo = _find_job_by_idx_or_name(idxOrName)
|
|
115
|
+
if (jobInfo) {
|
|
116
|
+
const done = _stop_job(jobInfo)
|
|
117
|
+
return [done, jobInfo.name]
|
|
118
|
+
}
|
|
119
|
+
return [0, '']
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
const _stop_all_jobs = () => {
|
|
123
|
+
try {
|
|
124
|
+
let stopped= [], errors= []
|
|
125
|
+
jobInfos.map(jobInfo => {
|
|
126
|
+
const done= _stop_job(jobInfo)
|
|
127
|
+
if (done == 1) {
|
|
128
|
+
stopped.push(jobInfo.name)
|
|
129
|
+
} else {
|
|
130
|
+
errors.push(jobInfo.name)
|
|
131
|
+
}
|
|
132
|
+
})
|
|
133
|
+
if (stopped.length > 0) {
|
|
134
|
+
logger.info(`[cron] Stopped ${stopped.length} jobs: ${stopped}`)
|
|
135
|
+
}
|
|
136
|
+
if (errors.length > 0) {
|
|
137
|
+
logger.warn(`[cron] Could not stop ${errors.length} jobs: ${errors}`)
|
|
138
|
+
}
|
|
139
|
+
} catch(error) {
|
|
140
|
+
logger.error(`[cron] stop() error: ${error}`)
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
app.cron= {
|
|
145
|
+
jobs: jobInfos,
|
|
146
|
+
start_one: _start_job_by_idx_or_name,
|
|
147
|
+
start: _start_all_jobs,
|
|
148
|
+
stop_one : _stop_job_by_idx_or_name,
|
|
149
|
+
stop: _stop_all_jobs
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
return app
|
|
153
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
|
|
2
|
+
import {CronJob} from 'cron'
|
|
3
|
+
import { cyan, green_bold } from 'tinguir'
|
|
4
|
+
|
|
5
|
+
export function init_cron_job(miolo, config) {
|
|
6
|
+
const logger= miolo.logger
|
|
7
|
+
const onTickName = config?.onTick?.name
|
|
8
|
+
? config.onTick.name != 'onTick'
|
|
9
|
+
? config.onTick.name
|
|
10
|
+
: 'custom'
|
|
11
|
+
: 'custom'
|
|
12
|
+
|
|
13
|
+
const name = config?.name || onTickName
|
|
14
|
+
|
|
15
|
+
const job= new CronJob(
|
|
16
|
+
// cronTime
|
|
17
|
+
config?.cronTime || '*/5 * * * *',
|
|
18
|
+
|
|
19
|
+
// onTick(miolo, onComplete)
|
|
20
|
+
(onComplete) => {
|
|
21
|
+
try {
|
|
22
|
+
logger.silly(`[cron][Custom Job ${cyan(name)}] ${green_bold('ticks!')}`)
|
|
23
|
+
config.onTick(miolo, onComplete)
|
|
24
|
+
} catch(e) {
|
|
25
|
+
logger.error(`[cron][Custom Job ${cyan(name)}] Error at onTick()`)
|
|
26
|
+
logger.error(e)
|
|
27
|
+
}
|
|
28
|
+
},
|
|
29
|
+
|
|
30
|
+
// onComplete(miolo)
|
|
31
|
+
() => {
|
|
32
|
+
logger.silly(`[cron][Custom Job ${cyan(name)}] ${green_bold('completed!')}`)
|
|
33
|
+
if (config?.onComplete) {
|
|
34
|
+
try {
|
|
35
|
+
config.onComplete(miolo)
|
|
36
|
+
} catch(e) {
|
|
37
|
+
logger.error(`[cron][Custom Job ${cyan(name)}] Error at onComplete()`)
|
|
38
|
+
logger.error(e)
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
},
|
|
42
|
+
|
|
43
|
+
// Do not start yet
|
|
44
|
+
false,
|
|
45
|
+
|
|
46
|
+
config?.timezone || 'Europe/Madrid',
|
|
47
|
+
// config?.context || null,
|
|
48
|
+
// config?.runOnInit || null,
|
|
49
|
+
// config?.utcOffset || null,
|
|
50
|
+
// config?.unrefTimeout || null,
|
|
51
|
+
)
|
|
52
|
+
return job
|
|
53
|
+
}
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
import path from 'path'
|
|
2
|
+
import fs from 'fs'
|
|
3
|
+
import https from 'https'
|
|
4
|
+
//import fetch from 'node-fetch'
|
|
5
|
+
import { cyan, green, yellow } from 'tinguir'
|
|
6
|
+
|
|
7
|
+
const _IPSUM_DEF_FOLDER = '/var/ipsum'
|
|
8
|
+
const _IPSUM_FILE_NAME = 'ipsum.txt'
|
|
9
|
+
const _IPSUM_REMOTE_FILE = 'https://raw.githubusercontent.com/stamparm/ipsum/master/ipsum.txt'
|
|
10
|
+
const _IPSUM_NLISTS = 1
|
|
11
|
+
|
|
12
|
+
/*function ipsum_download_file(callback, remote_file = _IPSUM_REMOTE_FILE) {
|
|
13
|
+
fetch(remote_file).then(response => {
|
|
14
|
+
response.text().then((content) => {
|
|
15
|
+
callback(content)
|
|
16
|
+
})
|
|
17
|
+
})
|
|
18
|
+
}*/
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
export function ipsum_download_file(callback, remote_file = _IPSUM_REMOTE_FILE, logger) {
|
|
22
|
+
const lerr = logger ? logger.error : console.error
|
|
23
|
+
|
|
24
|
+
https.get(remote_file, (res) => {
|
|
25
|
+
const data = []
|
|
26
|
+
res.on('data', (chunk) => {
|
|
27
|
+
data.push(chunk)
|
|
28
|
+
}).on('end', () => {
|
|
29
|
+
let content = Buffer.concat(data).toString()
|
|
30
|
+
callback(content)
|
|
31
|
+
})
|
|
32
|
+
}).on('error', (err) => {
|
|
33
|
+
lerr(`[cron][${cyan('IPsum')}] Error downloading remote file (${err.toString()})`)
|
|
34
|
+
callback('')
|
|
35
|
+
})
|
|
36
|
+
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function _ipsum_ips_from_content(content, logger) {
|
|
40
|
+
const lerr = logger ? logger.error : console.error
|
|
41
|
+
|
|
42
|
+
if (! content) {
|
|
43
|
+
return []
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
try {
|
|
47
|
+
let ips = []
|
|
48
|
+
content
|
|
49
|
+
.split('\n')
|
|
50
|
+
.filter(line => line.indexOf('#') < 0)
|
|
51
|
+
.map(line => {
|
|
52
|
+
const [ip, nlists] = line.split('\t')
|
|
53
|
+
if (parseInt(nlists) >= _IPSUM_NLISTS) {
|
|
54
|
+
ips.push(ip)
|
|
55
|
+
}
|
|
56
|
+
})
|
|
57
|
+
return ips
|
|
58
|
+
} catch(error) {
|
|
59
|
+
lerr(`[cron][${cyan('IPsum')}] Error getting IPs from content`)
|
|
60
|
+
return []
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function _ipsum_ips_from_file(folder= _IPSUM_DEF_FOLDER, logger) {
|
|
65
|
+
const lerr = logger ? logger.error : console.error
|
|
66
|
+
|
|
67
|
+
if (! fs.existsSync(folder)) {
|
|
68
|
+
if (logger) {
|
|
69
|
+
lerr(`[cron][${cyan('IPsum')}] Folder ${folder} does not exist`)
|
|
70
|
+
}
|
|
71
|
+
return []
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const local_path = path.join(folder, _IPSUM_FILE_NAME)
|
|
75
|
+
|
|
76
|
+
if (! fs.existsSync(local_path)) {
|
|
77
|
+
if (logger) {
|
|
78
|
+
lerr(`[cron][${cyan('IPsum')}] File ${local_path} does not exist`)
|
|
79
|
+
}
|
|
80
|
+
return []
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
const content = fs.readFileSync(local_path, {encoding:'utf8'})
|
|
84
|
+
return _ipsum_ips_from_content(content, logger)
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
function ipsum_update(folder= _IPSUM_DEF_FOLDER, callback, logger) {
|
|
89
|
+
const lerr = logger ? logger.error : console.error
|
|
90
|
+
const ldbg = logger ? logger.debug : console.log
|
|
91
|
+
|
|
92
|
+
if (! fs.existsSync(folder)) {
|
|
93
|
+
lerr(`[cron][${cyan('IPsum')}] Folder ${folder} does not exist`)
|
|
94
|
+
return
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
try {
|
|
98
|
+
ldbg(`[cron][${cyan('IPsum')}] Updating file...`)
|
|
99
|
+
|
|
100
|
+
ipsum_download_file((content) => {
|
|
101
|
+
|
|
102
|
+
const local_path = path.join(folder, _IPSUM_FILE_NAME)
|
|
103
|
+
fs.writeFileSync(local_path, content, {encoding:'utf8', flag:'w'})
|
|
104
|
+
|
|
105
|
+
const ntot = content.split('\n').length
|
|
106
|
+
const ips = _ipsum_ips_from_content(content, logger)
|
|
107
|
+
const nfilt = ips.length
|
|
108
|
+
ldbg(`[cron][${cyan('IPsum')}] File downloaded. ${ntot} ips on the list (${nfilt} appearing in ${_IPSUM_NLISTS} or more lists)`)
|
|
109
|
+
|
|
110
|
+
if (callback) {
|
|
111
|
+
callback(ips)
|
|
112
|
+
}
|
|
113
|
+
})
|
|
114
|
+
|
|
115
|
+
} catch(error) {
|
|
116
|
+
lerr(`[cron][${cyan('IPsum')}] Error ${error} updating the file`)
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
export function ipsum_config() {
|
|
122
|
+
return {
|
|
123
|
+
name: 'IPsum',
|
|
124
|
+
cronTime: '0 0 * * *',
|
|
125
|
+
onTick: (miolo, _onCompleted) => {
|
|
126
|
+
const folder = miolo.config.http.ratelimit.ipsum_folder || _IPSUM_DEF_FOLDER
|
|
127
|
+
ipsum_update(folder, (ips) => {
|
|
128
|
+
miolo.logger.debug(`[cron][${cyan('IPsum')}] File downloaded. ${green(ips.length)} ips will be ${yellow('blacklisted')}!`)
|
|
129
|
+
}, miolo.logger)
|
|
130
|
+
},
|
|
131
|
+
start: true
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
export function ipsum_read_ips(folder = _IPSUM_DEF_FOLDER, callback, logger) {
|
|
136
|
+
const ldbg = logger ? logger.debug : console.log
|
|
137
|
+
const lwarn = logger ? logger.warn : console.log
|
|
138
|
+
|
|
139
|
+
const ips = _ipsum_ips_from_file(folder, logger)
|
|
140
|
+
if (ips.length > 0) {
|
|
141
|
+
if (callback) {
|
|
142
|
+
callback(ips)
|
|
143
|
+
}
|
|
144
|
+
ldbg(`[cron][${cyan('IPsum')}] File contains ${ips.length} ips`)
|
|
145
|
+
return ips
|
|
146
|
+
} else {
|
|
147
|
+
lwarn(`[cron][${cyan('IPsum')}] File is empty. Launching update...`)
|
|
148
|
+
ipsum_update(folder, callback, logger)
|
|
149
|
+
return []
|
|
150
|
+
}
|
|
151
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import os from 'os'
|
|
2
|
+
import diskspace from 'diskspace'
|
|
3
|
+
import { cyan, green, yellow } from 'tinguir'
|
|
4
|
+
|
|
5
|
+
function _toMB(bytes) {
|
|
6
|
+
if (!bytes) return 0
|
|
7
|
+
return bytes/1000000
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
function _toGB(kbytes) {
|
|
12
|
+
if (!kbytes) return 0
|
|
13
|
+
return kbytes/1000000
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
function _sys_check_and_log(logger) {
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
const used= Math.round(_toMB(os.freemem()), 2)
|
|
22
|
+
const total= Math.round(_toMB(os.totalmem()), 2)
|
|
23
|
+
const perc= Math.round( (used*100)/total, 2)
|
|
24
|
+
|
|
25
|
+
if (perc>80) {
|
|
26
|
+
logger.error(`[cron][${cyan('SysCheck')}] RAM ${yellow(used)} MB used of ${green(total)} MB (${yellow(perc)} %)`)
|
|
27
|
+
} else {
|
|
28
|
+
logger.info(`[cron][${cyan('SysCheck')}] RAM ${yellow(used)} MB used of ${green(total)} MB (${yellow(perc)} %)`)
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
diskspace.check('/', function (err, result)
|
|
33
|
+
{
|
|
34
|
+
const used = Math.round(_toGB(result.used), 2)
|
|
35
|
+
const total= Math.round(_toGB(result.total), 2)
|
|
36
|
+
const free = Math.round(_toGB(result.free), 2)
|
|
37
|
+
|
|
38
|
+
if (free<1) {
|
|
39
|
+
logger.error(`[cron][${cyan('SysCheck')}] DISK ${yellow(used)} GB used of ${green(total)} GB (${yellow(free)} GB free)`)
|
|
40
|
+
} else {
|
|
41
|
+
logger.info(`[cron][${cyan('SysCheck')}] DISK ${yellow(used)} GB used of ${green(total)} GB (${yellow(free)} GB free)`)
|
|
42
|
+
}
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
export function sys_check_config() {
|
|
48
|
+
return {
|
|
49
|
+
name: 'SysCheck',
|
|
50
|
+
cronTime: '0,15,30,45 * * * *',
|
|
51
|
+
onTick: (miolo, _onCompleted) => {
|
|
52
|
+
_sys_check_and_log(miolo.logger)
|
|
53
|
+
},
|
|
54
|
+
start: true
|
|
55
|
+
}
|
|
56
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { v4 as uuidv4 } from 'uuid'
|
|
2
|
+
|
|
3
|
+
export let EMAIL_QUEUE = {}
|
|
4
|
+
|
|
5
|
+
export async function email_queue_an_email(email, logger= undefined) {
|
|
6
|
+
const _loge = logger?.info || console.error
|
|
7
|
+
|
|
8
|
+
try {
|
|
9
|
+
const id = uuidv4()
|
|
10
|
+
const emailData = { id, ...email, sent: false }
|
|
11
|
+
//await client.rPush('email_queue', JSON.stringify(emailData))
|
|
12
|
+
EMAIL_QUEUE[id] = emailData
|
|
13
|
+
return { ok: true, id }
|
|
14
|
+
|
|
15
|
+
} catch (error) {
|
|
16
|
+
_loge(`[emailer] Error al guardar en la cola: ${error}`)
|
|
17
|
+
return { ok: false, id: null, error }
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function email_queue_pop_pendings(logger= undefined) {
|
|
22
|
+
|
|
23
|
+
let grouped = {}
|
|
24
|
+
|
|
25
|
+
Object.values(EMAIL_QUEUE)
|
|
26
|
+
.filter(e => !e.sent)
|
|
27
|
+
.forEach(({ id: eid, from, to, subject }) => {
|
|
28
|
+
const key = `${from}_${to}_${subject}`
|
|
29
|
+
|
|
30
|
+
if (!grouped[key]) {
|
|
31
|
+
grouped[key] = { to_subject_key: key, from, to, subject, count: 0, ids: [] }
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
grouped[key].count++
|
|
35
|
+
grouped[key].ids.push(eid)
|
|
36
|
+
|
|
37
|
+
// Mark as sent
|
|
38
|
+
try {
|
|
39
|
+
EMAIL_QUEUE[eid].sent= true
|
|
40
|
+
} catch(_) {}
|
|
41
|
+
})
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
return Object.values(grouped)
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export function email_queue_remove_ids(eids, logger= undefined) {
|
|
48
|
+
eids.forEach((eid) => {
|
|
49
|
+
|
|
50
|
+
delete EMAIL_QUEUE[eid]
|
|
51
|
+
})
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
import nodemailer from 'nodemailer'
|
|
2
|
+
import { email_queue_an_email, email_queue_pop_pendings, email_queue_remove_ids } from './queue.mjs'
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
const _logi = (logger, msg) => logger?.info ? logger.info(msg) : console.info(msg)
|
|
6
|
+
const _loge = (logger, msg) => logger?.error ? logger.info(msg) : console.error(msg)
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
export function _init_emailer_transporter({options, defaults, silent}) {
|
|
10
|
+
|
|
11
|
+
const nmailer = nodemailer.createTransport(options, defaults)
|
|
12
|
+
|
|
13
|
+
function verify_emailer(logger= undefined) {
|
|
14
|
+
_logi(logger, '[emailer] Verifying...')
|
|
15
|
+
nmailer.verify(function(error, _success) {
|
|
16
|
+
if (error) {
|
|
17
|
+
_loge(logger, '[emailer] Verifying ERROR')
|
|
18
|
+
_loge(error)
|
|
19
|
+
} else {
|
|
20
|
+
_logi(logger, '[emailer] Verifyed OK: Server is ready to take our messages')
|
|
21
|
+
}
|
|
22
|
+
})
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
async function send_email(mail, logger= undefined) {
|
|
26
|
+
if (silent === true) {
|
|
27
|
+
_logi(logger, '[emailer] *********************************')
|
|
28
|
+
_logi(logger, '[emailer] This mail will not be send (emailing is disabled):')
|
|
29
|
+
_logi(mail)
|
|
30
|
+
_logi(logger, '[emailer] *********************************')
|
|
31
|
+
|
|
32
|
+
return {
|
|
33
|
+
ok: true,
|
|
34
|
+
silent: true,
|
|
35
|
+
error: undefined,
|
|
36
|
+
messageId: undefined
|
|
37
|
+
}
|
|
38
|
+
} else {
|
|
39
|
+
try {
|
|
40
|
+
let info = await nmailer.sendMail(mail)
|
|
41
|
+
info.ok = info?.messageId ? true : false
|
|
42
|
+
|
|
43
|
+
return info
|
|
44
|
+
} catch(error) {
|
|
45
|
+
_loge(logger, `[emailer] Error sending email: ${mail?.from || ''} => ${mail?.to || ''} (${mail?.subject || ''})`)
|
|
46
|
+
|
|
47
|
+
return {
|
|
48
|
+
ok: false,
|
|
49
|
+
silent: false,
|
|
50
|
+
error,
|
|
51
|
+
messageId: undefined
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function queue_email(mail, logger= undefined) {
|
|
58
|
+
if (silent === true) {
|
|
59
|
+
_logi(logger, '[emailer] *********************************')
|
|
60
|
+
_logi(logger, '[emailer] This mail will not be send (emailing is disabled):')
|
|
61
|
+
_logi(mail)
|
|
62
|
+
_logi(logger, '[emailer] *********************************')
|
|
63
|
+
|
|
64
|
+
return {
|
|
65
|
+
ok: true,
|
|
66
|
+
silent: true,
|
|
67
|
+
error: undefined,
|
|
68
|
+
messageId: undefined
|
|
69
|
+
}
|
|
70
|
+
} else {
|
|
71
|
+
try {
|
|
72
|
+
const q = email_queue_an_email(mail, logger)
|
|
73
|
+
_logi(logger, `[emailer] Queued email: ${mail?.from || ''} => ${mail?.to || ''} (${mail?.subject || ''})`)
|
|
74
|
+
|
|
75
|
+
return {
|
|
76
|
+
ok: q.ok,
|
|
77
|
+
silent: false,
|
|
78
|
+
error: q.error,
|
|
79
|
+
messageId: q.id
|
|
80
|
+
}
|
|
81
|
+
} catch(error) {
|
|
82
|
+
_loge(logger, `[emailer] Error queueing email: ${mail?.from || ''} => ${mail?.to || ''} (${mail?.subject || ''})`)
|
|
83
|
+
|
|
84
|
+
return {
|
|
85
|
+
ok: false,
|
|
86
|
+
silent: false,
|
|
87
|
+
error,
|
|
88
|
+
messageId: undefined
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
async function queue_send_emails(logger= undefined) {
|
|
95
|
+
const pending = email_queue_pop_pendings(logger)
|
|
96
|
+
if (pending.length <= 0) {
|
|
97
|
+
return
|
|
98
|
+
}
|
|
99
|
+
_logi(logger, `[emailer] Sending emails queue (${pending.length} emails)`)
|
|
100
|
+
|
|
101
|
+
// const emailString = await client.lPop('email_queue')
|
|
102
|
+
// if (!emailString) break
|
|
103
|
+
// const email = JSON.parse(emailString)
|
|
104
|
+
|
|
105
|
+
for (const email of pending) {
|
|
106
|
+
if (email.count > 1) {
|
|
107
|
+
_logi(logger, `[emailer] Sending queued and stacked email [${email.subject}](x${email.count})...`)
|
|
108
|
+
email.subject = `${email.subject} (x${email.count})`
|
|
109
|
+
} else {
|
|
110
|
+
_logi(logger, `[emailer] Sending queued email [${email.subject}]...`)
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
send_email(email).then((res) => {
|
|
114
|
+
_logi(logger, `[emailer] Queued email [${email.subject}]sent ${res.ok ? 'OK' : 'NOT OK'}`)
|
|
115
|
+
if (res.ok) {
|
|
116
|
+
delete email_queue_remove_ids(email.ids, logger)
|
|
117
|
+
}
|
|
118
|
+
})
|
|
119
|
+
}
|
|
120
|
+
_logi(logger, `[emailer] Sent emails ${pending.length} from queue`)
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
const emailer= {
|
|
124
|
+
send: send_email,
|
|
125
|
+
verify: verify_emailer,
|
|
126
|
+
queue_email,
|
|
127
|
+
queue_send_emails,
|
|
128
|
+
options,
|
|
129
|
+
defaults,
|
|
130
|
+
silent
|
|
131
|
+
}
|
|
132
|
+
return emailer
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
let _cache = {}
|
|
138
|
+
|
|
139
|
+
export function init_emailer_transporter({options, defaults, silent}, logger= undefined) {
|
|
140
|
+
|
|
141
|
+
const ckey = JSON.stringify({options, defaults, silent})
|
|
142
|
+
if (ckey in _cache) {
|
|
143
|
+
return _cache[ckey]
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
_cache[ckey] = _init_emailer_transporter({options, defaults, silent}, logger)
|
|
147
|
+
return _cache[ckey]
|
|
148
|
+
|
|
149
|
+
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import fs from 'fs'
|
|
2
|
+
import {Reader} from '@maxmind/geoip2-node'
|
|
3
|
+
|
|
4
|
+
let _geoip_reader = undefined
|
|
5
|
+
|
|
6
|
+
const _geoip_def_local_ips= [
|
|
7
|
+
'127.0.0.1',
|
|
8
|
+
'::1:',
|
|
9
|
+
'172.19.0.1' // Docker inner - probably healthcheck
|
|
10
|
+
]
|
|
11
|
+
|
|
12
|
+
function _geoip_is_local(ip, local_ips = []) {
|
|
13
|
+
// if (process.env.NODE_ENV == 'development') {
|
|
14
|
+
// return true
|
|
15
|
+
// }
|
|
16
|
+
|
|
17
|
+
const all_local_ips = [
|
|
18
|
+
..._geoip_def_local_ips,
|
|
19
|
+
...local_ips || []
|
|
20
|
+
]
|
|
21
|
+
return all_local_ips.indexOf(ip) >= 0
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
function _geoip_init(db = '/var/lib/GeoIP/GeoLite2-City.mmdb', logger= console) {
|
|
27
|
+
try {
|
|
28
|
+
if (_geoip_reader != undefined) {
|
|
29
|
+
return _geoip_reader
|
|
30
|
+
}
|
|
31
|
+
const dbBuffer = fs.readFileSync(db)
|
|
32
|
+
_geoip_reader = Reader.openBuffer(dbBuffer)
|
|
33
|
+
return _geoip_reader
|
|
34
|
+
} catch(error) {
|
|
35
|
+
logger.error(`[geoip] Error initing:`)
|
|
36
|
+
logger.error(error)
|
|
37
|
+
return undefined
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export const geoip_localize_ip= (ip, config, logger= console) => {
|
|
42
|
+
if (_geoip_is_local(ip, config?.local_ips)) {
|
|
43
|
+
return {
|
|
44
|
+
local: true,
|
|
45
|
+
country: '',
|
|
46
|
+
city: '',
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
try {
|
|
51
|
+
const reader = _geoip_init(config?.db, logger)
|
|
52
|
+
const resp= reader.city(ip)
|
|
53
|
+
return {
|
|
54
|
+
country: resp.country.isoCode,
|
|
55
|
+
city : resp.city?.names?.en
|
|
56
|
+
}
|
|
57
|
+
} catch(error) {
|
|
58
|
+
logger.error(`[geoip] Error localizing IP ${ip} (not in the database)`)
|
|
59
|
+
//logger.error(error)
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
return {
|
|
63
|
+
country: '',
|
|
64
|
+
city: '',
|
|
65
|
+
}
|
|
66
|
+
}
|