adapt-authoring-roles 1.1.0 → 1.1.2

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.
@@ -3,10 +3,16 @@ on:
3
3
  push:
4
4
  branches:
5
5
  - master
6
+
6
7
  jobs:
7
8
  release:
8
9
  name: Release
9
10
  runs-on: ubuntu-latest
11
+ permissions:
12
+ contents: write # to be able to publish a GitHub release
13
+ issues: write # to be able to comment on released issues
14
+ pull-requests: write # to be able to comment on released pull requests
15
+ id-token: write # to enable use of OIDC for trusted publishing and npm provenance
10
16
  steps:
11
17
  - name: Checkout
12
18
  uses: actions/checkout@v3
@@ -16,10 +22,11 @@ jobs:
16
22
  uses: actions/setup-node@v3
17
23
  with:
18
24
  node-version: 'lts/*'
25
+ - name: Update npm
26
+ run: npm install -g npm@latest
19
27
  - name: Install dependencies
20
28
  run: npm ci
21
29
  - name: Release
22
30
  env:
23
31
  GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
24
- NPM_TOKEN: ${{ secrets.AAT_NPM_TOKEN }}
25
- run: npx semantic-release
32
+ run: npx semantic-release
@@ -8,6 +8,7 @@ class RolesModule extends AbstractApiModule {
8
8
  /** @override */
9
9
  async init () {
10
10
  await super.init()
11
+ this.cache.isEnabled = true
11
12
  try {
12
13
  await this.initConfigRoles()
13
14
 
@@ -54,11 +55,7 @@ class RolesModule extends AbstractApiModule {
54
55
  */
55
56
  async shortNamesToIds (roles) {
56
57
  return Promise.all(roles.map(async r => {
57
- let role = this.roleCache[r]
58
- if (!role) {
59
- [role] = await this.find({ shortName: r })
60
- this.roleCache[r] = role
61
- }
58
+ const [role] = await this.find({ shortName: r })
62
59
  return role._id.toString()
63
60
  }))
64
61
  }
@@ -84,12 +81,6 @@ class RolesModule extends AbstractApiModule {
84
81
  * @return {Promise}
85
82
  */
86
83
  async initDefaultRoles () {
87
- /**
88
- * Local store of roles
89
- * @type {Object}
90
- */
91
- this.roleCache = {}
92
-
93
84
  const rolesforAll = await this.shortNamesToIds(this.getConfig('defaultRoles'))
94
85
  const rolesForAuth = Object.entries(this.getConfig('defaultRolesForAuthTypes')).reduce((m, [k, v]) => {
95
86
  return { [m[k]]: this.shortNamesToIds(v) }
@@ -116,12 +107,23 @@ class RolesModule extends AbstractApiModule {
116
107
  * @returns {Promise}
117
108
  */
118
109
  async onUpdateRoles (req) {
119
- if (!req.body.roles || req.method === 'GET' || req.method === 'DELETE') {
110
+ if (req.apiData?.modifying !== false || (req.method !== 'DELETE' && !req.apiData?.data.roles)) {
120
111
  return
121
112
  }
122
- if (!req.auth.isSuper && !req.auth.scopes.includes('assign:roles')) {
123
- this.log('error', 'User does not have the correct permissions to assign user roles')
124
- throw this.app.errors.UNAUTHORISED
113
+ if (!req.auth.isSuper) {
114
+ const reject = reason => {
115
+ this.log('error', 'UNAUTHORISED', req.auth.user._id.toString(), reason)
116
+ throw this.app.errors.UNAUTHORISED
117
+ }
118
+ if (!req.auth.scopes.includes('assign:roles')) {
119
+ reject('assign role')
120
+ }
121
+ if (req.apiData.data.roles.includes(await this.getSuperRoleId())) {
122
+ reject('assign superuser')
123
+ }
124
+ if (await this.isTargetSuper(req.apiData.query._id)) {
125
+ reject('modify superuser')
126
+ }
125
127
  }
126
128
  if (req.method !== 'POST') {
127
129
  const auth = await this.app.waitForModule('auth')
@@ -129,22 +131,22 @@ class RolesModule extends AbstractApiModule {
129
131
  }
130
132
  }
131
133
 
132
- /**
133
- * Blocks modification of super users by non-super users
134
- * @param {external:ExpressRequest} req
135
- * @param {Object} data Request data
136
- */
137
- async onCheckUserAccess (req, data) {
138
- if (['GET', 'POST'].includes(req.method)) {
139
- return true
140
- }
141
- const users = await this.app.waitForModule('users')
142
- const [user] = await users.find({ _id: req.apiData.query._id })
143
- const scopes = user.roles.length === 1 ? await this.getScopesForRole(user.roles[0]) : []
144
- const isSuper = scopes.length === 1 && scopes[0] === '*:*'
145
- if (isSuper && !req.auth.isSuper) {
134
+ async onCheckUserAccess (req) { // note access checks don't run for super users
135
+ if (req.apiData.modifying && await this.isTargetSuper(req.apiData.query._id)) {
146
136
  throw this.app.errors.UNAUTHORISED
147
137
  }
138
+ return true
139
+ }
140
+
141
+ async getSuperRoleId () {
142
+ const [superRole] = await this.find({ scopes: ['*:*'] })
143
+ return superRole._id.toString()
144
+ }
145
+
146
+ async isTargetSuper (_id) {
147
+ const users = await this.app.waitForModule('users')
148
+ const [user] = await users.find({ _id }, { projection: { roles: 1 } })
149
+ return user.roles.length === 1 && user.roles[0].toString() === await this.getSuperRoleId()
148
150
  }
149
151
  }
150
152
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "adapt-authoring-roles",
3
- "version": "1.1.0",
3
+ "version": "1.1.2",
4
4
  "description": "Module for managing user roles",
5
5
  "homepage": "https://github.com/adapt-security/adapt-authoring-roles",
6
6
  "license": "GPL-3.0",
@@ -12,15 +12,15 @@
12
12
  "adapt-authoring-core": "github:adapt-security/adapt-authoring-core"
13
13
  },
14
14
  "devDependencies": {
15
- "standard": "^17.1.0",
16
- "@semantic-release/commit-analyzer": "^9.0.2",
15
+ "@semantic-release/commit-analyzer": "^13.0.1",
17
16
  "@semantic-release/git": "^10.0.1",
18
- "@semantic-release/github": "^8.0.5",
19
- "@semantic-release/npm": "^9.0.1",
20
- "@semantic-release/release-notes-generator": "^10.0.3",
21
- "conventional-changelog-eslint": "^3.0.9",
22
- "semantic-release": "^21.0.1",
23
- "semantic-release-replace-plugin": "^1.2.7"
17
+ "@semantic-release/github": "^12.0.2",
18
+ "@semantic-release/npm": "^13.1.2",
19
+ "@semantic-release/release-notes-generator": "^14.1.0",
20
+ "conventional-changelog-eslint": "^6.0.0",
21
+ "semantic-release": "^25.0.2",
22
+ "semantic-release-replace-plugin": "^1.2.7",
23
+ "standard": "^17.1.0"
24
24
  },
25
25
  "release": {
26
26
  "plugins": [