diff --git a/web/backend/readme.md b/web/backend/readme.md index 54a5a0529..455e3f7eb 100644 --- a/web/backend/readme.md +++ b/web/backend/readme.md @@ -59,5 +59,6 @@ Commands: addAdmin [options] Given a SCIPER number, the owner would gain full admin permissions listUserPermissions [options] Lists the permissions -if any- of the owner of a given SCIPER removeAdmin [options] Given a SCIPER number, the owner would lose all admin privileges -if any- + addVoters [options] Assigns a list of SCIPERs to an Election as Voters help [command] display help for command ``` diff --git a/web/backend/src/.voters.example b/web/backend/src/.voters.example new file mode 100644 index 000000000..ae27e0360 --- /dev/null +++ b/web/backend/src/.voters.example @@ -0,0 +1,2 @@ +123456 +321451 \ No newline at end of file diff --git a/web/backend/src/cli.ts b/web/backend/src/cli.ts old mode 100644 new mode 100755 index 51445b1d6..3a37593e4 --- a/web/backend/src/cli.ts +++ b/web/backend/src/cli.ts @@ -7,10 +7,12 @@ Backend CLI, currently providing 3 commands for user management: npx cli removeAdmin --sciper 1234 */ -import { Command } from 'commander'; +import { Command, InvalidArgumentError } from 'commander'; import { SequelizeAdapter } from 'casbin-sequelize-adapter'; import { newEnforcer } from 'casbin'; import { curve } from '@dedis/kyber'; +import * as fs from 'fs'; +import { PERMISSIONS } from './authManager'; const program = new Command(); @@ -78,4 +80,36 @@ program console.log(`PUBLIC_KEY=${pub}`); }); +// Imports a list of SCIPERS from a file to allow to vote on a specific election +// the .voters.example file is available as an example +program + .command('addVoters') + .description('Assigns a list of SCIPERs to an Election as Voters') + .requiredOption('-e, --election-id ', 'ID of the election') + .requiredOption('-sf, --scipers-file ', 'File with line-separated list of SCIPERs') + .action(async ({ electionId, scipersFile }) => { + fs.readFile(scipersFile, 'utf8', async (err: any, data: string) => { + if (err) { + throw new InvalidArgumentError(`Faced a problem trying to process your file: \n ${err}`); + } + const scipers: Array = data.split('\n'); + const policies = []; + for (let i = 0; i < scipers.length; i += 1) { + const sciper: number = Number(scipers[i]); + if (Number.isNaN(sciper)) { + throw new InvalidArgumentError(`SCIPER '${sciper}' on line ${i + 1} is not a number`); + } + if (sciper > 999999 || sciper < 100000) { + throw new InvalidArgumentError( + `SCIPER '${sciper}' on line ${i + 1} is outside acceptable range (100000..999999)` + ); + } + policies[i] = [scipers[i], electionId, PERMISSIONS.ACTIONS.VOTE]; + } + const enforcer = await initEnforcer(); + await enforcer.addPolicies(policies); + console.log('Added Voting policies successfully!'); + }); + }); + program.parse(); diff --git a/web/backend/src/controllers/dela.ts b/web/backend/src/controllers/dela.ts index bc1a4626b..7253e4932 100644 --- a/web/backend/src/controllers/dela.ts +++ b/web/backend/src/controllers/dela.ts @@ -49,8 +49,8 @@ function sendToDela(dataStr: string, req: express.Request, res: express.Response let uri = process.env.DELA_NODE_URL + req.baseUrl.slice(4); // boolean to check let redirectToDefaultProxy = true; - // in case this is a DKG init request, we must also update the payload. + // in case this is a DKG init request, we must also update the payload. const dkgInitRegex = /\/evoting\/services\/dkg\/actors$/; if (uri.match(dkgInitRegex)) { const dataStr2 = JSON.stringify({ FormID: req.body.FormID }); @@ -154,6 +154,7 @@ delaRouter.post('/services/dkg/actors', (req, res, next) => { } next(); }); + delaRouter.use('/services/dkg/actors/:formID', (req, res, next) => { const { formID } = req.params; if (!isAuthorized(req.session.userId, formID, PERMISSIONS.ACTIONS.OWN)) { @@ -162,6 +163,7 @@ delaRouter.use('/services/dkg/actors/:formID', (req, res, next) => { } next(); }); + delaRouter.use('/services/shuffle/:formID', (req, res, next) => { if (!req.session.userId) { res.status(401).send('Unauthenticated'); @@ -174,6 +176,32 @@ delaRouter.use('/services/shuffle/:formID', (req, res, next) => { } next(); }); + +delaRouter.post('/forms/:formID/vote', (req, res) => { + if (!req.session.userId) { + res.status(401).send('Authentication required!'); + return; + } + if (!isAuthorized(req.session.userId, req.params.formID, PERMISSIONS.ACTIONS.VOTE)) { + res.status(400).send('Unauthorized'); + return; + } + + // We must set the UserID to know who this ballot is associated to. This is + // only needed to allow users to cast multiple ballots, where only the last + // ballot is taken into account. To preserve anonymity, the web-backend could + // translate UserIDs to another random ID. + // bodyData.UserID = req.session.userId.toString(); + + // DEBUG: this is only for debugging and needs to be replaced before production + const bodyData = req.body; + console.warn('DEV CODE - randomizing the SCIPER ID to allow for unlimited votes'); + bodyData.UserID = makeid(10); + + const dataStr = JSON.stringify(bodyData); + sendToDela(dataStr, req, res); +}); + delaRouter.delete('/forms/:formID', (req, res) => { if (!req.session.userId) { res.status(401).send('Unauthenticated'); @@ -235,18 +263,6 @@ delaRouter.use('/*', (req, res) => { } const bodyData = req.body; - - // special case for voting - const regex = /\/api\/evoting\/forms\/.*\/vote/; - if (req.baseUrl.match(regex)) { - // We must set the UserID to know who this ballot is associated to. This is - // only needed to allow users to cast multiple ballots, where only the last - // ballot is taken into account. To preserve anonymity the web-backend could - // translate UserIDs to another random ID. - // bodyData.UserID = req.session.userId.toString(); - bodyData.UserID = makeid(10); - } - const dataStr = JSON.stringify(bodyData); sendToDela(dataStr, req, res); diff --git a/web/backend/src/controllers/users.ts b/web/backend/src/controllers/users.ts index e1ec6b060..723848b58 100644 --- a/web/backend/src/controllers/users.ts +++ b/web/backend/src/controllers/users.ts @@ -39,7 +39,6 @@ usersRouter.post('/add_role', (req, res, next) => { }); // This call (only for admins) allow an admin to remove a role to a user. - usersRouter.post('/remove_role', (req, res, next) => { if (!isAuthorized(req.session.userId, PERMISSIONS.SUBJECTS.ROLES, PERMISSIONS.ACTIONS.REMOVE)) { res.status(400).send('Unauthorized - only admins allowed');