@sap/cds
Version:
SAP Cloud Application Programming Model - CDS for Node.js
75 lines (62 loc) • 2.63 kB
JavaScript
const cds = require('../../../cds')
const { rewriteExpandAsterisk } = require('../../utils/rewriteAsterisks')
const { ensureNoDraftsSuffix } = require('../../utils/draft')
const _getTarget = (ref, target, definitions) => {
if (cds.env.effective.odata.proxies) {
const target_ = target.elements[ref[0]]
if (ref.length === 1) return definitions[ensureNoDraftsSuffix(target_.target)]
return _getTarget(ref.slice(1), target_, definitions)
}
const target_ = target.elements[ref.map(x => x.id || x).join('_')]
return definitions[ensureNoDraftsSuffix(target_.target)]
}
const _getRestrictedExpand = (columns, target, definitions, depth = 0, maxLevels) => {
if (!columns || !target || columns === '*') return
const annotation = target['@Capabilities.ExpandRestrictions.NonExpandableProperties']
const restrictions = annotation?.map(element => element['=']) ?? []
let maxLevelsViolation
rewriteExpandAsterisk(columns, target)
for (const col of columns) {
if (!col.expand) continue
if (restrictions.length) {
const ref = col.ref.join('_')
const ref_ = restrictions.find(element => element.replace(/\./g, '_') === ref)
if (ref_) return { type: 'nonExpandable', property: ref_ }
}
// expand: '**' or '*3' is only possible within custom handler, no check needed
if (typeof col.expand[0] === 'string' && /^\*{1}[\d|*]+/.test(col.expand[0])) continue
if (maxLevels != null && depth + 1 > maxLevels) {
maxLevelsViolation ??= { type: 'maxLevels', maxLevels }
continue
}
const restricted = _getRestrictedExpand(
col.expand,
_getTarget(col.ref, target, definitions),
definitions,
depth + 1,
maxLevels
)
if (restricted) {
if (restricted.type === 'nonExpandable') return restricted
maxLevelsViolation ??= restricted
}
}
return maxLevelsViolation
}
function restrict_expand(req) {
if (!req.query) return
const columns = req.query.SELECT?.columns
if (!columns) return
const maxLevels =
req.target['@Capabilities.ExpandRestrictions.Expandable'] === false
? 0
: (req.target['@Capabilities.ExpandRestrictions.MaxLevels'] ?? cds.env.query?.restrictions?.expand?.maxLevels)
const restricted = _getRestrictedExpand(columns, req.target, this.model.definitions, 0, maxLevels)
if (!restricted) return
if (restricted.type === 'nonExpandable') {
req.reject(400, 'EXPAND_IS_RESTRICTED', [restricted.property])
} else if (restricted.type === 'maxLevels') {
req.reject(400, 'EXPAND_MAX_LEVELS_EXCEEDED', [restricted.maxLevels])
}
}
module.exports = restrict_expand