bitagora-booth
Advanced tools
Comparing version 1.0.6 to 1.0.7
171
booth.js
@@ -1,7 +0,10 @@ | ||
const bitagoraVersion = '1.0.6'; | ||
const bitagoraVersion = '1.0.7'; | ||
const CryptoJS = require('crypto-js'); | ||
const Ecdsa = require('elliptic'); | ||
const BASE58 = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'; | ||
const BASE64 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'; | ||
const Bs58 = require('base-x')(BASE58); | ||
const Bs64 = require('base-x')(BASE64); | ||
const EC = Ecdsa.ec('secp256k1'); | ||
const versionByte = '01'; | ||
@@ -28,10 +31,16 @@ var today = new Date(); | ||
// today.getUTCFullYear() + ('0' + (today.getUTCMonth()+1)).slice(-2) + ('0' + today.getUTCDate()).slice(-2); | ||
class Vote { | ||
constructor(idToken, userId, ballot, certSig, certKey, voterSig, voterKey, ctx) { | ||
this.id = CryptoJS.SHA1(idToken).toString(); /* 20 bytes SHA1 hash of ID to guarantee that vote is cast only once */ | ||
this.options = getOptions(ctx.options.string); /* 6 bytes - if 2 options: "\xaa\xaa\x00\x01\xaa\xaa" */ | ||
this.questions = Bs58.decode(ctx.options.string.substr(0,4)).toString('hex') + Bs58.decode(ctx.options.string.substr(10,4)).toString('hex'); /* 6 bytes : 3 bytes option 1, 3 bytes option 2 decoded from Base58 and in hex */ | ||
constructor(idToken, userId, ballot, certSig, certKey, voterSig, voterKey, date, ctx) { | ||
this.version = versionByte; | ||
this.id =idToken; /* 32 bytes : idToken sent by server to guarantee that vote is only cast once */ | ||
this.idPartial = getIdPartial(userId, ctx.idState); /* 4 bytes partial ID number to guarantee partial ident and check */ | ||
this.poll = ctx.id; /* 20 bytes : id of the poll from the context */ | ||
this.date = date; /*4 bytes: date of vote utc format "yyyymmdd" has to match token signed by server */ | ||
this.questions = getQuestions(ctx.options); /* 12 bytes decoded from Base64 and in hex */ | ||
this.options = getOptions(ctx.options); /* 6 bytes - if 2 options: "\xaa\xaa\x00\x01\xaa\xaa" */ | ||
this.ballot = 'ffff' + ballot + 'ffff'; /* 5 bytes with padding "\xFFFF" + "\x00" or "\x01" + "\xFFFF" */ | ||
this.idPartial = getIdPartial(userId.substr(15,8), ctx.idState); /* 3 bytes: 2 bytes partial ID number to guarantee partial ident and check */ | ||
this.date = today.getUTCFullYear() + ('0' + (today.getUTCMonth()+1)).slice(-2) + ('0' + today.getUTCDate()).slice(-2); /*4 bytes: date of vote utc format "yyyymmdd" has to match token signed by server */ | ||
this.checkSum = CryptoJS.SHA256(this.id + this.idPartial + this.poll + this.date + this.questions + this.options + emptyBallot() ).toString().substr(0,4); /* 2 bytes double SHA256 of previous bytes */ | ||
this.certTag = 'f2'; /* 1 byte "\x02" indicating beginning of server signature/pubkey */ | ||
@@ -41,3 +50,2 @@ this.certSig = certSig; /* 70 bytes Server signature. Proof that identity of voter has been validated by server */ | ||
this.certKey = certKey; /* 32 bytes Server Pubkey to authentify signature */ | ||
this.checkSum = CryptoJS.SHA256(CryptoJS.SHA256(this.id + this.options + this.questions + this.ballot + this.idPartial + this.date + this.certTag + this.certSig + this.certKeyLength + this.certKey ) ).toString().substr(0,6); /* 3 bytes double SHA256 of previous 133 bytes */ | ||
this.voterTag = voterSig ? 'f3' : ''; /* 1 byte "\x03" indicating beginning of voter signature/pubkey */ | ||
@@ -47,3 +55,3 @@ this.voterSig = voterSig ? voterSig : ''; /* 70 bytes voter signature. Proof of voter signing vote */ | ||
this.voterKey = voterKey ? voterKey : ''; /* 32 bytes pubkey to authentify voter signature */ | ||
this.padding = '00000000'; /* 4 bytes of final padding: "\x00\x00\x00\x00" */ | ||
this.padding = voterKey ? '00000000' : ''; /* 4 bytes of final padding: "\x00\x00\x00\x00" */ | ||
/* Total length of hex_string = 272 bytes */ | ||
@@ -53,25 +61,63 @@ } | ||
function emptyBallot(ballot) { | ||
return 'ffffffff'; | ||
} | ||
function getOptions(optionString) { | ||
var options = optionString.replace(/\D/g, ''); | ||
if (options.length > 6 || options.length < 2) return null; | ||
var string = ''; | ||
for (var i=0; i<options.length; i++) { | ||
string = string + '0' + options.charAt(i); | ||
if (optionString != null) { | ||
var options = optionString.replace(/\D/g, ''); | ||
if (options.length > 6 || options.length < 2) return null; | ||
var string = ''; | ||
for (var i=0; i<options.length; i++) { | ||
string = string + '0' + options.charAt(i); | ||
} | ||
var padding = 6-options.length; | ||
switch(options.length) { | ||
case 2: | ||
string = 'aaaa' + string + 'aaaa'; | ||
break; | ||
case 3: | ||
string = 'aaaa' + string + 'aa'; | ||
break; | ||
case 4: | ||
string = 'aa' + string + 'aa'; | ||
break; | ||
case 5: | ||
string = 'aa' + string; | ||
break; | ||
} | ||
return string; | ||
} else { | ||
return null; | ||
} | ||
var padding = 6-options.length; | ||
switch(options.length) { | ||
case 2: | ||
string = 'aaaa' + string + 'aaaa'; | ||
break; | ||
case 3: | ||
string = 'aaaa' + string + 'aa'; | ||
break; | ||
case 4: | ||
string = 'aa' + string + 'aa'; | ||
break; | ||
case 5: | ||
string = 'aa' + string; | ||
break; | ||
} | ||
function getQuestions(oa) { | ||
if (oa != null) { | ||
var options = oa.replace(/\D/g, ''); | ||
if (options.length > 6 || options.length < 2) return null; | ||
var questions = ''; | ||
switch(options.length) { | ||
case 2: | ||
questions = oa.substr(0,5) + oa[9] + oa.substr(10,5) + oa[19]; | ||
break; | ||
case 3: | ||
questions = oa.substr(0,3) + oa[9] + oa.substr(10,3) +oa[19] + oa.substr(20,3) + oa[29]; | ||
break; | ||
case 4: | ||
questions = oa.substr(0,2) + oa[9] + oa.substr(10,2) + oa[19] + oa.substr(20,2) + oa[29] + oa.substr(30,2) +oa[39]; | ||
break; | ||
case 5: | ||
questions = oa.substr(0,2)+oa[9]+oa.substr(10,2)+oa[19]+oa.substr(20,1)+oa[29]+oa.substr(30,1)+oa[39]+oa.substr(40,1) + oa[49]; | ||
break; | ||
case 6: | ||
questions = oa.substr(0,1) + oa[9] + oa.substr(10,1) + oa[19] +oa.substr(20,1) +oa[29] + oa.substr(30,1) +oa[39] +oa.substr(40,1) +oa[49] + oa.substr(50,1) +oa[59]; | ||
} | ||
console.log("Questions before base64"+questions); | ||
console.log("In b64: "+Bs64.decode(questions).toString('hex')); | ||
return Bs64.decode(questions).toString('hex'); | ||
} else { | ||
return null; | ||
} | ||
return string; | ||
} | ||
@@ -81,4 +127,3 @@ | ||
if (state == 'ES') { | ||
const letters = 'TRWAGMYFPDXBNJZSQVHLCKE'; | ||
return id.substr(0,4) + ("0" + (letters.indexOf(id.substr(8,1))).toString(16)).substr(-16); | ||
return id.substr(15,4); | ||
} else { | ||
@@ -88,33 +133,37 @@ return null; | ||
} | ||
function getVoteScript(vote) { | ||
return ( vote.versionByte + vote.id + vote.idPartial + vote.poll + vote.date + vote.questions + vote.options + vote.ballot + vote.checkSum + vote.certTag + vote.certSig + vote.certKeyLength + vote.certKey ); | ||
` } | ||
function getPublicToken(vote) { | ||
return ( vote.versionByte + vote.id + vote.idPartial + vote.poll + vote.date + vote.questions + vote.options + emptyBallot() + vote.checkSum ); | ||
} | ||
function getVoteHex(vote) { | ||
return getVoteScript(vote) + vote.voterTag + vote.voterSig + vote.voterKeyLength + vote.voterKey + vote.padding; | ||
}; | ||
return (getVoteScript(vote) + vote.voterTag + vote.voterSig + vote.voterKeyLength + vote.voterKey + vote.padding); | ||
} | ||
function getVoteScript(vote) { | ||
return (vote.id + vote.options + vote.questions + vote.ballot + vote.idPartial + vote.date + | ||
vote.certTag + vote.certSig + vote.certKeyLength + vote.certKey + vote.checkSum + vote.padding) | ||
}; | ||
function validateVoterSig(vote) { | ||
var key = EC.keyFromPublic(vote.voterKey, 'hex'); | ||
var voteScript = getVoteScript(vote); | ||
return key.verify(voteScript, vote.voterSig); | ||
}; | ||
var key = EC.keyFromPublic(vote.voterKey, 'hex'); | ||
var voteScript = getVoteScript(vote); | ||
return key.verify(voteScript, vote.voterSig); | ||
} | ||
function validateCertSig(vote) { | ||
var key = EC.keyFromPublic(vote.certKey, 'hex'); | ||
var certScript = CryptoJS.SHA256(CryptoJS.SHA256(vote.idPartial + questions + vote.date + vote.voterKey)).toString(); | ||
return key.verify(certScript, vote.certSig); | ||
}; | ||
var key = EC.keyFromPublic(vote.certKey, 'hex'); | ||
var payload = getPublicToken(vote) + vote.voterKey; | ||
var certScript = CryptoJS.SHA256(CryptoJS.SHA256(payload)).toString(); | ||
return key.verify(certScript, vote.certSig); | ||
} | ||
function signScript(script, privateKey) { | ||
var key = EC.keyFromPrivate(privateKey, 'hex'); | ||
var signature = key.sign(script).toDER(); | ||
if (signature) { | ||
return toHexString(signature); | ||
} else { | ||
return null; | ||
var key = EC.keyFromPrivate(privateKey, 'hex'); | ||
var signature = key.sign(script).toDER(); | ||
if (signature) { | ||
return toHexString(signature); | ||
} else { | ||
return null; | ||
} | ||
} | ||
}; | ||
@@ -147,4 +196,4 @@ function validateVote (vote) { | ||
console.log("Checksum"); | ||
var voteString = vote.id + vote.options + vote.questions + vote.ballot + vote.idPartial + vote.date + vote.certTag + vote.certSig + vote.certKeyLength + vote.certKey; | ||
var checksum = CryptoJS.SHA256(CryptoJS.SHA256(voteString)).toString().substr(0,6); | ||
var voteString = vote.versionByte + vote.id + vote.idPartial + vote.poll + vote.date + vote.questions + vote.options + emptyBallot(); | ||
var checksum = CryptoJS.SHA256(voteString).toString().substr(0,4); | ||
if (checksum != vote.checkSum) { | ||
@@ -168,3 +217,3 @@ console.log('Invalid checksum'); | ||
function generateNewVote (voteData, ctx) { | ||
var idToken = voteData.id; /* ID token sent by server */ | ||
var idToken = voteData.idToken; /* ID token sent by server */ | ||
var userId = voteData.userId; /* ID introduced by user */ | ||
@@ -174,7 +223,8 @@ var ballot = voteData.ballot; /* Vote by user with options available */ | ||
var certKey = voteData.certKey; | ||
return new Vote(idToken, userId, ballot, certSig, certKey, null, null, ctx); | ||
var date = voteData.regDate; | ||
return new Vote(idToken, userId, ballot, certSig, certKey, null, null, date, ctx); | ||
}; | ||
function completeVote (vote, idToken, userId, signature, pubkey, ctx) { | ||
return new Vote(idToken, userId, vote.ballot.substr(4,2), vote.certSig, vote.certKey, signature, pubkey, ctx); | ||
return new Vote(idToken, userId, vote.ballot.substr(4,2), vote.certSig, vote.certKey, signature, pubkey, vote.date, ctx ); | ||
}; | ||
@@ -192,5 +242,2 @@ | ||
vote: function(data, context) { | ||
console.log("Starting vote in booth.js"); | ||
console.log(data); | ||
console.log(context); | ||
if (data == null || context == null) return false; | ||
@@ -197,0 +244,0 @@ try { |
{ | ||
"name": "bitagora-booth", | ||
"version": "1.0.6", | ||
"version": "1.0.7", | ||
"description": "Bitagora booth js functions", | ||
@@ -5,0 +5,0 @@ "main": "booth.js", |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
11098
258