@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.
@@ -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, contextifyValue, decontextifyValue, unproxyValue, 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
@@ -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
- 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)
121
144
  const functionsCode = `return {${functionNames.map(h => `"${h}": ${h}`).join(',')}}`
122
- const executionCode = `;(async () => { ${userCode}; ${functionsCode} })()
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
- const functionsCache = LRU({ max: 100 })
187
- function getTopLevelFunctions (code) {
209
+ function getTopLevelFunctions (cache, code) {
188
210
  const key = `functions:${code}`
189
211
 
190
- if (functionsCache.has(key)) {
191
- return functionsCache.get(key)
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
- functionsCache.set(key, names)
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.4.1",
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.0",
35
+ "@jsreport/advanced-workers": "1.2.2",
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.5",
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
- }