diff --git a/app/controllers/BallotboxApi.scala b/app/controllers/BallotboxApi.scala index e249d5e..0d18c7f 100644 --- a/app/controllers/BallotboxApi.scala +++ b/app/controllers/BallotboxApi.scala @@ -58,6 +58,7 @@ object BallotboxApi extends Controller with Response { } } val boothSecret = Play.current.configuration.getString("elections.auth.secret").get + val voterTokenExpiry = Play.current.configuration.getString("elections.auth.expiry").get.toLong /** cast a vote, performs several validations, see vote.validate */ def vote(electionId: Long, voterId: String) = @@ -87,10 +88,19 @@ object BallotboxApi extends Controller with Response { else { val configJson = Json.parse(election.configuration) val presentation = configJson.validate[ElectionConfig].get.presentation + val authorizationHeader = request.headers.get("Authorization").get + val tokenTimestamp = ActionHelper(authorizationHeader).getTokenTime + val insideGracePeriod = ( + election.endDate.isDefined && + tokenTimestamp.isDefined && + election.endDate.get.getTime / 1000 + voterTokenExpiry > tokenTimestamp.get + ) + val gracefulEnd = ( presentation.extra_options.isDefined && presentation.extra_options.get.allow_voting_end_graceful_period.isDefined && - presentation.extra_options.get.allow_voting_end_graceful_period.get == true + presentation.extra_options.get.allow_voting_end_graceful_period.get == true && + insideGracePeriod ) if( election.state == Elections.STARTED || diff --git a/app/utils/Actions.scala b/app/utils/Actions.scala index fd14af8..6354901 100644 --- a/app/utils/Actions.scala +++ b/app/utils/Actions.scala @@ -24,6 +24,34 @@ import play.api._ import play.api.libs.concurrent.Execution.Implicits.defaultContext import play.api.libs.{Crypto => PlayCrypto} +case class ActionHelper(authorizationHeader: String) { + def getTokenTime(): Option[Long] = { + val start = "khmac:///sha-256;"; + val slashPos = start.length + 64; + + if( + !authorizationHeader.startsWith(start) || + authorizationHeader.length < slashPos || + authorizationHeader.charAt(slashPos) != '/' + ) { + Logger.warn(s"Malformed authorization header") + return None + } + + val hash = authorizationHeader.substring(start.length, slashPos) + val message = authorizationHeader.substring(slashPos + 1) + + val split = message.split(':') + if (split.length < 7) { + Logger.warn(s"Malformed authorization header") + return None + } + + val rcvTime = split(split.length - 1).toLong + return Some(rcvTime) + } +} + case class HMACActionHelper( userId: String, objType: String, @@ -223,3 +251,4 @@ object LoggingFilter extends Filter { } } } +