feat: inplement auth for runs and runCases

This commit is contained in:
Takeshi Kimata
2024-06-08 08:52:19 +09:00
parent 07259f6daf
commit 2b5a806aee
24 changed files with 293 additions and 67 deletions

View File

@@ -4,6 +4,7 @@ const defineMember = require('../models/members');
const defineProject = require('../models/projects');
const defineFolder = require('../models/folders');
const defineCase = require('../models/cases');
const defineRun = require('../models/runs');
function verifyEditableMiddleware(sequelize) {
/**
@@ -195,12 +196,99 @@ function verifyEditableMiddleware(sequelize) {
return false;
}
/**
* Verify user is reporter of the project by projectId
* (have to be called after verifySignedIn() middleware)
*/
async function verifyProjectReporterFromProjectId(req, res, next) {
const projectId = req.params.projectId || req.query.projectId;
if (!projectId) {
return res.status(400).json({ error: 'projectId is required' });
}
const isReporterRet = await isReporter(projectId, req.userId);
if (isReporterRet) {
next();
return;
}
return res.status(403).json({ error: 'Forbidden' });
}
/**
* Verify user is reporter of the project by runId
* (have to be called after verifySignedIn() middleware)
*/
async function verifyProjectReporterFromRunId(req, res, next) {
const Run = defineRun(sequelize, DataTypes);
const runId = req.params.runId || req.query.runId;
if (!runId) {
return res.status(400).json({ error: 'runId is required' });
}
// find project id from runId
const run = await Run.findByPk(runId);
const projectId = run && run.id;
if (!projectId) {
return res.status(404).send('failed to find projectId');
}
const isReporterRet = await isReporter(projectId, req.userId);
if (isReporterRet) {
next();
return;
}
return res.status(403).json({ error: 'Forbidden' });
}
async function isReporter(projectId, userId) {
const Project = defineProject(sequelize, DataTypes);
const Member = defineMember(sequelize, DataTypes);
Project.hasMany(Member, { foreignKey: 'projectId' });
Member.belongsTo(Project, { foreignKey: 'projectId' });
const project = await Project.findOne({
where: { id: projectId },
include: [
{
model: Member,
where: { userId: userId },
required: false,
},
],
});
if (!project) {
return false;
}
// owner has reporter or higher authority
if (project.userId === userId) {
return true;
}
const member = project.Members && project.Members[0];
if (member) {
const managerRoleIndex = memberRoles.findIndex((entry) => entry.uid === 'manager');
const developerRoleIndex = memberRoles.findIndex((entry) => entry.uid === 'developer');
const reporterRoleIndex = memberRoles.findIndex((entry) => entry.uid === 'reporter');
if (member.role === managerRoleIndex || member.role === developerRoleIndex || member.role === reporterRoleIndex) {
return true;
}
}
return false;
}
return {
verifyProjectOwner,
verifyProjectManagerFromProjectId,
verifyProjectDeveloperFromProjectId,
verifyProjectDeveloperFromFolderId,
verifyProjectDeveloperFromCaseId,
verifyProjectReporterFromProjectId,
verifyProjectReporterFromRunId,
};
}

View File

