Skip to content

Commit 34ba6ca

Browse files
authored
Merge pull request #349 from dedis/feat/adds-voting-permissions
Feat: adds voting permission
2 parents 2c6c609 + b4499de commit 34ba6ca

File tree

5 files changed

+67
-15
lines changed

5 files changed

+67
-15
lines changed

web/backend/readme.md

+1
Original file line numberDiff line numberDiff line change
@@ -59,5 +59,6 @@ Commands:
5959
addAdmin [options] Given a SCIPER number, the owner would gain full admin permissions
6060
listUserPermissions [options] Lists the permissions -if any- of the owner of a given SCIPER
6161
removeAdmin [options] Given a SCIPER number, the owner would lose all admin privileges -if any-
62+
addVoters [options] Assigns a list of SCIPERs to an Election as Voters
6263
help [command] display help for command
6364
```

web/backend/src/.voters.example

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
123456
2+
321451

web/backend/src/cli.ts

100644100755
+35-1
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,12 @@ Backend CLI, currently providing 3 commands for user management:
77
npx cli removeAdmin --sciper 1234
88
*/
99

10-
import { Command } from 'commander';
10+
import { Command, InvalidArgumentError } from 'commander';
1111
import { SequelizeAdapter } from 'casbin-sequelize-adapter';
1212
import { newEnforcer } from 'casbin';
1313
import { curve } from '@dedis/kyber';
14+
import * as fs from 'fs';
15+
import { PERMISSIONS } from './authManager';
1416

1517
const program = new Command();
1618

@@ -78,4 +80,36 @@ program
7880
console.log(`PUBLIC_KEY=${pub}`);
7981
});
8082

83+
// Imports a list of SCIPERS from a file to allow to vote on a specific election
84+
// the .voters.example file is available as an example
85+
program
86+
.command('addVoters')
87+
.description('Assigns a list of SCIPERs to an Election as Voters')
88+
.requiredOption('-e, --election-id <char>', 'ID of the election')
89+
.requiredOption('-sf, --scipers-file <char>', 'File with line-separated list of SCIPERs')
90+
.action(async ({ electionId, scipersFile }) => {
91+
fs.readFile(scipersFile, 'utf8', async (err: any, data: string) => {
92+
if (err) {
93+
throw new InvalidArgumentError(`Faced a problem trying to process your file: \n ${err}`);
94+
}
95+
const scipers: Array<string> = data.split('\n');
96+
const policies = [];
97+
for (let i = 0; i < scipers.length; i += 1) {
98+
const sciper: number = Number(scipers[i]);
99+
if (Number.isNaN(sciper)) {
100+
throw new InvalidArgumentError(`SCIPER '${sciper}' on line ${i + 1} is not a number`);
101+
}
102+
if (sciper > 999999 || sciper < 100000) {
103+
throw new InvalidArgumentError(
104+
`SCIPER '${sciper}' on line ${i + 1} is outside acceptable range (100000..999999)`
105+
);
106+
}
107+
policies[i] = [scipers[i], electionId, PERMISSIONS.ACTIONS.VOTE];
108+
}
109+
const enforcer = await initEnforcer();
110+
await enforcer.addPolicies(policies);
111+
console.log('Added Voting policies successfully!');
112+
});
113+
});
114+
81115
program.parse();

web/backend/src/controllers/dela.ts

+29-13
Original file line numberDiff line numberDiff line change
@@ -49,8 +49,8 @@ function sendToDela(dataStr: string, req: express.Request, res: express.Response
4949
let uri = process.env.DELA_NODE_URL + req.baseUrl.slice(4);
5050
// boolean to check
5151
let redirectToDefaultProxy = true;
52-
// in case this is a DKG init request, we must also update the payload.
5352

53+
// in case this is a DKG init request, we must also update the payload.
5454
const dkgInitRegex = /\/evoting\/services\/dkg\/actors$/;
5555
if (uri.match(dkgInitRegex)) {
5656
const dataStr2 = JSON.stringify({ FormID: req.body.FormID });
@@ -154,6 +154,7 @@ delaRouter.post('/services/dkg/actors', (req, res, next) => {
154154
}
155155
next();
156156
});
157+
157158
delaRouter.use('/services/dkg/actors/:formID', (req, res, next) => {
158159
const { formID } = req.params;
159160
if (!isAuthorized(req.session.userId, formID, PERMISSIONS.ACTIONS.OWN)) {
@@ -162,6 +163,7 @@ delaRouter.use('/services/dkg/actors/:formID', (req, res, next) => {
162163
}
163164
next();
164165
});
166+
165167
delaRouter.use('/services/shuffle/:formID', (req, res, next) => {
166168
if (!req.session.userId) {
167169
res.status(401).send('Unauthenticated');
@@ -174,6 +176,32 @@ delaRouter.use('/services/shuffle/:formID', (req, res, next) => {
174176
}
175177
next();
176178
});
179+
180+
delaRouter.post('/forms/:formID/vote', (req, res) => {
181+
if (!req.session.userId) {
182+
res.status(401).send('Authentication required!');
183+
return;
184+
}
185+
if (!isAuthorized(req.session.userId, req.params.formID, PERMISSIONS.ACTIONS.VOTE)) {
186+
res.status(400).send('Unauthorized');
187+
return;
188+
}
189+
190+
// We must set the UserID to know who this ballot is associated to. This is
191+
// only needed to allow users to cast multiple ballots, where only the last
192+
// ballot is taken into account. To preserve anonymity, the web-backend could
193+
// translate UserIDs to another random ID.
194+
// bodyData.UserID = req.session.userId.toString();
195+
196+
// DEBUG: this is only for debugging and needs to be replaced before production
197+
const bodyData = req.body;
198+
console.warn('DEV CODE - randomizing the SCIPER ID to allow for unlimited votes');
199+
bodyData.UserID = makeid(10);
200+
201+
const dataStr = JSON.stringify(bodyData);
202+
sendToDela(dataStr, req, res);
203+
});
204+
177205
delaRouter.delete('/forms/:formID', (req, res) => {
178206
if (!req.session.userId) {
179207
res.status(401).send('Unauthenticated');
@@ -235,18 +263,6 @@ delaRouter.use('/*', (req, res) => {
235263
}
236264

237265
const bodyData = req.body;
238-
239-
// special case for voting
240-
const regex = /\/api\/evoting\/forms\/.*\/vote/;
241-
if (req.baseUrl.match(regex)) {
242-
// We must set the UserID to know who this ballot is associated to. This is
243-
// only needed to allow users to cast multiple ballots, where only the last
244-
// ballot is taken into account. To preserve anonymity the web-backend could
245-
// translate UserIDs to another random ID.
246-
// bodyData.UserID = req.session.userId.toString();
247-
bodyData.UserID = makeid(10);
248-
}
249-
250266
const dataStr = JSON.stringify(bodyData);
251267

252268
sendToDela(dataStr, req, res);

web/backend/src/controllers/users.ts

-1
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,6 @@ usersRouter.post('/add_role', (req, res, next) => {
3939
});
4040

4141
// This call (only for admins) allow an admin to remove a role to a user.
42-
4342
usersRouter.post('/remove_role', (req, res, next) => {
4443
if (!isAuthorized(req.session.userId, PERMISSIONS.SUBJECTS.ROLES, PERMISSIONS.ACTIONS.REMOVE)) {
4544
res.status(400).send('Unauthorized - only admins allowed');

0 commit comments

Comments
 (0)