@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.
@@ -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
- if (req && req.context && req.context.user && !req.context.user.isAdmin) {
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
- if (req && req.context && req.context.user && !req.context.user.isAdmin) {
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
- if (req && req.context && req.context.user && !req.context.user.isAdmin) {
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: normalizedHelpers,
289
+ userCode: helpersStr,
268
290
  initFn,
269
291
  executionFn,
270
292
  currentPath: entityPath,
@@ -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