@@ -3,6 +3,7 @@ const defineMember = require('../models/members');
const defineProject = require('../models/projects');
const defineFolder = require('../models/folders');
const defineCase = require('../models/cases');
const defineRun = require('../models/runs');
function verifyVisibleMiddleware(sequelize) {
/**
@@ -88,6 +89,34 @@ function verifyVisibleMiddleware(sequelize) {
return res.status(403).json({ error: 'Forbidden' });
}
/**
* Verify user can read project by runId
* (have to be called after verifySignedIn() middleware)
*/
async function verifyProjectVisibleFromRunId(req, res, next) {
const Run = defineRun(sequelize, DataTypes);
const runId = req.params.runId || req.query.runId;
if (!runId) {
return res.status(400).json({ error: 'runId is required' });
}
// find project id from runId
const run = await Run.findByPk(runId);
const projectId = run && run.id;
if (!projectId) {
return res.status(404).send('failed to find projectId');
}
const isVisble = await isVisible(projectId, req.userId);
if (isVisble) {
next();
return;
}
return res.status(403).json({ error: 'Forbidden' });
}
async function isVisible(projectId, userId) {
const Project = defineProject(sequelize, DataTypes);
const Member = defineMember(sequelize, DataTypes);
@@ -128,6 +157,7 @@ function verifyVisibleMiddleware(sequelize) {
verifyProjectVisibleFromProjectId,
verifyProjectVisibleFromFolderId,
verifyProjectVisibleFromCaseId,
verifyProjectVisibleFromRunId,
};
}

View File

@@ -5,10 +5,14 @@ const { DataTypes, Op } = require('sequelize');
module.exports = function (sequelize) {
const RunCase = defineRunCase(sequelize, DataTypes);
const { verifySignedIn } = require('../../middleware/auth')(sequelize);
const { verifyProjectReporterFromRunId } = require('../../middleware/verifyEditable')(sequelize);
router.post('/bulkdelete', async (req, res) => {
router.post('/bulkdelete', verifySignedIn, verifyProjectReporterFromRunId, async (req, res) => {
const recordsToDelete = req.body;
// TODO Instead of receiving a combination of runId and caseId from frontend,
// receives only an array of caseId and constructs a pair from the query parameter runId
try {
const existingRunCases = await RunCase.findAll({
where: {

View File

@@ -4,11 +4,15 @@ const defineRunCase = require('../../models/runCases');
const { DataTypes, Op } = require('sequelize');
module.exports = function (sequelize) {
const { verifySignedIn } = require('../../middleware/auth')(sequelize);
const { verifyProjectReporterFromRunId } = require('../../middleware/verifyEditable')(sequelize);
const RunCase = defineRunCase(sequelize, DataTypes);
router.post('/bulknew', async (req, res) => {
router.post('/bulknew', verifySignedIn, verifyProjectReporterFromRunId, async (req, res) => {
const recordsToCreate = req.body;
// TODO Instead of receiving a combination of runId and caseId from frontend,
// receives only an array of caseId and constructs a pair from the query parameter runId
try {
const existingRunCases = await RunCase.findAll({
where: {

View File

@@ -4,9 +4,11 @@ const defineRunCase = require('../../models/runCases');
const { DataTypes } = require('sequelize');
module.exports = function (sequelize) {
const { verifySignedIn } = require('../../middleware/auth')(sequelize);
const { verifyProjectReporterFromRunId } = require('../../middleware/verifyEditable')(sequelize);
const RunCase = defineRunCase(sequelize, DataTypes);
router.delete('/', async (req, res) => {
router.delete('/', verifySignedIn, verifyProjectReporterFromRunId, async (req, res) => {
const runId = req.query.runId;
const caseId = req.query.caseId;

View File

@@ -4,9 +4,11 @@ const defineRunCase = require('../../models/runCases');
const { DataTypes } = require('sequelize');
module.exports = function (sequelize) {
const { verifySignedIn } = require('../../middleware/auth')(sequelize);
const { verifyProjectReporterFromRunId } = require('../../middleware/verifyEditable')(sequelize);
const RunCase = defineRunCase(sequelize, DataTypes);
router.put('/', async (req, res) => {
router.put('/', verifySignedIn, verifyProjectReporterFromRunId, async (req, res) => {
const runId = req.query.runId;
const caseId = req.query.caseId;
const status = req.query.status;

View File

@@ -4,9 +4,11 @@ const defineRunCase = require('../../models/runCases');
const { DataTypes } = require('sequelize');
module.exports = function (sequelize) {
const { verifySignedIn } = require('../../middleware/auth')(sequelize);
const { verifyProjectVisibleFromRunId } = require('../../middleware/verifyVisible')(sequelize);
const RunCase = defineRunCase(sequelize, DataTypes);
router.get('/', async (req, res) => {
router.get('/', verifySignedIn, verifyProjectVisibleFromRunId, async (req, res) => {
const { runId } = req.query;
if (!runId) {

View File

@@ -4,9 +4,11 @@ const defineRunCase = require('../../models/runCases');
const { DataTypes } = require('sequelize');
module.exports = function (sequelize) {
const { verifySignedIn } = require('../../middleware/auth')(sequelize);
const { verifyProjectReporterFromRunId } = require('../../middleware/verifyEditable')(sequelize);
const RunCase = defineRunCase(sequelize, DataTypes);
router.post('/', async (req, res) => {
router.post('/', verifySignedIn, verifyProjectReporterFromRunId, async (req, res) => {
const runId = req.query.runId;
const caseId = req.query.caseId;

View File

@@ -4,9 +4,11 @@ const defineRun = require('../../models/runs');
const { DataTypes } = require('sequelize');
module.exports = function (sequelize) {
const { verifySignedIn } = require('../../middleware/auth')(sequelize);
const { verifyProjectReporterFromRunId } = require('../../middleware/verifyEditable')(sequelize);
const Run = defineRun(sequelize, DataTypes);
router.delete('/:runId', async (req, res) => {
router.delete('/:runId', verifySignedIn, verifyProjectReporterFromRunId, async (req, res) => {
const runId = req.params.runId;
try {
const testrun = await Run.findByPk(runId);

View File

@@ -5,8 +5,10 @@ const { DataTypes } = require('sequelize');
module.exports = function (sequelize) {
const Run = defineRun(sequelize, DataTypes);
const { verifySignedIn } = require('../../middleware/auth')(sequelize);
const { verifyProjectReporterFromRunId } = require('../../middleware/verifyEditable')(sequelize);
router.put('/:runId', async (req, res) => {
router.put('/:runId', verifySignedIn, verifyProjectReporterFromRunId, async (req, res) => {
const runId = req.params.runId;
const updateRun = req.body;
try {

View File

@@ -4,9 +4,11 @@ const defineRun = require('../../models/runs');
const { DataTypes } = require('sequelize');
module.exports = function (sequelize) {
const { verifySignedIn } = require('../../middleware/auth')(sequelize);
const { verifyProjectVisibleFromProjectId } = require('../../middleware/verifyVisible')(sequelize);
const Run = defineRun(sequelize, DataTypes);
router.get('/', async (req, res) => {
router.get('/', verifySignedIn, verifyProjectVisibleFromProjectId, async (req, res) => {
const { projectId } = req.query;
if (!projectId) {

View File

@@ -4,11 +4,14 @@ const defineRun = require('../../models/runs');
const { DataTypes } = require('sequelize');
module.exports = function (sequelize) {
const { verifySignedIn } = require('../../middleware/auth')(sequelize);
const { verifyProjectReporterFromProjectId } = require('../../middleware/verifyEditable')(sequelize);
const Run = defineRun(sequelize, DataTypes);
router.post('/', async (req, res) => {
router.post('/', verifySignedIn, verifyProjectReporterFromProjectId, async (req, res) => {
try {
const { name, configurations, description, state, projectId } = req.body;
const projectId = req.query.projectId;
const { name, configurations, description, state } = req.body;
if (!name || !projectId) {
return res.status(400).json({ error: 'Name and projectId are required' });
}

View File

@@ -5,10 +5,12 @@ const defineRunCase = require('../../models/runCases');
const { DataTypes, literal } = require('sequelize');
module.exports = function (sequelize) {
const { verifySignedIn } = require('../../middleware/auth')(sequelize);
const { verifyProjectVisibleFromRunId } = require('../../middleware/verifyVisible')(sequelize);
const Run = defineRun(sequelize, DataTypes);
const RunCase = defineRunCase(sequelize, DataTypes);
router.get('/:runId', async (req, res) => {
router.get('/:runId', verifySignedIn, verifyProjectVisibleFromRunId, async (req, res) => {
const runId = req.params.runId;
if (!runId) {