@jsreport/jsreport-core 3.4.2 → 3.6.1

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.
@@ -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 safeSandbox = require('./safeSandbox')
4
+ const createSandbox = require('./createSandbox')
5
5
  const nanoid = customAlphabet('abcdefghijklmnopqrstuvwxyz', 10)
6
6
 
7
7
  module.exports = (reporter) => {
8
- return ({
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() + '_executionFn'
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, restore, sandbox, safeRequire } = safeSandbox(context, {
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 { "allowLocalFilesAccess": true } or enable just specific module using { sandbox: { allowedModules": ["${moduleName}"] }`
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
- jsreportProxy = reporter.createProxy({ req, runInSandbox: run, context: sandbox, getTopLevelFunctions, safeRequire })
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
@@ -114,9 +129,20 @@ module.exports = (reporter) => {
114
129
  // be passed in options
115
130
  manager.restore = restore
116
131
 
117
- const functionNames = getTopLevelFunctions(userCode)
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)
118
144
  const functionsCode = `return {${functionNames.map(h => `"${h}": ${h}`).join(',')}}`
119
- const executionCode = `;(async () => { ${userCode}; ${functionsCode} })()
145
+ const executionCode = `;(async () => { ${userCode} \n\n;${functionsCode} })()
120
146
  .then((topLevelFunctions) => {
121
147
  const mergedTopLevelFunctions = { ...topLevelFunctions, ...__topLevelFunctions }
122
148
 
@@ -180,12 +206,11 @@ function handleError (reporter, errValue) {
180
206
  })
181
207
  }
182
208
 
183
- const functionsCache = LRU({ max: 100 })
184
- function getTopLevelFunctions (code) {
209
+ function getTopLevelFunctions (cache, code) {
185
210
  const key = `functions:${code}`
186
211
 
187
- if (functionsCache.has(key)) {
188
- return functionsCache.get(key)
212
+ if (cache.has(key)) {
213
+ return cache.get(key)
189
214
  }
190
215
 
191
216
  // lazy load to speed up boot
@@ -223,6 +248,6 @@ function getTopLevelFunctions (code) {
223
248
  return []
224
249
  }
225
250
 
226
- functionsCache.set(key, names)
251
+ cache.set(key, names)
227
252
  return names
228
253
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jsreport/jsreport-core",
3
- "version": "3.4.2",
3
+ "version": "3.6.1",
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.0",
35
+ "@jsreport/advanced-workers": "1.2.3",
36
36
  "@jsreport/mingo": "2.4.1",
37
37
  "ajv": "6.12.6",
38
- "app-root-path": "2.0.1",
39
- "async-replace": "1.0.1",
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": "1.2.0",
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.11.3",
57
+ "nconf": "0.12.0",
58
58
  "node.extend.without.arrays": "1.1.6",
59
- "reap2": "1.0.1",
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.7",
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": "8.2.1",
71
+ "mocha": "9.2.2",
72
72
  "should": "13.2.3",
73
73
  "standard": "16.0.4",
74
74
  "std-mocks": "1.0.1",
@@ -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
- }