@sap/eslint-plugin-cds
Version:
ESLint plugin including recommended SAP Cloud Application Programming model and environment rules
86 lines (78 loc) • 2.63 kB
JavaScript
const VALID_PSEUDO_ROLES = new Set(['authenticated-user', 'system-user', 'internal-user', 'any'])
module.exports = {
meta: {
schema: [{/* to avoid deprecation warning for ESLint 9 */}],
docs: {
description: '`@restrict.to` must have valid values.',
category: 'Model Validation',
recommended: true,
url: 'https://cap.cloud.sap/docs/tools/cds-lint/rules/auth-valid-restrict-to',
},
messages: {
invalidType: 'Invalid type for value of `@restrict.to`. Must either be string or array of strings.',
pseudoRoleTypo: "Did you mean pseudo-role '{{valid}}' instead of '{{role}}'?",
any: 'Role \'any\' overrides all other roles. Replace by \'any\' only.'
},
type: 'problem',
model: 'inferred'
},
create (context) {
return {
entity: checkRestrictTo,
service: checkRestrictTo,
action: checkRestrictTo,
function: checkRestrictTo,
}
function checkRestrictTo(def) {
// TODO: This check also applies to `@requires`. Test that.
if (!Array.isArray(def?.['@restrict']))
return
const node = context.getNode(def)
const file = def.$location.file
def['@restrict'].forEach(checkRestrictEntry)
function checkRestrictEntry(entry) {
if (entry?.to !== undefined) {
const roles = getUserRoles(entry)
if (roles.every(checkRole)) {
// all roles are valid
if (roles.length > 1 && roles.includes('any'))
context.report({ messageId: 'any', node, file })
}
}
}
function getUserRoles(entry) {
if (typeof entry.to === 'string') {
return [ entry.to ]
}
else if (Array.isArray(entry.to)) {
return entry.to
}
else {
// neither string nor array: report invalid type
context.report({ messageId: 'invalidType', node, file })
return []
}
}
function checkRole(role) {
if (typeof role !== 'string') {
context.report({ messageId: 'invalidType', node, file })
return false
}
else if (role !== '') {
// empty roles handled by auth-no-empty-restrictions
const roleLowercase = role.toLowerCase()
if (roleLowercase !== role && VALID_PSEUDO_ROLES.has(roleLowercase)) {
context.report({
messageId: 'pseudoRoleTypo',
data: { role, valid: roleLowercase },
node, file,
})
return false
}
return true
}
}
}
}
}