diff --git a/SequentConfig.js b/SequentConfig.js index 26a29709..63f0afe9 100644 --- a/SequentConfig.js +++ b/SequentConfig.js @@ -137,8 +137,6 @@ var SequentConfigData = { // Default: '/admin/login' defaultRoute: '/admin/login', - timeoutSeconds: 3600, - publicURL: "https://sequent/elections/public/", // if we are in debug mode or not @@ -224,7 +222,10 @@ var SequentConfigData = { }, mainVersion: '8.0.0', - repoVersions: [] + repoVersions: [], + + // Number of seconds after which an authentication token expires. + authTokenExpirationSeconds: 600 }; angular.module('SequentConfig', []) diff --git a/avBooth/booth-directive/booth-directive.js b/avBooth/booth-directive/booth-directive.js index de2df643..0558c9a7 100644 --- a/avBooth/booth-directive/booth-directive.js +++ b/avBooth/booth-directive/booth-directive.js @@ -222,63 +222,6 @@ angular.module('avBooth') ); } - // After cookies expires, redirect to login. But only if cookies do - // expire. - function autoredirectToLoginAfterTimeout() { - // demo and live preview don't need to expire - if (scope.isDemo || scope.isPreview) { - return; - } - - var election = ( - (!!scope.parentElection) ? - scope.parentElection : - scope.election - ); - - if ( - ConfigService.cookies.expires && - ( - !election || - !election.presentation || - !election.presentation.extra_options || - !election.presentation.extra_options.booth_log_out__disable - ) - ) { - var minutes = ConfigService.cookies.expires; - setTimeout( - function () { logoutAndRedirect( /* isSuccess */ false); }, - 60*1000*minutes - ); - - setTimeout( - function () { - $modal.open({ - ariaLabelledBy: 'modal-title', - ariaDescribedBy: 'modal-body', - templateUrl: "avBooth/invalid-answers-controller/invalid-answers-controller.html", - controller: "InvalidAnswersController", - size: 'sm', - resolve: { - errors: function() { return []; }, - data: function() { - return { - errors: [], - header: "avBooth.logoutWarnModal.header", - body: "avBooth.logoutWarnModal.body", - continue: "avBooth.logoutWarnModal.confirm" - }; - } - } - }); - }, - 60*1000*(minutes - 1) - ); - - } - } - autoredirectToLoginAfterTimeout(); - function checkCookies(electionId) { if (scope.isDemo || scope.isPreview) { return; @@ -750,6 +693,78 @@ angular.module('avBooth') scope.isDemo = false; } + var startTimeMs = Date.now(); + + function getSessionStartTime() { + readVoteCredentials(); + return scope.currentElectionCredentials && scope.currentElectionCredentials.sessionStartedAtMs || startTimeMs; + } + + // After cookies expires, redirect to login. But only if cookies do + // expire. + function autoredirectToLoginAfterTimeout() { + // demo and live preview don't need to expire + if (scope.isDemo || scope.isPreview) { + return; + } + + var election = ( + (!!scope.parentElection) ? + scope.parentElection : + scope.election + ); + + if ( + ConfigService.authTokenExpirationSeconds && + ( + !election || + !election.presentation || + !election.presentation.extra_options || + !election.presentation.extra_options.booth_log_out__disable + ) + ) { + + var logoutTimeMs = getSessionStartTime() + ConfigService.authTokenExpirationSeconds * 1000; + + setTimeout( + function () { logoutAndRedirect( /* isSuccess */ false); }, + Math.max(logoutTimeMs - Date.now(), 0) + ); + + var modalTimeMs = logoutTimeMs - 60 * 1000; + + if (modalTimeMs < Date.now()) { + return; + } + + setTimeout( + function () { + $modal.open({ + ariaLabelledBy: 'modal-title', + ariaDescribedBy: 'modal-body', + templateUrl: "avBooth/invalid-answers-controller/invalid-answers-controller.html", + controller: "InvalidAnswersController", + size: 'sm', + resolve: { + errors: function() { return []; }, + data: function() { + return { + errors: [], + header: "avBooth.logoutWarnModal.header", + body: "avBooth.logoutWarnModal.body", + continue: "avBooth.logoutWarnModal.confirm" + }; + } + } + }); + }, + modalTimeMs - Date.now() + ); + + } + } + autoredirectToLoginAfterTimeout(); + function simpleGetElection(electionId) { if (!electionId) { var future = $q.defer(); @@ -1144,6 +1159,7 @@ angular.module('avBooth') next: next, redirectToLogin: redirectToLogin, checkFixToBottom: checkFixToBottom, + getSessionStartTime: getSessionStartTime, // stateData stores information used by the directive being shown. // Its content depends on the current state. diff --git a/locales/ca.json b/locales/ca.json index 88593075..3480aaff 100644 --- a/locales/ca.json +++ b/locales/ca.json @@ -44,6 +44,11 @@ "showPdf": { "showPdfButton": "Mostrar PDF" }, + "countdownTooltip": { + "title": "La teva sessió expirarà.", + "contentMins": "Tens __mins__ minuts per a emetre el teu vot.", + "contentSecs": "Tens __secs__ segons per a emetre el teu vot." + }, "hashForVoteNotCastModal": { "header": "Vot no emès", "body": "Està a punt de copiar el Localitzador de el Cot, però el seu vot encara no s'ha emès. Si voleu buscar el Localitzador de el Vot, no el trobarà. Qual la raó per la que vam mostrar el Localitzador de l'Vot en aquest moment és perquè pugui auditar la correcció de l'vot xifrat abans d'emetre'l. Si aquesta és la raó per la qual vol copiar el Localitzador de l'Vot, procedeixi a copiar-lo i després auditi el seu vot.", diff --git a/locales/en.json b/locales/en.json index f96554b6..6873f261 100644 --- a/locales/en.json +++ b/locales/en.json @@ -40,6 +40,11 @@ "showPdfButton": "Show PDF", "pdfTextDescription": "Please read the PDF before voting" }, + "countdownTooltip": { + "title": "Your session is going to expire.", + "contentMins": "You have __mins__ minutes left to cast your vote.", + "contentSecs": "You have __secs__ seconds left to cast your vote." + }, "electionChooser": { "hasVoted": { "title": "Success!", diff --git a/locales/es.json b/locales/es.json index f80c4ec3..becb3a07 100644 --- a/locales/es.json +++ b/locales/es.json @@ -41,6 +41,11 @@ "showPdfButton": "Mostrar PDF", "pdfTextDescription": "Por favor lea el PDF antes de votar" }, + "countdownTooltip": { + "title": "Tu sesión va a expirar.", + "contentMins": "Tienes __mins__ minutos para emitir tu voto.", + "contentSecs": "Tienes __secs__ segundos para emitir tu voto." + }, "demoModeModal": { "header": "Cabina de votación de demo", "body": "Está ingresando a una cabina de votación de demostración. Su voto NO se emitirá. Esta cabina de votación solo tiene fines demostrativos.", diff --git a/locales/fi.json b/locales/fi.json index 933b2a78..574cf419 100644 --- a/locales/fi.json +++ b/locales/fi.json @@ -44,6 +44,11 @@ "body": "No puede continuarse porque la papeleta no es paritaria y en cremallera. Por favor, comprueba que tu selección esté compuesta de forma que detrás de una mujer luego va un hombre y así sucesivamente.", "continue": "Revisar mi papeleta" }, + "countdownTooltip": { + "title": "Istunnon vanhenemisaika lähestyy.", + "contentMins": "Sinulla on __mins__ minuuttia aikaa äänestyksen tekemiseen.", + "contentSecs": "Sinulla on __secs__ sekuntia aikaa äänestyksen tekemiseen." + }, "thisisATest": " HUOM! Tämä on testiäänestys", "loadingElectionTitle": "Vaalin tiedot latautuu. Odota, kiitos... ", "stepNumber": "vaihe __num__ yhteensä __total__ vaiheesta", diff --git a/locales/fr.json b/locales/fr.json index 2232752b..ab08a8ff 100644 --- a/locales/fr.json +++ b/locales/fr.json @@ -39,6 +39,11 @@ "showPdfButton": "Afficher le PDF", "pdfTextDescription": "Veuillez lire le PDF avant de voter" }, + "countdownTooltip": { + "title": "Votre session expire bientôt.", + "contentMins": "Il vous reste __mins__ minutes pour voter.", + "contentSecs": "Il vous reste __secs__ secondes pour voter." + }, "electionChooser": { "hasVoted": { "title": "Succ\u00e8s !", diff --git a/locales/gl.json b/locales/gl.json index 7984e761..9e33ffe9 100644 --- a/locales/gl.json +++ b/locales/gl.json @@ -32,6 +32,11 @@ "showPdf": { "showPdfButton": "Mostrar PDF" }, + "countdownTooltip": { + "title": "A túa sesión vai expirar.", + "contentMins": "Tes __mins__ minutos para emitir o teu voto.", + "contentSecs": "Tes __secs__ segundos para emitir o teu voto." + }, "confirmAuditBallot": { "header": "¿Realmente quieres auditar tu papeleta?", "body": "La auditoría de la papeleta lo invalidará y tendrás que iniciar el proceso de votación de nuevo si deseas emitir tu voto. El proceso de auditoría de la papeleta permite verificar que está codificada correctamente. Hacer este proceso requiere que unos conocimientos técnicos importantes, por lo que no se recomienda si no sabes lo que estás haciendo.

Si lo que desea es emitir su voto, en Cancelar para volver a la pantalla de revisión de votación.", diff --git a/locales/sv.json b/locales/sv.json index b70be964..b4927b49 100644 --- a/locales/sv.json +++ b/locales/sv.json @@ -36,6 +36,11 @@ "body": "Ifall du kontrollerar din röst annulleras din tidigare röst och du måste lagra en ny. Kontrollen ger dit möjligheten att se till att din röst verkligen har registrerats i den elektroniska valurnan. Att göra detta kräver tekniskt kunnande, så undvik att göra det ifall du inte är säker på vad du gör.

Ifall du enbart vill lagra din röst, klicka på Avbryt för att återgå till vyn över röstens sammandrag.", "confirm": "Ja, jag är säker på att jag vill ANNULLERA min tidigare röst för att kontrollera den" }, + "countdownTooltip": { + "title": "Din session kommer att gå ut.", + "contentMins": "Du har __mins__ minuter kvar att rösta.", + "contentSecs": "Du har __secs__ sekunder kvar att rösta." + }, "planchaSelect": "välj alla", "planchaDeselect": "ta bort alla val", "showSelectedOptionPoints": "(__points__ points)",