vote optimizes the election

Skriven av ekmartin

Våren 2014 ble det tatt i bruk et digitalt stemmesystem ved Abakus’ Generalforsamling. Det ble for det meste godt mottatt, men hadde et par problemer det måtte ordnes opp i. Nå er versjon to av vote klar for lansering og tilgjengelig på GitHub.

GitHub

I motsetning til i fjor står vote nå på egne ben, og er helt uavhengig av abakus.no. Stemmesystemet er et av temaene på diskusjonskvelden i dag (fredag den 20.), og her vil det også holdes en demoavstemning. Dersom du finner feil i systemet kan dette gjerne tas opp der, via en issue på GitHub, eller på mail til webkom@abakus.no.

Selv om sikkerhet har stått i fokus under utviklingsprosessen har også målet om å oppnå en bra brukeropplevelse vært sentralt. vote er designet med responsivitet i tankene og skal dermed fungere optimalt på mobile enheter. Det skal være enkelt å stemme, med så få manuelle handlinger som mulig. Nye avstemninger lastes inn automatisk, og brukeren blir plassert rett inn i listen med alternativer.

vote

Det å spare tid har alltid vært hovedmålet med et digitalt stemmesytem. Ved papirstemming går mye tid med på innhenting og opptelling av stemmer, noe du naturligvis slipper med digital avstemning. Likevel risikerer man nye forsinkelser ved å ta i bruk et system som vote, og det å minimere disse og gjøre prosessen så smidig som mulig har vært et viktig mål.

Et av forbedringsforslagene på forrige diskusjonskveld var å gi hver bruker et nøkkelkort, som de så kan bruke når de skal gå inn og ut av lokalet. Dette gjør jobben enklere for de ansvarlige og passer på at kun tilstedeværende kan stemme. Det å lage nye avstemninger, samt gjøre opptelling av disse, har også blitt forenklet. vote skal være et nyttig og diskret verktøy, uten å bli et frustrasjonsmoment for de som bruker det.

Implementasjon

vote er skrevet i Node.js, med den såkalte MEAN-stacken. Dette innebærer at MongoDB, Express og AngularJS har blitt tatt i bruk. Express gjør det enkelt å sette opp API-er i Node, og dette fungerer bra sammen med ensidesrammeverk som AngularJS. Som et ekstra lag oppå databasen brukes Mongoose, som gjør valideringer og lignende enkelt.

Et av de potensielle sikkerhetshullene i det gamle stemmesystemet var at Abakus.no ble brukt som innloggingsmekanisme. Da vote nå er helt selvstendig og brukere registreres på Generalforsamlingen er dette problemet løst. Nøkkelkortene utdelt på stedet er også helt anonyme. I tillegg står også brukerne fritt til å velge sitt eget brukernavn, samt et passord de tar i bruk for å logge inn senere.

I løpet av selve stemmeprosessen lagres det heller aldri noen knytning mellom brukeridentiteter og avgitte stemmer. I stedet lages det en hash av brukernavnet, avstemningen og en hemmelig nøkkel:

exports.createHash = function(username, electionId) {
    var appSecret = process.env.APP_SECRET || 'dev_secret';
    var hash = crypto.createHash('sha512');
    hash.setEncoding('hex');
    hash.write(username);
    hash.write(String(electionId));
    hash.write(appSecret);
    hash.end();

    var createdHash = hash.read();
    return createdHash;
};

Når så systemet skal finne ut av om en bruker har stemt tidligere lages hashen på nytt, og dersom det allerede finnes en identisk hash i databasen blir stemmen avvist. I tillegg gjør dette at en stemme ikke kan knyttes tilbake til en enkelt bruker ved et senere tidspunkt. Alternativet en bruker stemmer på sendes heller aldri i klartekst i URL-en, da den legges ved i selve POST-forespørselen. Dette gjør at den blir kryptert når applikasjonen tar i bruk HTTPS.

Tester

Selvom gode tester alltid står i fokus for Webkomprosjekter har det kanskje vært et ekstra viktig arbeidsområde for vote. Med en testdekning tilnærmet lik 100% minker sannsynligheten for uventede hendelser, samtidig som det legger til rette for at all funksjonalitet er dokumentert i tester.

Da vote har en adskilt frontend og backend har det også vært en utfordring å opprettholde tester for begge deler. Dette har resultert i hovedsakelig to typer tester: API-tester mot serveren, samt ende-til-ende-tester i nettleseren.

Ved å ta i bruk supertest og mocha til API-testene kan de ulike endepunktenes ønskede returverdier enkelt sjekkes (kilde):

it('should not be possible to vote without logging in', function(done) {
    passportStub.logout();
    request(app)
        .post('/api/vote')
        .send(votePayload(this.activeAlternative.id))
        .expect(401)
        .expect('Content-Type', /json/)
        .end(function(err, res) {
            if (err) return done(err);

            var error = res.body;
            error.status.should.equal(401);
            error.message.should.equal('You need to be logged in to access this resource.');
            done();
        });
});

Det å teste frontendkoden, altså det som kjøres i nettleseren, er litt vanskeligere. Dette gjøres med Protractor, for å sjekke at nettsiden reagerer på riktig måte når f.eks. en bruker trykker på et alternativ og prøver å stemme. Her tar vi også i bruk cucumber-js, som lar oss definere frontend-funksjonalitet på følgende måte (kilde):

Scenario: Add alternatives
  Given There is an inactive election
  And I am on the edit election page
  When I enter a new alternative "Alternative"
  And I click "Legg til alternativ"
  Then I should see the alternative "Alternative"

Hver av setningene hører så til et steg i testen, som du kan se her. Testene vil så kunne kjøres i en faktisk nettleser:

frontend tests

Bidrag

Det er fortsatt to uker igjen til Generalforsamlingen går av stabelen, og vi tar gjerne imot pull-requests dersom du har forbedringsforslag. For å gjøre dette må du lage en fork av prosjektet - les mer her. Send oss en mail på webkom@abakus.no dersom du lurer på noe!

← Attende