@sap/cds 6.8.4 → 7.0.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.
Files changed (217) hide show
  1. package/CHANGELOG.md +66 -4
  2. package/README.md +0 -1
  3. package/bin/cds-serve.js +50 -3
  4. package/bin/deploy/to-hana.js +1 -0
  5. package/bin/serve.js +16 -20
  6. package/lib/auth/basic-auth.js +6 -4
  7. package/lib/auth/index.js +4 -3
  8. package/lib/auth/jwt-auth.js +2 -5
  9. package/lib/compile/cds-compile.js +34 -89
  10. package/lib/compile/cdsc.js +11 -0
  11. package/lib/compile/etc/properties.js +2 -2
  12. package/lib/compile/for/lean_drafts.js +36 -69
  13. package/lib/compile/for/nodejs.js +2 -1
  14. package/lib/compile/load.js +3 -3
  15. package/lib/compile/minify.js +2 -0
  16. package/lib/compile/to/csn.js +74 -0
  17. package/{bin/build/provider/hana/2tabledata.js → lib/compile/to/hdbtabledata.js} +4 -6
  18. package/lib/compile/to/json.js +1 -1
  19. package/lib/compile/to/sql.js +8 -6
  20. package/lib/dbs/cds-deploy.js +174 -114
  21. package/lib/env/cds-env.js +64 -79
  22. package/lib/env/cds-requires.js +11 -28
  23. package/lib/env/defaults.js +13 -3
  24. package/lib/env/plugins.js +1 -12
  25. package/lib/env/presets.js +25 -21
  26. package/lib/index.js +121 -147
  27. package/lib/{core/reflect.js → linked/models.js} +2 -2
  28. package/lib/{core/infer.js → linked/queries.js} +2 -0
  29. package/lib/{core/index.js → linked/types.js} +2 -1
  30. package/lib/log/cds-error.js +13 -7
  31. package/lib/log/format/cf.js +1 -1
  32. package/lib/plugins.js +49 -0
  33. package/lib/ql/Query.js +0 -9
  34. package/lib/ql/STREAM.js +0 -1
  35. package/lib/req/context.js +2 -7
  36. package/lib/req/request.js +6 -2
  37. package/lib/req/response.js +23 -10
  38. package/lib/srv/middlewares/ctx-model.js +2 -2
  39. package/lib/srv/middlewares/errors.js +1 -1
  40. package/lib/srv/protocols/_legacy.js +1 -0
  41. package/lib/srv/protocols/graphql.js +7 -16
  42. package/lib/srv/protocols/index.js +59 -45
  43. package/lib/srv/protocols/odata-v2-proxy.js +2 -70
  44. package/lib/srv/protocols/odata-v4.js +9 -4
  45. package/lib/srv/srv-api.js +9 -3
  46. package/lib/srv/srv-dispatch.js +12 -9
  47. package/lib/srv/srv-models.js +4 -21
  48. package/lib/srv/srv-tx.js +15 -12
  49. package/lib/utils/cds-test.js +14 -9
  50. package/lib/utils/cds-utils.js +2 -12
  51. package/lib/utils/check-version.js +17 -0
  52. package/{bin/build → lib/utils}/csv-reader.js +23 -24
  53. package/libx/_runtime/auth/index.js +27 -23
  54. package/libx/_runtime/cds-services/adapter/odata-v4/ODataRequest.js +15 -72
  55. package/libx/_runtime/cds-services/adapter/odata-v4/handlers/create.js +1 -1
  56. package/libx/_runtime/cds-services/adapter/odata-v4/handlers/metadata.js +0 -2
  57. package/libx/_runtime/cds-services/adapter/odata-v4/handlers/read.js +33 -63
  58. package/libx/_runtime/cds-services/adapter/odata-v4/handlers/request.js +14 -18
  59. package/libx/_runtime/cds-services/adapter/odata-v4/handlers/update.js +15 -5
  60. package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/ExpressionToCQN.js +5 -4
  61. package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/readToCQN.js +37 -40
  62. package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/updateToCQN.js +7 -1
  63. package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/utils.js +101 -38
  64. package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-commons/errors/AbstractError.js +5 -1
  65. package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-commons/uri/UriTokenizer.js +5 -8
  66. package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-commons/utils/ValueConverter.js +2 -1
  67. package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-server/deserializer/ResourceJsonDeserializer.js +9 -8
  68. package/libx/_runtime/cds-services/adapter/odata-v4/to.js +1 -1
  69. package/libx/_runtime/cds-services/adapter/odata-v4/utils/data.js +15 -11
  70. package/libx/_runtime/cds-services/adapter/odata-v4/utils/readAfterWrite.js +4 -0
  71. package/libx/_runtime/cds-services/adapter/odata-v4/utils/result.js +5 -2
  72. package/libx/_runtime/cds-services/adapter/odata-v4/utils/stream.js +1 -123
  73. package/libx/_runtime/cds-services/services/Service.js +79 -107
  74. package/libx/_runtime/cds-services/services/utils/columns.js +23 -19
  75. package/libx/_runtime/cds-services/services/utils/compareJson.js +11 -1
  76. package/libx/_runtime/cds-services/services/utils/differ.js +7 -2
  77. package/libx/_runtime/cds-services/util/assert.js +65 -2
  78. package/libx/_runtime/common/composition/data.js +1 -0
  79. package/libx/_runtime/common/generic/auth/expand.js +1 -1
  80. package/libx/_runtime/common/generic/auth/restrict.js +5 -10
  81. package/libx/_runtime/common/generic/auth/restrictions.js +40 -0
  82. package/libx/_runtime/common/generic/auth/utils.js +1 -2
  83. package/libx/_runtime/common/generic/crud.js +32 -16
  84. package/libx/_runtime/common/generic/etag.js +133 -104
  85. package/libx/_runtime/common/generic/input.js +6 -21
  86. package/libx/_runtime/common/generic/put.js +1 -1
  87. package/libx/_runtime/common/generic/stream.js +52 -0
  88. package/libx/_runtime/common/generic/temporal.js +25 -8
  89. package/libx/_runtime/common/i18n/messages.properties +0 -2
  90. package/libx/_runtime/common/utils/cqn.js +1 -1
  91. package/libx/_runtime/common/utils/cqn2cqn4sql.js +5 -2
  92. package/libx/_runtime/common/utils/csn.js +0 -51
  93. package/libx/_runtime/common/utils/etag.js +30 -0
  94. package/libx/_runtime/common/utils/keys.js +1 -1
  95. package/libx/_runtime/common/utils/normalizeTimestamp.js +25 -0
  96. package/libx/_runtime/common/utils/path.js +1 -1
  97. package/libx/_runtime/common/utils/resolveView.js +2 -1
  98. package/libx/_runtime/common/utils/rewriteAsterisks.js +6 -4
  99. package/libx/_runtime/common/utils/search2cqn4sql.js +12 -16
  100. package/libx/_runtime/common/utils/stream.js +140 -0
  101. package/libx/_runtime/common/utils/streamProp.js +29 -12
  102. package/libx/_runtime/common/utils/templateProcessorPathSerializer.js +0 -2
  103. package/libx/_runtime/db/generic/index.js +0 -2
  104. package/libx/_runtime/db/query/delete.js +2 -2
  105. package/libx/_runtime/db/query/insert.js +2 -2
  106. package/libx/_runtime/db/query/read.js +2 -2
  107. package/libx/_runtime/db/query/run.js +2 -2
  108. package/libx/_runtime/db/query/update.js +2 -2
  109. package/libx/_runtime/db/sql-builder/BaseBuilder.js +0 -6
  110. package/libx/_runtime/db/sql-builder/ExpressionBuilder.js +23 -12
  111. package/libx/_runtime/db/sql-builder/FunctionBuilder.js +18 -6
  112. package/libx/_runtime/db/sql-builder/InsertBuilder.js +1 -0
  113. package/libx/_runtime/db/sql-builder/SelectBuilder.js +3 -7
  114. package/libx/_runtime/db/sql-builder/UpsertBuilder.js +1 -0
  115. package/libx/_runtime/db/utils/normalizeTimeData.js +7 -3
  116. package/libx/_runtime/fiori/draft.js +2 -0
  117. package/libx/_runtime/fiori/generic/activate.js +8 -9
  118. package/libx/_runtime/fiori/generic/before.js +30 -20
  119. package/libx/_runtime/fiori/generic/cancel.js +5 -3
  120. package/libx/_runtime/fiori/generic/delete.js +5 -3
  121. package/libx/_runtime/fiori/generic/edit.js +7 -7
  122. package/libx/_runtime/fiori/generic/index.js +10 -16
  123. package/libx/_runtime/fiori/generic/new.js +5 -3
  124. package/libx/_runtime/fiori/generic/patch.js +11 -8
  125. package/libx/_runtime/fiori/generic/prepare.js +13 -6
  126. package/libx/_runtime/fiori/generic/read.js +12 -6
  127. package/libx/_runtime/fiori/lean-draft.js +207 -152
  128. package/libx/_runtime/fiori/utils/delete.js +10 -5
  129. package/libx/_runtime/fiori/utils/req.js +17 -5
  130. package/libx/_runtime/fiori/utils/stream.js +36 -0
  131. package/libx/_runtime/hana/Service.js +12 -9
  132. package/libx/_runtime/hana/conversion.js +10 -15
  133. package/libx/_runtime/hana/driver.js +2 -0
  134. package/libx/_runtime/hana/execute.js +28 -6
  135. package/libx/_runtime/hana/pool.js +36 -122
  136. package/libx/_runtime/hana/search2cqn4sql.js +34 -36
  137. package/libx/_runtime/messaging/enterprise-messaging-utils/getTenantInfo.js +2 -6
  138. package/libx/_runtime/messaging/enterprise-messaging-utils/registerEndpoints.js +3 -1
  139. package/libx/_runtime/messaging/enterprise-messaging.js +10 -58
  140. package/libx/_runtime/messaging/outbox/utils.js +1 -1
  141. package/libx/_runtime/remote/Service.js +20 -1
  142. package/libx/_runtime/remote/utils/client.js +3 -5
  143. package/libx/_runtime/sqlite/Service.js +4 -6
  144. package/libx/_runtime/sqlite/conversion.js +3 -13
  145. package/libx/_runtime/sqlite/customBuilder/CustomFunctionBuilder.js +9 -6
  146. package/libx/_runtime/sqlite/customBuilder/CustomUpsertBuilder.js +6 -1
  147. package/libx/_runtime/sqlite/execute.js +5 -16
  148. package/libx/odata/afterburner.js +22 -6
  149. package/libx/odata/grammar.pegjs +6 -1
  150. package/libx/odata/parser.js +1 -1
  151. package/libx/rest/RestAdapter.js +16 -9
  152. package/libx/rest/RestRequest.js +1 -1
  153. package/libx/rest/middleware/input.js +2 -1
  154. package/libx/rest/middleware/operation.js +1 -0
  155. package/libx/rest/middleware/parse.js +3 -2
  156. package/libx/rest/middleware/payload.js +9 -8
  157. package/libx/rest/middleware/read.js +1 -0
  158. package/package.json +9 -16
  159. package/server.js +1 -1
  160. package/app/fiori/preview.js +0 -270
  161. package/app/fiori/routes.js +0 -59
  162. package/bin/build/buildTaskEngine.js +0 -360
  163. package/bin/build/buildTaskFactory.js +0 -283
  164. package/bin/build/buildTaskHandler.js +0 -241
  165. package/bin/build/buildTaskProvider.js +0 -22
  166. package/bin/build/buildTaskProviderFactory.js +0 -175
  167. package/bin/build/cds.js +0 -5
  168. package/bin/build/constants.js +0 -66
  169. package/bin/build/index.js +0 -58
  170. package/bin/build/provider/buildTaskHandlerEdmx.js +0 -82
  171. package/bin/build/provider/buildTaskHandlerFeatureToggles.js +0 -131
  172. package/bin/build/provider/buildTaskHandlerInternal.js +0 -254
  173. package/bin/build/provider/buildTaskProviderInternal.js +0 -383
  174. package/bin/build/provider/fiori/index.js +0 -171
  175. package/bin/build/provider/hana/2migration.js +0 -179
  176. package/bin/build/provider/hana/index.js +0 -505
  177. package/bin/build/provider/hana/migrationtable.js +0 -472
  178. package/bin/build/provider/hana/template/.hdiconfig-haas +0 -163
  179. package/bin/build/provider/hana/template/.hdiconfig-hanacloud +0 -137
  180. package/bin/build/provider/hana/template/.hdinamespace +0 -4
  181. package/bin/build/provider/hana/template/package.json +0 -12
  182. package/bin/build/provider/hana/template/undeploy.json +0 -5
  183. package/bin/build/provider/java/index.js +0 -111
  184. package/bin/build/provider/java-cf/index.js +0 -1
  185. package/bin/build/provider/mtx/index.js +0 -268
  186. package/bin/build/provider/mtx/resourcesTarBuilder.js +0 -95
  187. package/bin/build/provider/mtx-extension/index.js +0 -131
  188. package/bin/build/provider/mtx-sidecar/index.js +0 -137
  189. package/bin/build/provider/node-cf/index.js +0 -1
  190. package/bin/build/provider/nodejs/index.js +0 -192
  191. package/bin/build/util.js +0 -299
  192. package/bin/cds.js +0 -125
  193. package/bin/deploy/to-hana/cfUtil.js +0 -355
  194. package/bin/deploy/to-hana/gitUtil.js +0 -57
  195. package/bin/deploy/to-hana/hana.js +0 -306
  196. package/bin/deploy/to-hana/hdiDeployUtil.js +0 -153
  197. package/bin/deploy/to-hana/index.js +0 -16
  198. package/bin/deploy/to-hana/mtaUtil.js +0 -170
  199. package/bin/mtx/in-cds.js +0 -17
  200. package/bin/plugins.js +0 -32
  201. package/bin/run.js +0 -24
  202. package/bin/utils/log.js +0 -24
  203. package/bin/version.js +0 -178
  204. package/libx/_runtime/audit/Service.js +0 -222
  205. package/libx/_runtime/audit/generic/personal/access.js +0 -61
  206. package/libx/_runtime/audit/generic/personal/index.js +0 -56
  207. package/libx/_runtime/audit/generic/personal/modification.js +0 -132
  208. package/libx/_runtime/audit/generic/personal/utils.js +0 -186
  209. package/libx/_runtime/audit/utils/log.js +0 -23
  210. package/libx/_runtime/audit/utils/v2.js +0 -176
  211. package/libx/_runtime/db/data-conversion/timestamp.js +0 -9
  212. package/libx/_runtime/db/generic/integrity.js +0 -455
  213. package/srv/audit-log.cds +0 -87
  214. package/srv/mtx.cds +0 -2
  215. package/srv/mtx.js +0 -8
  216. /package/lib/{core → linked}/classes.js +0 -0
  217. /package/lib/{core → linked}/entities.js +0 -0
