Implement IP and fingerprint logging

This commit is contained in:
RunasSudo 2017-12-11 13:23:25 +10:30
parent d264159237
commit 5740f33b7d
Signed by: RunasSudo
GPG Key ID: 7234E476BF21C61A
9 changed files with 49 additions and 8 deletions

View File

@ -47,9 +47,14 @@ class Ballot(EmbeddedObject):
return Ballot(encrypted_answers=encrypted_answers_deaudit, election_id=self.election_id, election_hash=self.election_hash)
class Vote(EmbeddedObject):
_ver = StringField(default='0.4')
ballot = EmbeddedObjectField()
cast_at = DateTimeField()
cast_ip = StringField(is_protected=True)
cast_fingerprint = BlobField(is_protected=True)
class Voter(EmbeddedObject):
_id = UUIDField()
votes = EmbeddedObjectListField()

View File

@ -84,6 +84,7 @@ DictField = PrimitiveField
IntField = PrimitiveField
StringField = PrimitiveField
BooleanField = PrimitiveField
BlobField = PrimitiveField
class EmbeddedObjectField(Field):
def __init__(self, object_type=None, *args, **kwargs):

View File

@ -18,6 +18,7 @@
"dependencies": {
"semantic": "semantic-ui#^2.2.13",
"nunjucks": "^3.0.1",
"dragula.js": "dragula#^3.7.2"
"dragula.js": "dragula#^3.7.2",
"fingerprintjs2": "^1.5.1"
}
}

View File

@ -252,6 +252,16 @@ def election_api_cast_vote(election):
# Cast the vote
ballot = EosObject.deserialise_and_unwrap(data['ballot'])
vote = Vote(ballot=ballot, cast_at=DateTimeField.now())
# Store data
if app.config['CAST_FINGERPRINT']:
vote.cast_fingerprint = data['fingerprint']
if app.config['CAST_IP']:
if os.path.exists('/app/.heroku'):
vote.cast_ip = flask.request.headers['X-Forwarded-For'].split(',')[-1]
else:
vote.cast_ip = flask.request.remote_addr
voter.votes.append(vote)
election.save()

View File

@ -19,7 +19,7 @@
window = self; // Workaround for libraries
isLibrariesLoaded = false;
function generateEncryptedVote(election, answers) {
function generateEncryptedVote(election, answers, should_do_fingerprint) {
encrypted_answers = [];
for (var q_num = 0; q_num < answers.length; q_num++) {
answer_json = answers[q_num];
@ -28,7 +28,9 @@ function generateEncryptedVote(election, answers) {
encrypted_answers.push(eosjs.eos.core.objects.__all__.EosObject.serialise_and_wrap(encrypted_answer, null));
}
postMessage(encrypted_answers);
postMessage({
encrypted_answers: encrypted_answers
});
}
onmessage = function(msg) {

View File

@ -90,7 +90,8 @@
url: "{{ election_base_url }}cast_ballot",
type: "POST",
data: eosjs.eos.core.objects.__all__.EosObject.to_json({
"ballot": eosjs.eos.core.objects.__all__.EosObject.serialise_and_wrap(booth.ballot, null)
"ballot": eosjs.eos.core.objects.__all__.EosObject.serialise_and_wrap(booth.ballot, null),
"fingerprint": booth.fingerprint || null
}),
contentType: "application/json",
dataType: "text"

View File

@ -27,7 +27,7 @@
}
encryptedAnswers = [];
for (var encrypted_answer_json of msg.data) {
for (var encrypted_answer_json of msg.data.encrypted_answers) {
encryptedAnswers.push(eosjs.eos.core.objects.__all__.EosObject.deserialise_and_unwrap(encrypted_answer_json, null));
}
@ -37,7 +37,18 @@
booth.ballot.election_id = election._id;
booth.ballot.election_hash = eosjs.eos.core.hashing.__all__.SHA256().update_obj(election).hash_as_b64();
nextTemplate();
if (should_do_fingerprint) {
// String.prototype.join confuses fingerprintjs2
var strjoin = String.prototype.join;
String.prototype.join = undefined;
new Fingerprint2().get(function(result, components) {
String.prototype.join = strjoin;
booth.fingerprint = components;
nextTemplate();
});
} else {
nextTemplate();
}
} catch (err) {
boothError(err);
throw err;
@ -52,7 +63,7 @@
"action": "generateEncryptedVote",
"static_base_url": "{{ static_base_url }}",
"election": eosjs.eos.core.objects.__all__.EosObject.serialise_and_wrap(election, null),
"answers": booth.answers,
"answers": booth.answers
});
} catch (err) {
boothError(err);

View File

@ -38,6 +38,9 @@
<script src="{{ url_for('static', filename='js/eosjs.js') }}"></script>
<script src="{{ url_for('static', filename='bower_components/dragula.js/dist/dragula.min.js') }}"></script>
{% if eosweb.app.config['CAST_FINGERPRINT'] %}
<script src="{{ url_for('static', filename='bower_components/fingerprintjs2/dist/fingerprint2.min.js') }}"></script>
{% endif %}
<script>
var templates = {};
@ -50,12 +53,14 @@
var username = {% if session.user %}"{{ session.user.name }}"{% else %}null{% endif %};
var auth_methods = {{ auth_methods|safe }};
var should_do_fingerprint = {{ 'true' if eosweb.app.config['CAST_FINGERPRINT'] else 'false' }};
function resetBooth() {
booth = {
"questionNum": 0,
"answers": [],
"q_state": []
"q_state": [],
"fingerprint": []
};
}
resetBooth();

View File

@ -37,3 +37,8 @@ SMTP_FROM = 'eos@localhost'
REDDIT_OAUTH_CLIENT_ID = 'xxxxxxxxxxxxxx'
REDDIT_OAUTH_CLIENT_SECRET = 'xxxxxxxxxxxxxxxxxxxxxxxxxxx'
REDDIT_USER_AGENT = 'Application Title by /u/Your_Username'
# Security
CAST_IP = True
CAST_FINGERPRINT = False