/*
 * Copyright 2018 Scytl Secure Electronic Voting SA
 *
 * All rights reserved
 *
 * See our extended copyright notice in *file 'Copyright.txt' which is part of this source code package
 */
/* jshint maxlen: 666  */
/* global forge */
/* global CL */


module.exports = (function() {
	
	var session = require('../client/session.js');
	var jsrsasign = require('jsrsasign');
    var _ = require('lodash');

    'use strict';
	
	var verifyBallotSignature = function(ballot,publicKeyCertificate) {
        return verifyJWSignature(ballot.signature, publicKeyCertificate);
    };

    var verifyBallotTextsSignature = function(ballotTextsSignature,publicKeyCertificate) {
        return verifyJWSignature(ballotTextsSignature, publicKeyCertificate);
    };

    var verifyBallotBoxSignature = function(ballotBox,publicKeyCertificate) {
        return verifyJWSignature(ballotBox.signature, publicKeyCertificate) && 
            verifyJWSignature(ballotBox.electoralAuthority.signature, publicKeyCertificate);
    };

    var verifyJWSignature = function(jwSignature, publicKeyCertificate) {
        var publicKey = jsrsasign.KEYUTIL.getKey(publicKeyCertificate);     
        return jsrsasign.jws.JWS.verifyJWT(jwSignature, publicKey, { alg: ['PS256']} );
    }

    var validateAuthToken = function(authToken, authenticationTokenSignerCert) {

        // verify authtoken structure
        
        var tokenSignature = authToken.signature;
        var voterInformation = authToken.voterInformation;

        if (!authToken.id ||
            !voterInformation.votingCardId ||
            !voterInformation.ballotId ||
            !voterInformation.credentialId ||
            !voterInformation.ballotBoxId ||
            !voterInformation.verificationCardId ||
            !voterInformation.verificationCardSetId ||
            !voterInformation.votingCardSetId) {
            throw new Error('TOKEN_ERROR');
        }

        // verify server auth token signature

        var dataToVerify = authToken.id + authToken.timestamp + voterInformation.tenantId +
            voterInformation.electionEventId + voterInformation.votingCardId + voterInformation.ballotId +
            voterInformation.credentialId + voterInformation.verificationCardId + voterInformation.ballotBoxId +
            voterInformation.verificationCardSetId + voterInformation.votingCardSetId;

        var dataToVerifyB64 = forge.util.encode64(dataToVerify);
        var publicKey = CL.certificates.service.load(authenticationTokenSignerCert).getPublicKey();
        try {
            if (!CL.asymmetric.service.verifySignature(tokenSignature, publicKey, [dataToVerifyB64])) {
                throw new Error('TOKEN_ERROR');
            }
        } catch (e) {
            // ignore details
            throw new Error('TOKEN_ERROR');
        }

    };

    var validateAuthTokenResponse = function(response, certificates, credentialId, electionEventId) {

        var authToken = response.authenticationToken;
        var voterInformation = authToken.voterInformation;

        // verify authentication structure and signatures

        validateAuthToken(authToken, certificates['authenticationTokenSignerCert']);

        var adminBoardCertificate = session('certificates')['adminBoard'];
        
        if (!verifyBallotSignature(response.ballot, adminBoardCertificate)) {
            throw new Error('TOKEN_ERROR');
        }

        _.each(response.ballotTextsSignature, function(ballotTextSignature) {
            if (!verifyBallotTextsSignature(ballotTextSignature.signedObject, adminBoardCertificate)) {
                throw new Error('TOKEN_ERROR');
            }
        });

        if (!verifyBallotBoxSignature(response.ballotBox, adminBoardCertificate)) {
            throw new Error('TOKEN_ERROR');
        }
        

        // verify authentication token content
        // voting card id can not be verified because it is retrieved for the first time here

        var ballotBox = jsrsasign.jws.JWS.parse(response.ballotBox.signature).payloadObj.objectToSign;

        // parse ballot as it comes in string format
        var ballot = JSON.parse(jsrsasign.jws.JWS.parse(response.ballot.signature).payloadObj.objectToSign);


        if (voterInformation.credentialId !== credentialId ||
            voterInformation.electionEventId !== electionEventId ||
            voterInformation.ballotId !== ballot.id ||
            voterInformation.ballotBoxId !== ballotBox.id ||
            voterInformation.verificationCardId !== response.verificationCard.id            
        ) {
            throw new Error('TOKEN_ERROR');
        }
				
		

    };
	
	return {
        validateAuthTokenResponse: validateAuthTokenResponse,
        validateAuthToken: validateAuthToken
    };

})();
