diff --git a/lib/www/server/api/index.js b/lib/www/server/api/index.js index c0b4a2b..c6de556 100644 --- a/lib/www/server/api/index.js +++ b/lib/www/server/api/index.js @@ -83,7 +83,7 @@ app.map({ post: [ mw.user.logout ] }, '/version': { - get: [ mw.version.get ] + get: [ mw.auth.operations, mw.version.get ] }, '/': { get: [ mw.openapi.get ] @@ -304,10 +304,10 @@ app.map({ }, '/info/': { ':path(*)': { - get: [ mw.info.get ], - put: [ mw.auth.access.write, mw.info.put ], - post: [ mw.auth.access.write, mw.info.post ], - delete: [ mw.auth.access.write, mw.info.delete ] + get: [ mw.auth.operations, mw.info.get ], + put: [ mw.auth.operations, mw.auth.access.write, mw.info.put ], + post: [ mw.auth.operations, mw.auth.access.write, mw.info.post ], + delete: [ mw.auth.operations, mw.auth.access.write, mw.info.delete ] } }, '/queue/outgoing/': { diff --git a/lib/www/server/api/middleware/info/delete.js b/lib/www/server/api/middleware/info/delete.js index 047c951..54085d5 100644 --- a/lib/www/server/api/middleware/info/delete.js +++ b/lib/www/server/api/middleware/info/delete.js @@ -4,7 +4,7 @@ const { info } = require('../../../lib/db'); module.exports = async function (req, res, next) { try { - await info.delete(req.params.project, req.params.path, undefined, req.user.role); + await info.delete(req.params.project, req.params.path, undefined, req.user?.operations); res.status(204).send(); next(); } catch (err) { diff --git a/lib/www/server/api/middleware/info/get.js b/lib/www/server/api/middleware/info/get.js index fe2a1d4..7a38cb2 100644 --- a/lib/www/server/api/middleware/info/get.js +++ b/lib/www/server/api/middleware/info/get.js @@ -4,7 +4,7 @@ const { info } = require('../../../lib/db'); module.exports = async function (req, res, next) { try { - res.status(200).json(await info.get(req.params.project, req.params.path, req.query, req.user.role)); + res.status(200).json(await info.get(req.params.project, req.params.path, req.query, req.user?.operations)); } catch (err) { if (err instanceof TypeError) { res.status(404).json(null); diff --git a/lib/www/server/api/middleware/info/post.js b/lib/www/server/api/middleware/info/post.js index b3514b0..26d67fa 100644 --- a/lib/www/server/api/middleware/info/post.js +++ b/lib/www/server/api/middleware/info/post.js @@ -6,7 +6,7 @@ module.exports = async function (req, res, next) { try { const payload = req.body; - await info.post(req.params.project, req.params.path, payload, undefined, req.user.role); + await info.post(req.params.project, req.params.path, payload, undefined, req.user?.operations); res.status(201).send(); next(); } catch (err) { diff --git a/lib/www/server/api/middleware/info/put.js b/lib/www/server/api/middleware/info/put.js index 8e97347..e6fc215 100644 --- a/lib/www/server/api/middleware/info/put.js +++ b/lib/www/server/api/middleware/info/put.js @@ -6,7 +6,7 @@ module.exports = async function (req, res, next) { try { const payload = req.body; - await info.put(req.params.project, req.params.path, payload, undefined, req.user.role); + await info.put(req.params.project, req.params.path, payload, undefined, req.user?.operations); res.status(201).send(); next(); } catch (err) { diff --git a/lib/www/server/api/middleware/plan/list/json.js b/lib/www/server/api/middleware/plan/list/json.js index e5ee08b..131ccb1 100644 --- a/lib/www/server/api/middleware/plan/list/json.js +++ b/lib/www/server/api/middleware/plan/list/json.js @@ -4,7 +4,7 @@ const { plan, info } = require('../../../../lib/db'); const json = async function (req, res, next) { try { const sequences = await plan.list(req.params.project, req.query) ?? []; - const remarks = await info.get(req.params.project, "plan/remarks", req.query, req.user.role) ?? null; + const remarks = await info.get(req.params.project, "plan/remarks", req.query, req.user?.operations) ?? null; const response = { remarks, sequences diff --git a/lib/www/server/api/middleware/qc/results/get.js b/lib/www/server/api/middleware/qc/results/get.js index 069fef4..30aaabf 100644 --- a/lib/www/server/api/middleware/qc/results/get.js +++ b/lib/www/server/api/middleware/qc/results/get.js @@ -4,7 +4,7 @@ const { qc } = require('../../../../lib/db'); module.exports = async function (req, res, next) { try { - res.status(200).json(await qc.results.get(req.params.project, req.params.sequence, req.query, req.user.role)); + res.status(200).json(await qc.results.get(req.params.project, req.params.sequence, req.query)); } catch (err) { next(err); return; diff --git a/lib/www/server/lib/db/info/check-permission.js b/lib/www/server/lib/db/info/check-permission.js index e8dd7aa..d17b1f9 100644 --- a/lib/www/server/lib/db/info/check-permission.js +++ b/lib/www/server/lib/db/info/check-permission.js @@ -30,7 +30,7 @@ const dictionary = { config: { // Configuration (site-wide or survey) // Nobody except admin can access - _: { _: false, admin: true } + _: { _: false, edit: true } }, qc: { // QC results (survey) @@ -42,13 +42,13 @@ const dictionary = { // Equipment info (site) // Everyone can read, user + admin can alter get: { _: true }, - _ : { _: false, user: true, admin: true } + _ : { _: false, write: true, edit: true } }, contact: { // Contact details (basically an example entry) // Everyone can read, admin can alter get: { _: true }, - _ : { _: false, admin: true }, + _ : { _: false, edit: true }, } } @@ -56,7 +56,7 @@ const dictionary = { * * @a key {String} is the object of the action. * @a verb {String} is the action. - * @a role {String} is the subject of the action. + * @a operations {Array} is one of the subjects of the action. * * @returns {Boolean} `true` is the action is allowed, * `false` if it is not. @@ -67,12 +67,17 @@ const dictionary = { * by `_`, others are entered explicitly. * */ -function checkPermission (key, verb, role) { +function checkPermission (key, verb, operations) { const entry = dictionary[key] if (entry) { const action = entry[verb] ?? entry._ if (action) { - return action[role] ?? action._ ?? false; + for (const op of operations) { + if ((op in action)) { + return action[op]; + } + } + return action._ ?? false; } return false; } diff --git a/lib/www/server/lib/db/info/delete.js b/lib/www/server/lib/db/info/delete.js index d0b0c6f..0d77d55 100644 --- a/lib/www/server/lib/db/info/delete.js +++ b/lib/www/server/lib/db/info/delete.js @@ -1,11 +1,11 @@ const { setSurvey, transaction } = require('../connection'); const checkPermission = require('./check-permission'); -async function del (projectId, path, opts = {}, role) { +async function del (projectId, path, opts = {}, operations = []) { const client = await setSurvey(projectId); const [key, ...jsonpath] = (path||"").split("/").filter(i => i.length); - if (!checkPermission(key, "delete", role)) { + if (!checkPermission(key, "delete", operations)) { throw {status: 403, message: "Forbidden"}; return; } diff --git a/lib/www/server/lib/db/info/get.js b/lib/www/server/lib/db/info/get.js index 867b47c..85ff8b5 100644 --- a/lib/www/server/lib/db/info/get.js +++ b/lib/www/server/lib/db/info/get.js @@ -1,11 +1,11 @@ const { setSurvey } = require('../connection'); const checkPermission = require('./check-permission'); -async function get (projectId, path, opts = {}, role) { +async function get (projectId, path, opts = {}, operations = []) { const client = await setSurvey(projectId); const [key, ...subkey] = path.split("/").filter(i => i.trim().length); - if (!checkPermission(key, "get", role)) { + if (!checkPermission(key, "get", operations)) { throw {status: 403, message: "Forbidden"}; return; } diff --git a/lib/www/server/lib/db/info/post.js b/lib/www/server/lib/db/info/post.js index e9b79a7..b7b2f38 100644 --- a/lib/www/server/lib/db/info/post.js +++ b/lib/www/server/lib/db/info/post.js @@ -1,11 +1,11 @@ const { setSurvey, transaction } = require('../connection'); const checkPermission = require('./check-permission'); -async function post (projectId, path, payload, opts = {}, role) { +async function post (projectId, path, payload, opts = {}, operations = []) { const client = await setSurvey(projectId); const [key, ...jsonpath] = (path||"").split("/").filter(i => i.length); - if (!checkPermission(key, "post", role)) { + if (!checkPermission(key, "post", operations)) { throw {status: 403, message: "Forbidden"}; return; } diff --git a/lib/www/server/lib/db/info/put.js b/lib/www/server/lib/db/info/put.js index c1be19f..a65cd2e 100644 --- a/lib/www/server/lib/db/info/put.js +++ b/lib/www/server/lib/db/info/put.js @@ -1,11 +1,11 @@ const { setSurvey, transaction } = require('../connection'); const checkPermission = require('./check-permission'); -async function put (projectId, path, payload, opts = {}, role) { +async function put (projectId, path, payload, opts = {}, operations = []) { const client = await setSurvey(projectId); const [key, ...jsonpath] = (path??"").split("/").filter(i => i.length); - if (role !== null && !checkPermission(key, "put", role)) { + if (!checkPermission(key, "put", operations)) { throw {status: 403, message: "Forbidden"}; return; }