@jsreport/jsreport-core 3.11.4 → 4.0.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 +12 -0
- package/lib/main/optionsSchema.js +263 -270
- package/lib/main/reporter.js +12 -16
- package/lib/main/settings.js +14 -8
- package/lib/worker/render/executeEngine.js +23 -1
- package/lib/worker/reporter.js +45 -0
- package/lib/worker/sandbox/createSandbox.js +164 -709
- package/lib/worker/sandbox/isolatedRequire.js +442 -0
- package/lib/worker/sandbox/propertiesSandbox.js +521 -0
- package/lib/worker/sandbox/requireSandbox.js +117 -0
- package/lib/worker/sandbox/runInSandbox.js +270 -255
- package/package.json +7 -6
- package/test/extensions/validExtensions/listeners/main.js +62 -51
- package/test/extensions/validExtensions/listeners/worker.js +81 -68
- package/lib/main/migration/resourcesToAssets.js +0 -230
- package/lib/main/migration/xlsxTemplatesToAssets.js +0 -128
package/lib/main/settings.js
CHANGED
|
@@ -47,40 +47,46 @@ Settings.prototype.addOrSet = async function (key, avalue, req) {
|
|
|
47
47
|
}
|
|
48
48
|
}
|
|
49
49
|
|
|
50
|
-
Settings.prototype.init = async function (documentStore, authorization) {
|
|
50
|
+
Settings.prototype.init = async function (documentStore, { authentication, authorization }) {
|
|
51
51
|
this.documentStore = documentStore
|
|
52
52
|
|
|
53
|
-
if (authorization != null) {
|
|
53
|
+
if (authentication != null && authorization != null) {
|
|
54
54
|
const col = documentStore.collection('settings')
|
|
55
55
|
|
|
56
56
|
// settings can be read by anyone so we don't add find listeners,
|
|
57
57
|
// we only care about modification listeners
|
|
58
|
-
col.beforeInsertListeners.add('settings', (doc, req) => {
|
|
58
|
+
col.beforeInsertListeners.add('settings', async (doc, req) => {
|
|
59
59
|
if (req && req.context && req.context.skipAuthorization) {
|
|
60
60
|
return
|
|
61
61
|
}
|
|
62
62
|
|
|
63
|
-
|
|
63
|
+
const isAdmin = await authentication.isUserAdmin(req?.context?.user, req)
|
|
64
|
+
|
|
65
|
+
if (req && req.context && req.context.user && !isAdmin) {
|
|
64
66
|
throw authorization.createAuthorizationError(col.name)
|
|
65
67
|
}
|
|
66
68
|
})
|
|
67
69
|
|
|
68
|
-
col.beforeUpdateListeners.add('settings', (q, u, options, req) => {
|
|
70
|
+
col.beforeUpdateListeners.add('settings', async (q, u, options, req) => {
|
|
69
71
|
if (req && req.context && req.context.skipAuthorization) {
|
|
70
72
|
return
|
|
71
73
|
}
|
|
72
74
|
|
|
73
|
-
|
|
75
|
+
const isAdmin = await authentication.isUserAdmin(req?.context?.user, req)
|
|
76
|
+
|
|
77
|
+
if (req && req.context && req.context.user && !isAdmin) {
|
|
74
78
|
throw authorization.createAuthorizationError(col.name)
|
|
75
79
|
}
|
|
76
80
|
})
|
|
77
81
|
|
|
78
|
-
col.beforeRemoveListeners.add('settings', (q, req) => {
|
|
82
|
+
col.beforeRemoveListeners.add('settings', async (q, req) => {
|
|
79
83
|
if (req && req.context && req.context.skipAuthorization) {
|
|
80
84
|
return
|
|
81
85
|
}
|
|
82
86
|
|
|
83
|
-
|
|
87
|
+
const isAdmin = await authentication.isUserAdmin(req?.context?.user, req)
|
|
88
|
+
|
|
89
|
+
if (req && req.context && req.context.user && !isAdmin) {
|
|
84
90
|
throw authorization.createAuthorizationError(col.name)
|
|
85
91
|
}
|
|
86
92
|
})
|
|
@@ -140,6 +140,10 @@ module.exports = (reporter) => {
|
|
|
140
140
|
const executionFnParsedParamsKey = `entity:${entity.shortid || 'anonymous'}:helpers:${normalizedHelpers}`
|
|
141
141
|
|
|
142
142
|
const initFn = async (getTopLevelFunctions, compileScript) => {
|
|
143
|
+
if (reporter.options.trustUserCode === false) {
|
|
144
|
+
return null
|
|
145
|
+
}
|
|
146
|
+
|
|
143
147
|
if (systemHelpersCache != null) {
|
|
144
148
|
return systemHelpersCache
|
|
145
149
|
}
|
|
@@ -259,12 +263,30 @@ module.exports = (reporter) => {
|
|
|
259
263
|
templatesCache.reset()
|
|
260
264
|
}
|
|
261
265
|
|
|
266
|
+
let helpersStr = normalizedHelpers
|
|
267
|
+
if (reporter.options.trustUserCode === false) {
|
|
268
|
+
const registerResults = await reporter.registerHelpersListeners.fire()
|
|
269
|
+
const systemHelpers = []
|
|
270
|
+
|
|
271
|
+
for (const result of registerResults) {
|
|
272
|
+
if (result == null) {
|
|
273
|
+
continue
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
if (typeof result === 'string') {
|
|
277
|
+
systemHelpers.push(result)
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
const systemHelpersStr = systemHelpers.join('\n')
|
|
281
|
+
helpersStr = normalizedHelpers + '\n' + systemHelpersStr
|
|
282
|
+
}
|
|
283
|
+
|
|
262
284
|
try {
|
|
263
285
|
return await reporter.runInSandbox({
|
|
264
286
|
context: {
|
|
265
287
|
...(engine.createContext ? engine.createContext(req) : {})
|
|
266
288
|
},
|
|
267
|
-
userCode:
|
|
289
|
+
userCode: helpersStr,
|
|
268
290
|
initFn,
|
|
269
291
|
executionFn,
|
|
270
292
|
currentPath: entityPath,
|
package/lib/worker/reporter.js
CHANGED
|
@@ -19,6 +19,7 @@ class WorkerReporter extends Reporter {
|
|
|
19
19
|
|
|
20
20
|
this._executeMain = executeMain
|
|
21
21
|
this._initialized = false
|
|
22
|
+
this._lockedDown = false
|
|
22
23
|
this._documentStoreData = documentStore
|
|
23
24
|
this._requestContextMetaConfigCollection = new Map()
|
|
24
25
|
this._proxyRegistrationFns = []
|
|
@@ -80,6 +81,50 @@ class WorkerReporter extends Reporter {
|
|
|
80
81
|
|
|
81
82
|
await this.initializeListeners.fire()
|
|
82
83
|
|
|
84
|
+
if (!this._lockedDown && this.options.trustUserCode === false) {
|
|
85
|
+
require('@jsreport/ses')
|
|
86
|
+
|
|
87
|
+
// eslint-disable-next-line
|
|
88
|
+
lockdown({
|
|
89
|
+
// don't change locale based methods which users may be using in their templates
|
|
90
|
+
localeTaming: 'unsafe',
|
|
91
|
+
errorTaming: 'unsafe',
|
|
92
|
+
stackFiltering: 'verbose',
|
|
93
|
+
/*
|
|
94
|
+
FROM SES DOCS
|
|
95
|
+
The 'severe' setting enables all the properties on at least Object.prototype, which is sometimes needed for compatibility with code generated by rollup or webpack.
|
|
96
|
+
However, this extra compatibility comes at the price of a miserable debugging experience.
|
|
97
|
+
|
|
98
|
+
We need this to make jsrender working, which overrides constructor.
|
|
99
|
+
In case we need to put back default, we will need to fork jsrender and change the following line
|
|
100
|
+
(Tag.prototype = compiledDef).constructor = compiledDef._ctr = Tag;
|
|
101
|
+
x
|
|
102
|
+
Tag.prototype = compiledDef
|
|
103
|
+
compiledDef._ctr = Tag
|
|
104
|
+
*/
|
|
105
|
+
overrideTaming: 'severe'
|
|
106
|
+
})
|
|
107
|
+
|
|
108
|
+
// in this mode we alias the unsafe methods to safe ones
|
|
109
|
+
Buffer.allocUnsafe = function allocUnsafe (size) {
|
|
110
|
+
return Buffer.alloc(size)
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
Buffer.allocUnsafeSlow = function allocUnsafeSlow (size) {
|
|
114
|
+
return Buffer.alloc(size)
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// we also harden Buffer because we expose it to sandbox
|
|
118
|
+
// eslint-disable-next-line
|
|
119
|
+
harden(Buffer)
|
|
120
|
+
|
|
121
|
+
// we need to expose Intl to sandbox
|
|
122
|
+
// eslint-disable-next-line
|
|
123
|
+
harden(Intl)
|
|
124
|
+
|
|
125
|
+
this._lockedDown = true
|
|
126
|
+
}
|
|
127
|
+
|
|
83
128
|
this._initialized = true
|
|
84
129
|
}
|
|
85
130
|
|