package/bin/run.js DELETED
@@ -1,24 +0,0 @@
1
- const serve = require ('./serve')
2
- module.exports = Object.assign (
3
- cds_run, serve, {help: `
4
- # SYNOPSIS
5
-
6
- *cds run* [<project>] [<options>]
7
-
8
- Runs 'cds serve all' for the specified project, with default <project> = cwd.
9
-
10
- # OPTIONS
11
-
12
- - see _cds help serve_
13
-
14
- # SEE ALSO
15
-
16
- Actually, *cds run* is just a convenient shortcut for:
17
- *cds serve* [--project <project>] [<options>] ...
18
- Check out *cds serve --help* to learn more.
19
-
20
- `})
21
-
22
- function cds_run (projects, options) {
23
- return serve (projects,{ project:true, ...options })
24
- }
package/bin/utils/log.js DELETED
@@ -1,24 +0,0 @@
1
- // sorts, filters, and writes compilation messages to console
2
- module.exports = (messages, options={}) => {
3
- const { format } = require('./term')
4
- const logLevel = options && options['log-level'] || require('../../lib').env.log.levels.cli || ''
5
- const levels = {
6
- debug: { Error:4, undefined:4, Warning:3, Info:2, Debug:1 },
7
- info: { Error:4, undefined:4, Warning:3, Info:2 },
8
- warn: { Error:4, undefined:4, Warning:3 },
9
- error: { Error:4, undefined:4 },
10
- } [logLevel.toLowerCase()] || { Error:4, undefined:4, Warning:3 }
11
- const log = options.log || console.error
12
-
13
- if (!Array.isArray (messages)) messages = [messages]
14
- for (let m of messages.filter (m => m.severity in levels)) {
15
- // show stack for resolution issues since there the requiring code location is in the stack
16
- // check for standard Error classes, but not Error itself
17
- const internalError = m.name === 'EvalError' || m.name === 'InternalError' || m.name === 'RangeError'
18
- || m.name === 'ReferenceError' || m.name === 'SyntaxError' || m.name === 'TypeError'
19
- || m.name === 'URIError'
20
- const mf = format (m, m.severity, internalError, true)
21
- log (mf)
22
- }
23
- }
24
- /* eslint no-console:off */
package/bin/version.js DELETED
@@ -1,178 +0,0 @@
1
- /* eslint-disable no-console */
2
- const { dirname, join, resolve } = require ('path')
3
- const { cwd } = require('process')
4
- module.exports = Object.assign(list_versions, {
5
- flags: [ '--info', '--markdown', '--all', '--npm-list', '--npm-tree', '--no-colors'],
6
- shortcuts: [ '-i', '-m','-a', '-ls', '-ll' ],
7
- info,
8
- help: `
9
- # SYNOPSIS
10
-
11
- *cds version* <options>
12
- *cds -v* <option>
13
-
14
- Prints the versions of all @sap/cds packages in your package dependencies.
15
-
16
- # OPTIONS
17
-
18
- *-i | --info*
19
-
20
- Prints version information in a tabular markdown format, which you
21
- can embed into your bug reports.
22
-
23
- *-a | --all*
24
-
25
- Also lists sub-packages and optional dependencies.
26
-
27
- *-ls | --npm-list* <pattern>
28
- *-ll | --npm-tree* <pattern>
29
-
30
- Prints an npm ls tree filtered to the specified pattern.
31
- (default: '@sap/cds')
32
-
33
- `})
34
-
35
- const MISSING = '-- missing --'
36
-
37
- function list_versions(args, options) { //NOSONAR
38
- if (options['npm-list'] || options['npm-tree']) {
39
- let [pattern] = args, re = pattern ? RegExp(pattern) : /@sap\/cd[rs]|@sap\/eslint-plugin-cds/
40
- let cmd = 'npm ls --depth ' + (options['npm-tree'] ? 11 : 0)
41
- console.log (cmd,'| grep', pattern)
42
- return require('child_process').exec(cmd, (e,stdout)=>{
43
- // if (e) console.error(e)
44
- const replacement = (options['no-colors'] ? '$1 $2$3$4' : '\x1b[91m$1 \x1b[32m$2\x1b[0m\x1b[2m$3\x1b[32m$4\x1b[0m');
45
- for (let line of stdout.split(/\n/)) if (line.match(re)) console.log(
46
- line.replace(/(@sap[^@]*)@([\S]+)( -> [\S]+)?(deduped)?/,replacement)
47
- )
48
- })
49
- }
50
- const versions = info (options)
51
- if (options.markdown) return _markdown (versions)
52
- if (options.info) return _markdown (versions)
53
- const mark = options['no-colors'] ? s => s : require('./utils/term').info
54
- for (let each of Object.keys(versions).sort()) console.log(`${mark(each)}: ${versions[each]}`)
55
- }
56
-
57
- function info(o) {
58
- const { npmGlobalModules } = require('./utils/modules');
59
- const main = _findPackage (require.main.filename)
60
- const sap_cds = require.resolve('@sap/cds/package.json', {paths:[process.cwd(), __dirname]})
61
- return {
62
- // REVISIT: Why do we need all these different hard-coded ways, including proliferation of arguments?
63
- ..._versions4(main, {}, true), // usually sap/cds-dk or sap/cds
64
- ..._versions4('@sap/cds-dk', {}, null, o), // make sure cds-dk is there, cds-maven-plugin uses it
65
- ..._versions4('@sap/cds-dk', {}, null, {...o, label: '@sap/cds-dk (global)', pkg: join(npmGlobalModules(), '@sap/cds-dk')}),
66
- ..._versions4('@sap/eslint-plugin-cds', {}, null, o),
67
- ..._versions4(process.cwd(), {}, null, o),
68
- ..._versions4('..', {}, null, o),
69
- ..._findMTX(),
70
- '@sap/cds': require(sap_cds).version, // ensure effective sap/cds version is listed
71
- 'Node.js': process.version,
72
- 'home': __dirname.slice(0,-4)
73
- }
74
- }
75
-
76
- function _versions4 (pkg_name, info, parent, o={}) {
77
- if (!pkg_name) return info
78
- try {
79
- let path = join(o.pkg || pkg_name, 'package.json')
80
- if(o.here) {
81
- // path.join(['./', x]) is immediately resolved to x.
82
- // Calling require() on that will then follow the standard (global) module resolution strategy.
83
- // If we want to look into a directory relative to CWD,
84
- // turning it into a global path is the most convenient way.
85
- path = join(cwd(), path)
86
- }
87
- const pkg = require(path)
88
- info[o.label || pkg.name] = pkg.version
89
- // console.log(o.label || pkg.name, pkg.version, path)
90
- if (!parent || o.all) for (let d in pkg.dependencies) { // recurse sap packages in dependencies...
91
- if (!(d in info) && (d.startsWith('@sap/') || d.startsWith('@cap-js/'))) _versions4(d, info, pkg.name, o)
92
- }
93
- } catch (e) {
94
- if (e.code !== 'MODULE_NOT_FOUND') info[pkg_name] = MISSING // unknown error
95
- // require fails for indirect packages if node_modules layout is nested, e.g. on Windows.
96
- // Try one more time with nested node_modules dir.
97
- else if (parent) _versions4(parent + '/node_modules/' + pkg_name, info)
98
- }
99
- return info
100
- }
101
-
102
-
103
- function _markdown (versions) {
104
- console.log()
105
- const pkg = { name:'', repository:'', version:'' }; try {
106
- Object.assign (pkg, require (resolve('package.json')))
107
- } catch (e) {/* ignored */}
108
- console.log ('|', pkg.name, '|', pkg.repository.url || pkg.repository, '|')
109
- console.log ('|:---------------------- | ----------- |')
110
- if (require('../lib').env['project-nature'] === 'nodejs') {
111
- console.log ('|', v('Node.js'), '|')
112
- console.log ('|', v('@sap/cds'), '|')
113
- } else {
114
- console.log ('|', v('CAP Java Runtime'), '|')
115
- console.log ('|', v('OData Version'), '|')
116
- }
117
- console.log ('|', v('@sap/cds-compiler'), '|')
118
- console.log ('|', v('@sap/cds-dk'), '|')
119
- console.log ('|', v('@sap/cds-dk (global)'), '|')
120
- console.log ('|', v('@sap/eslint-plugin-cds'), '|')
121
- function v (component) {
122
- const version = versions [component] || '_version_'
123
- return (component + ' ').slice(0,22)
124
- +' | '+ (version + ' ').slice(0,11)
125
- }
126
- console.log()
127
- }
128
-
129
- function _findPackage (dir) {
130
- try {
131
- if (dir) {
132
- require.resolve(join (dir, 'package.json'))
133
- return dir
134
- }
135
- } catch (e) {
136
- if (e.code !== 'MODULE_NOT_FOUND') throw e
137
- return _findPackage (dirname (dir))
138
- }
139
- }
140
-
141
- function _findMTX() {
142
- // looks for any occurrence of cds-mtx.
143
- // In node projects, cds-mtx can be resolved via _versions4 like all the other SAP modules
144
- // In Java-flavoured projects cds-mtx may be deployed through a separate node project
145
- // with just sidecar in it. So we can not rely on the global require() resolution strategy
146
- // and will as a fallback...
147
- // (1) ...look for an MTX project within cds.env
148
- // (2) ...look within a few preselected subdirectories which often contain MTX projects
149
- const cds = require('../lib')
150
- const cdsmtx = '@sap/cds-mtx'
151
- let res = _versions4 (cdsmtx, {}, null)
152
-
153
- if (res[cdsmtx] === undefined) {
154
- // not resolvable -> look in cds.env
155
- if ('build' in cds.env && 'tasks' in cds.env.build) {
156
- let i = 0
157
- while (res[cdsmtx] === undefined && i < cds.env.build.tasks.length) {
158
- const task = cds.env.build.tasks[i]
159
- if ('for' in task && task.for === 'mtx' && 'dest' in task) {
160
- res = _versions4 (join(task.dest, 'node_modules', cdsmtx), {}, null, {here: true})
161
- }
162
- i++
163
- }
164
- }
165
-
166
- // mtx still not found via cds.env? Try looking in well-known subdirectories
167
- const folders = cds.env.folders
168
- ? [cds.env.folders.db, cds.env.folders.srv].flat().filter(d => d)
169
- : []
170
- let i = 0
171
- while(res[cdsmtx] === undefined && i < folders.length) {
172
- res = _versions4 (join(folders[i], 'node_modules', cdsmtx), {}, null, {here: true})
173
- i++
174
- }
175
- res[cdsmtx] = res[cdsmtx] || MISSING
176
- }
177
- return res
178
- }
@@ -1,222 +0,0 @@
1
- const cds = require('../cds')
2
- const OutboxService = require('../messaging/Outbox')
3
- const {
4
- connect,
5
- buildDataAccessLogs,
6
- sendDataAccessLog,
7
- buildDataModificationLogs,
8
- sendDataModificationLog,
9
- buildSecurityLog,
10
- sendSecurityLog,
11
- buildConfigChangeLogs,
12
- sendConfigChangeLog
13
- } = require('./utils/v2')
14
- const ANONYMOUS = 'anonymous'
15
- const PLAN = {
16
- standard: 'standard',
17
- OAuth2: 'OAuth2'
18
- }
19
-
20
- const _getTenantAndUser = options => {
21
- // REVISIT: the standard plan is deprecated/insecure
22
- if (options.plan === PLAN.standard) {
23
- return {
24
- user: cds.context?.user?.id ?? ANONYMOUS,
25
- tenant: cds.context?.tenant
26
- }
27
- }
28
-
29
- return {
30
- user: '$USER',
31
- tenant: '$PROVIDER'
32
- }
33
- }
34
-
35
- const _getSecurityContext = () => {
36
- const securityContext = cds?.context?.http?.req?.authInfo
37
-
38
- if (!securityContext) {
39
- const errorMsg =
40
- '[Audit Logging]: The Programmatic API of the Audit Logging service for the OAuth2 plan (API - V2) can only be ' +
41
- 'called within the context of a request event handler. The authInfo property of the request interface (req.authInfo) ' +
42
- "is used to get the security context required for the implementation's proper functioning."
43
- throw new Error(errorMsg)
44
- }
45
-
46
- return securityContext
47
- }
48
-
49
- module.exports = class AuditLogService extends OutboxService {
50
- async init() {
51
- // call OutboxService's init, which handles outboxing
52
- await super.init()
53
-
54
- const credentials = this.options.credentials
55
- this.options.plan = !credentials || !credentials.uaa ? PLAN.standard : PLAN.OAuth2
56
-
57
- // REVISIT: the standard plan is deprecated/insecure
58
- if (this.options.plan === PLAN.standard) {
59
- const auditLogClient = await connect(credentials)
60
- if (auditLogClient) this.#registerOnHandlers(auditLogClient)
61
- return
62
- }
63
-
64
- // OAuth2 plan
65
- const outbox = cds.requires['audit-log'].outbox
66
- if (outbox?.kind === 'persistent-outbox' || (outbox && cds.requires.outbox?.kind === 'persistent-outbox')) {
67
- throw new Error('The OAuth2 plan is not currently supported with persistent outbox')
68
- }
69
-
70
- if (credentials?.uaa) this.#registerOnHandlers()
71
- }
72
-
73
- async emit(first, second) {
74
- const { event, data } = typeof first === 'object' ? first : { event: first, data: second }
75
- if (!this.options.outbox) return this.send(event, data)
76
-
77
- if (this[event]) {
78
- try {
79
- // this will open a new tx -> preserve user
80
- await super.send(new cds.Request({ method: event, data, user: cds.context.user }))
81
- } catch (e) {
82
- if (e.code === 'ERR_ASSERTION') {
83
- e.unrecoverable = true
84
- }
85
- throw e
86
- }
87
- }
88
- }
89
-
90
- async send(event, data) {
91
- if (this[event]) return super.send(event, data)
92
- }
93
-
94
- /*
95
- * api (await AuditLogService.<event>(data))
96
- */
97
-
98
- async dataAccessLog(data) {
99
- return super.send('dataAccessLog', data)
100
- }
101
-
102
- async dataModificationLog(data) {
103
- return super.send('dataModificationLog', data)
104
- }
105
-
106
- async securityLog(data) {
107
- return super.send('securityLog', data)
108
- }
109
-
110
- async configChangeLog(data) {
111
- return super.send('configChangeLog', data)
112
- }
113
-
114
- /*
115
- * impl
116
- */
117
-
118
- #registerOnHandlers(auditLogClient) {
119
- this.on('dataAccessLog', function (req) {
120
- return this._dataAccessLog(req, auditLogClient)
121
- })
122
-
123
- this.on('dataModificationLog', function (req) {
124
- return this._dataModificationLog(req, auditLogClient)
125
- })
126
-
127
- this.on('securityLog', function (req) {
128
- return this._securityLog(req, auditLogClient)
129
- })
130
-
131
- this.on('configChangeLog', function (req) {
132
- return this._configChangeLog(req, auditLogClient)
133
- })
134
- }
135
-
136
- async _dataAccessLog({ data: { accesses } }, auditLogClient) {
137
- const { tenant, user } = _getTenantAndUser(this.options)
138
-
139
- // build the logs
140
- auditLogClient = auditLogClient ?? (await connect(this.options.credentials, _getSecurityContext()))
141
- const { entries, errors } = buildDataAccessLogs(auditLogClient, accesses, tenant, user)
142
- if (errors.length) {
143
- throw errors.length === 1 ? errors[0] : Object.assign(new Error('MULTIPLE_ERRORS'), { details: errors })
144
- }
145
-
146
- // write the logs
147
- await Promise.all(entries.map(entry => sendDataAccessLog(entry).catch(err => errors.push(err))))
148
-
149
- if (errors.length) {
150
- throw errors.length === 1 ? errors[0] : Object.assign(new Error('MULTIPLE_ERRORS'), { details: errors })
151
- }
152
- }
153
-
154
- // REVISIT: modification.action not used in auditlog v2
155
- async _dataModificationLog({ data: { modifications } }, auditLogClient) {
156
- const { tenant, user } = _getTenantAndUser(this.options)
157
-
158
- // build the logs
159
- auditLogClient = auditLogClient ?? (await connect(this.options.credentials, _getSecurityContext()))
160
- const { entries, errors } = buildDataModificationLogs(auditLogClient, modifications, tenant, user)
161
- if (errors.length) {
162
- throw errors.length === 1 ? errors[0] : Object.assign(new Error('MULTIPLE_ERRORS'), { details: errors })
163
- }
164
-
165
- // write the logs
166
- await Promise.all(entries.map(entry => sendDataModificationLog(entry).catch(err => errors.push(err))))
167
-
168
- if (errors.length) {
169
- throw errors.length === 1 ? errors[0] : Object.assign(new Error('MULTIPLE_ERRORS'), { details: errors })
170
- }
171
- }
172
-
173
- async _securityLog({ data: { action, data } }, auditLogClient) {
174
- let { tenant, user } = _getTenantAndUser(this.options)
175
-
176
- // cds.context may not be proper on auth-related errors -> try to extract from data
177
- if (!tenant && user === ANONYMOUS) {
178
- try {
179
- const parsed = JSON.parse(data)
180
- if (parsed.tenant) {
181
- tenant = parsed.tenant
182
- delete parsed.tenant
183
- }
184
-
185
- if (parsed.user && typeof parsed.user === 'string') {
186
- user = parsed.user
187
- delete parsed.user
188
- }
189
-
190
- data = JSON.stringify(parsed)
191
- } catch (e) {
192
- // ignore
193
- }
194
- }
195
-
196
- // build the log
197
- auditLogClient = auditLogClient ?? (await connect(this.options.credentials, _getSecurityContext()))
198
- const entry = buildSecurityLog(auditLogClient, action, data, tenant, user)
199
-
200
- // write the log
201
- await sendSecurityLog(entry)
202
- }
203
-
204
- // REVISIT: action and success not used in auditlog v2
205
- async _configChangeLog({ data: { configurations } }, auditLogClient) {
206
- const { tenant, user } = _getTenantAndUser(this.options)
207
-
208
- // build the logs
209
- auditLogClient = auditLogClient ?? (await connect(this.options.credentials, _getSecurityContext()))
210
- const { entries, errors } = buildConfigChangeLogs(auditLogClient, configurations, tenant, user)
211
- if (errors.length) {
212
- throw errors.length === 1 ? errors[0] : Object.assign(new Error('MULTIPLE_ERRORS'), { details: errors })
213
- }
214
-
215
- // write the logs
216
- await Promise.all(entries.map(entry => sendConfigChangeLog(entry).catch(err => errors.push(err))))
217
-
218
- if (errors.length) {
219
- throw errors.length === 1 ? errors[0] : Object.assign(new Error('MULTIPLE_ERRORS'), { details: errors })
220
- }
221
- }
222
- }
@@ -1,61 +0,0 @@
1
- const cds = require('../../../cds')
2
-
3
- const getTemplate = require('../../../common/utils/template')
4
- const templateProcessor = require('../../../common/utils/templateProcessor')
5
-
6
- const {
7
- getRootEntity,
8
- getPick,
9
- createLogEntry,
10
- addObjectID,
11
- addDataSubject,
12
- addDataSubjectForDetailsEntity,
13
- resolveDataSubjectPromises
14
- } = require('./utils')
15
-
16
- const _processorFnAccess = (accessLogs, model, req) => {
17
- return ({ row, key, element, plain }) => {
18
- if (row.IsActiveEntity === false) return
19
-
20
- const entity = getRootEntity(element)
21
-
22
- // create or augment log entry
23
- const entry = createLogEntry(accessLogs, entity, row)
24
-
25
- // process categories
26
- for (const category of plain.categories) {
27
- if (category === 'ObjectID') addObjectID(entry, row, key)
28
- else if (category === 'DataSubjectID') addDataSubject(entry, row, key, entity)
29
- else if (category === 'IsPotentiallySensitive' && key in row) {
30
- if (!entry.attributes.some(e => e.name === key)) entry.attributes.push({ name: key })
31
- // REVISIT: attribute vs. attachment?
32
- }
33
- }
34
-
35
- // add promise to determine data subject if a DataSubjectDetails entity
36
- const semantics = entity['@PersonalData.EntitySemantics']
37
- if (
38
- (semantics === 'DataSubjectDetails' || semantics === 'Other') &&
39
- entry.dataSubject.id.length === 0 // > id still an array -> promise not yet set
40
- ) {
41
- addDataSubjectForDetailsEntity(row, entry, req, entity, model)
42
- }
43
- }
44
- }
45
-
46
- const auditAccessHandler = async function (data, req) {
47
- const auditLogService = await cds.connect.to('audit-log')
48
- const mock = Object.assign({ name: req.target._service.name, model: this.model })
49
- const template = getTemplate('personal_read', mock, req.target, { pick: getPick('READ') })
50
- if (!template.elements.size) return
51
- const accessLogs = {}
52
- if (typeof data === 'object' && data !== null) {
53
- const processFn = _processorFnAccess(accessLogs, this.model, req)
54
- const data_ = Array.isArray(data) ? data : [data]
55
- data_.forEach(row => templateProcessor({ processFn, row, template }))
56
- const accesses = (await resolveDataSubjectPromises(accessLogs)).filter(ele => ele.attributes.length)
57
- if (accesses.length) await auditLogService.emit('dataAccessLog', { accesses })
58
- }
59
- }
60
-
61
- module.exports = { auditAccessHandler }
@@ -1,56 +0,0 @@
1
- const cds = require('../../../cds')
2
- const {
3
- attachDiffToContextHandler,
4
- calcModificationLogsHandler4Before,
5
- calcModificationLogsHandler4After,
6
- emitModificationHandler
7
- } = require('./modification')
8
- const { auditAccessHandler } = require('./access')
9
-
10
- exports.impl = cds.service.impl(function () {
11
- if (!cds.db) return cds.on('connect', srv => srv.isDatabaseService && exports.impl.call(this))
12
- // REVISIT: diff() doesn't work in srv after phase but foreign key propagation has not yet taken place in srv before phase
13
- // -> calc diff in db layer and store in audit data structure at context
14
- // -> REVISIT for GA: clear req._.partialPersistentState?
15
- attachDiffToContextHandler._initial = true
16
- for (const e of this.entities) {
17
- if (!_hasPersonalData(e)) continue
18
-
19
- if (e['@AuditLog.Operation.Insert']) {
20
- cds.db.before('CREATE', e, attachDiffToContextHandler)
21
- // create -> all new -> calcModificationLogsHandler in after phase
22
- cds.db.after('CREATE', e, calcModificationLogsHandler4After)
23
- this.after('CREATE', e, emitModificationHandler)
24
- }
25
-
26
- if (e['@AuditLog.Operation.Update']) {
27
- cds.db.before('UPDATE', e, attachDiffToContextHandler)
28
- // update -> mixed (via deep) -> calcModificationLogsHandler in before and after phase
29
- cds.db.before('UPDATE', e, calcModificationLogsHandler4Before)
30
- cds.db.after('UPDATE', e, calcModificationLogsHandler4After)
31
- this.after('UPDATE', e, emitModificationHandler)
32
- }
33
-
34
- if (e['@AuditLog.Operation.Delete']) {
35
- cds.db.before('DELETE', e, attachDiffToContextHandler)
36
- // delete -> all done -> calcModificationLogsHandler in before phase
37
- cds.db.before('DELETE', e, calcModificationLogsHandler4Before)
38
- this.after('DELETE', e, emitModificationHandler)
39
- }
40
-
41
- if (e['@AuditLog.Operation.Read']) {
42
- this.after('READ', e, auditAccessHandler)
43
- }
44
- }
45
- })
46
-
47
- const _hasPersonalData = e => {
48
- if (!e['@PersonalData.DataSubjectRole']) return
49
- if (!e['@PersonalData.EntitySemantics']) return
50
- return !!Object.values(e.elements).some(
51
- e =>
52
- e['@PersonalData.IsPotentiallyPersonal'] ||
53
- e['@PersonalData.IsPotentiallySensitive'] ||
54
- (e['@PersonalData.FieldSemantics'] && e['@PersonalData.FieldSemantics'] === 'DataSubjectID')
55
- )
56
- }