@jsreport/jsreport-core 3.4.1 → 3.6.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/README.md +14 -1
- package/lib/main/blobStorage/blobStorage.js +8 -0
- package/lib/main/logger.js +3 -0
- package/lib/main/optionsLoad.js +10 -2
- package/lib/main/optionsSchema.js +21 -3
- package/lib/main/profiler.js +166 -75
- package/lib/main/reporter.js +113 -78
- package/lib/main/schemaValidator.js +30 -0
- package/lib/main/settings.js +1 -2
- package/lib/main/store/collection.js +10 -8
- package/lib/main/store/documentStore.js +19 -0
- package/lib/main/store/setupValidateId.js +7 -1
- package/lib/main/store/setupValidateShortid.js +4 -0
- package/lib/shared/normalizeMetaFromLogs.js +1 -1
- package/lib/shared/reporter.js +16 -0
- package/lib/worker/render/executeEngine.js +108 -27
- package/lib/worker/render/moduleHelper.js +4 -4
- package/lib/worker/render/profiler.js +20 -13
- package/lib/worker/render/render.js +0 -4
- package/lib/worker/reporter.js +6 -4
- package/lib/worker/sandbox/{safeSandbox.js → createSandbox.js} +85 -52
- package/lib/worker/sandbox/runInSandbox.js +38 -16
- package/package.json +9 -9
- package/lib/main/monitoring.js +0 -92
|
@@ -1,14 +1,17 @@
|
|
|
1
1
|
const LRU = require('lru-cache')
|
|
2
2
|
const stackTrace = require('stack-trace')
|
|
3
3
|
const { customAlphabet } = require('nanoid')
|
|
4
|
-
const
|
|
4
|
+
const createSandbox = require('./createSandbox')
|
|
5
5
|
const nanoid = customAlphabet('abcdefghijklmnopqrstuvwxyz', 10)
|
|
6
6
|
|
|
7
7
|
module.exports = (reporter) => {
|
|
8
|
-
|
|
8
|
+
const functionsCache = LRU(reporter.options.sandbox.cache)
|
|
9
|
+
|
|
10
|
+
return async ({
|
|
9
11
|
manager = {},
|
|
10
12
|
context,
|
|
11
13
|
userCode,
|
|
14
|
+
initFn,
|
|
12
15
|
executionFn,
|
|
13
16
|
currentPath,
|
|
14
17
|
onRequire,
|
|
@@ -19,7 +22,8 @@ module.exports = (reporter) => {
|
|
|
19
22
|
|
|
20
23
|
// we use dynamic name because of the potential nested vm2 execution in the jsreportProxy.assets.require
|
|
21
24
|
// it may turn out it is a bad approach in assets so we gonna delete it here
|
|
22
|
-
const executionFnName = nanoid()
|
|
25
|
+
const executionFnName = `${nanoid()}_executionFn`
|
|
26
|
+
|
|
23
27
|
context[executionFnName] = executionFn
|
|
24
28
|
context.__appDirectory = reporter.options.appDirectory
|
|
25
29
|
context.__rootDirectory = reporter.options.rootDirectory
|
|
@@ -28,13 +32,14 @@ module.exports = (reporter) => {
|
|
|
28
32
|
context.__topLevelFunctions = {}
|
|
29
33
|
context.__handleError = (err) => handleError(reporter, err)
|
|
30
34
|
|
|
31
|
-
const { sourceFilesInfo, run,
|
|
35
|
+
const { sourceFilesInfo, run, compileScript, restore, sandbox, sandboxRequire } = createSandbox(context, {
|
|
32
36
|
onLog: (log) => {
|
|
33
37
|
reporter.logger[log.level](log.message, { ...req, timestamp: log.timestamp })
|
|
34
38
|
},
|
|
35
39
|
formatError: (error, moduleName) => {
|
|
36
|
-
error.message += ` To be able to require custom modules you need to add to configuration { "
|
|
40
|
+
error.message += ` To be able to require custom modules you need to add to configuration { "trustUserCode": true } or enable just specific module using { sandbox: { allowedModules": ["${moduleName}"] }`
|
|
37
41
|
},
|
|
42
|
+
safeExecution: reporter.options.trustUserCode === false,
|
|
38
43
|
modulesCache: reporter.requestModulesCache.get(req.context.rootId),
|
|
39
44
|
globalModules: reporter.options.sandbox.nativeModules || [],
|
|
40
45
|
allowedModules: reporter.options.sandbox.allowedModules,
|
|
@@ -61,7 +66,17 @@ module.exports = (reporter) => {
|
|
|
61
66
|
}
|
|
62
67
|
})
|
|
63
68
|
|
|
64
|
-
|
|
69
|
+
const _getTopLevelFunctions = (code) => {
|
|
70
|
+
return getTopLevelFunctions(functionsCache, code)
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
jsreportProxy = reporter.createProxy({
|
|
74
|
+
req,
|
|
75
|
+
runInSandbox: run,
|
|
76
|
+
context: sandbox,
|
|
77
|
+
getTopLevelFunctions: _getTopLevelFunctions,
|
|
78
|
+
sandboxRequire
|
|
79
|
+
})
|
|
65
80
|
|
|
66
81
|
jsreportProxy.currentPath = async () => {
|
|
67
82
|
// we get the current path by throwing an error, which give us a stack trace
|
|
@@ -113,13 +128,21 @@ module.exports = (reporter) => {
|
|
|
113
128
|
// we don't attach these methods to the sandbox, and instead share them through a "manager" object that should
|
|
114
129
|
// be passed in options
|
|
115
130
|
manager.restore = restore
|
|
116
|
-
manager.contextifyValue = contextifyValue
|
|
117
|
-
manager.decontextifyValue = decontextifyValue
|
|
118
|
-
manager.unproxyValue = unproxyValue
|
|
119
131
|
|
|
120
|
-
|
|
132
|
+
if (typeof initFn === 'function') {
|
|
133
|
+
const initScriptInfo = await initFn(_getTopLevelFunctions, compileScript)
|
|
134
|
+
|
|
135
|
+
if (initScriptInfo) {
|
|
136
|
+
await run(initScriptInfo.script, {
|
|
137
|
+
filename: initScriptInfo.filename || 'sandbox-init.js',
|
|
138
|
+
source: initScriptInfo.source
|
|
139
|
+
})
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
const functionNames = getTopLevelFunctions(functionsCache, userCode)
|
|
121
144
|
const functionsCode = `return {${functionNames.map(h => `"${h}": ${h}`).join(',')}}`
|
|
122
|
-
const executionCode = `;(async () => { ${userCode}
|
|
145
|
+
const executionCode = `;(async () => { ${userCode} \n\n;${functionsCode} })()
|
|
123
146
|
.then((topLevelFunctions) => {
|
|
124
147
|
const mergedTopLevelFunctions = { ...topLevelFunctions, ...__topLevelFunctions }
|
|
125
148
|
|
|
@@ -183,12 +206,11 @@ function handleError (reporter, errValue) {
|
|
|
183
206
|
})
|
|
184
207
|
}
|
|
185
208
|
|
|
186
|
-
|
|
187
|
-
function getTopLevelFunctions (code) {
|
|
209
|
+
function getTopLevelFunctions (cache, code) {
|
|
188
210
|
const key = `functions:${code}`
|
|
189
211
|
|
|
190
|
-
if (
|
|
191
|
-
return
|
|
212
|
+
if (cache.has(key)) {
|
|
213
|
+
return cache.get(key)
|
|
192
214
|
}
|
|
193
215
|
|
|
194
216
|
// lazy load to speed up boot
|
|
@@ -226,6 +248,6 @@ function getTopLevelFunctions (code) {
|
|
|
226
248
|
return []
|
|
227
249
|
}
|
|
228
250
|
|
|
229
|
-
|
|
251
|
+
cache.set(key, names)
|
|
230
252
|
return names
|
|
231
253
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jsreport/jsreport-core",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.6.0",
|
|
4
4
|
"description": "javascript based business reporting",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"report",
|
|
@@ -32,11 +32,11 @@
|
|
|
32
32
|
"@babel/code-frame": "7.12.13",
|
|
33
33
|
"@babel/parser": "7.14.4",
|
|
34
34
|
"@babel/traverse": "7.12.9",
|
|
35
|
-
"@jsreport/advanced-workers": "1.2.
|
|
35
|
+
"@jsreport/advanced-workers": "1.2.2",
|
|
36
36
|
"@jsreport/mingo": "2.4.1",
|
|
37
37
|
"ajv": "6.12.6",
|
|
38
|
-
"app-root-path": "
|
|
39
|
-
"
|
|
38
|
+
"app-root-path": "3.0.0",
|
|
39
|
+
"bytes": "3.1.2",
|
|
40
40
|
"camelcase": "5.0.0",
|
|
41
41
|
"debug": "4.3.2",
|
|
42
42
|
"decamelize": "2.0.0",
|
|
@@ -46,7 +46,7 @@
|
|
|
46
46
|
"enhanced-resolve": "5.8.3",
|
|
47
47
|
"has-own-deep": "1.1.0",
|
|
48
48
|
"isbinaryfile": "4.0.0",
|
|
49
|
-
"listener-collection": "
|
|
49
|
+
"listener-collection": "2.0.0",
|
|
50
50
|
"lodash.get": "4.4.2",
|
|
51
51
|
"lodash.groupby": "4.6.0",
|
|
52
52
|
"lodash.omit": "4.5.0",
|
|
@@ -54,21 +54,21 @@
|
|
|
54
54
|
"lru-cache": "4.1.1",
|
|
55
55
|
"ms": "2.1.3",
|
|
56
56
|
"nanoid": "3.2.0",
|
|
57
|
-
"nconf": "0.
|
|
57
|
+
"nconf": "0.12.0",
|
|
58
58
|
"node.extend.without.arrays": "1.1.6",
|
|
59
|
-
"
|
|
59
|
+
"@jsreport/reap": "0.1.0",
|
|
60
60
|
"semver": "7.3.5",
|
|
61
61
|
"serializator": "1.0.2",
|
|
62
62
|
"stack-trace": "0.0.10",
|
|
63
63
|
"triple-beam": "1.3.0",
|
|
64
64
|
"unset-value": "1.0.0",
|
|
65
65
|
"uuid": "8.3.2",
|
|
66
|
-
"vm2": "3.9.
|
|
66
|
+
"vm2": "3.9.9",
|
|
67
67
|
"winston": "3.3.3",
|
|
68
68
|
"winston-transport": "4.4.0"
|
|
69
69
|
},
|
|
70
70
|
"devDependencies": {
|
|
71
|
-
"mocha": "
|
|
71
|
+
"mocha": "9.2.2",
|
|
72
72
|
"should": "13.2.3",
|
|
73
73
|
"standard": "16.0.4",
|
|
74
74
|
"std-mocks": "1.0.1",
|
package/lib/main/monitoring.js
DELETED
|
@@ -1,92 +0,0 @@
|
|
|
1
|
-
const os = require('os')
|
|
2
|
-
|
|
3
|
-
function cpu () {
|
|
4
|
-
// Create function to get CPU information
|
|
5
|
-
function cpuAverage () {
|
|
6
|
-
// Initialise sum of idle and time of cores and fetch CPU info
|
|
7
|
-
let totalIdle = 0; let totalTick = 0
|
|
8
|
-
const cpus = os.cpus()
|
|
9
|
-
|
|
10
|
-
// Loop through CPU cores
|
|
11
|
-
for (let i = 0, len = cpus.length; i < len; i++) {
|
|
12
|
-
// Select CPU core
|
|
13
|
-
const cpu = cpus[i]
|
|
14
|
-
|
|
15
|
-
// Total up the time in the cores tick
|
|
16
|
-
for (const type in cpu.times) {
|
|
17
|
-
totalTick += cpu.times[type]
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
// Total up the idle time of the core
|
|
21
|
-
totalIdle += cpu.times.idle
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
// Return the average Idle and Tick times
|
|
25
|
-
return { idle: totalIdle / cpus.length, total: totalTick / cpus.length }
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
// Grab first CPU Measure
|
|
29
|
-
const startMeasure = cpuAverage()
|
|
30
|
-
|
|
31
|
-
return new Promise((resolve) => {
|
|
32
|
-
// Set delay for second Measure
|
|
33
|
-
setTimeout(function () {
|
|
34
|
-
// Grab second Measure
|
|
35
|
-
const endMeasure = cpuAverage()
|
|
36
|
-
|
|
37
|
-
// Calculate the difference in idle and total time between the measures
|
|
38
|
-
const idleDifference = endMeasure.idle - startMeasure.idle
|
|
39
|
-
const totalDifference = endMeasure.total - startMeasure.total
|
|
40
|
-
|
|
41
|
-
// Calculate the average percentage CPU usage
|
|
42
|
-
const percentageCPU = 100 - ~~(100 * idleDifference / totalDifference)
|
|
43
|
-
|
|
44
|
-
// Output result to console
|
|
45
|
-
resolve(percentageCPU)
|
|
46
|
-
}, 1000)
|
|
47
|
-
})
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
class Monitoring {
|
|
51
|
-
constructor (reporter) {
|
|
52
|
-
this.reporter = reporter
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
async execute () {
|
|
56
|
-
const monitoring = {
|
|
57
|
-
cpu: await cpu(),
|
|
58
|
-
freemem: Math.round(os.freemem() / 1024 / 1024),
|
|
59
|
-
timestamp: new Date(),
|
|
60
|
-
hostname: os.hostname()
|
|
61
|
-
}
|
|
62
|
-
return this.reporter.documentStore.collection('monitoring').insert(monitoring)
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
init () {
|
|
66
|
-
this._interval = setInterval(() => {
|
|
67
|
-
this.execute().catch((e) => this.reporter.logger.warn('unable to persist monitoring info, but no need to worry, we will retry, details:' + e.stack))
|
|
68
|
-
}, 60000)
|
|
69
|
-
this._interval.unref()
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
close () {
|
|
73
|
-
clearInterval(this._interval)
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
module.exports = (reporter) => {
|
|
78
|
-
reporter.documentStore.registerEntityType('MonitoringType', {
|
|
79
|
-
cpu: { type: 'Edm.Int32' },
|
|
80
|
-
freemem: { type: 'Edm.Int32' },
|
|
81
|
-
timestamp: { type: 'Edm.DateTimeOffset', schema: { type: 'null' } },
|
|
82
|
-
hostname: { type: 'Edm.String' }
|
|
83
|
-
})
|
|
84
|
-
|
|
85
|
-
reporter.documentStore.registerEntitySet('monitoring', {
|
|
86
|
-
entityType: 'jsreport.MonitoringType',
|
|
87
|
-
exportable: false,
|
|
88
|
-
shared: true
|
|
89
|
-
})
|
|
90
|
-
|
|
91
|
-
reporter.monitoring = new Monitoring(reporter)
|
|
92
|
-
}
|