Implement IP and fingerprint logging
This commit is contained in:
parent
d264159237
commit
5740f33b7d
@ -47,9 +47,14 @@ class Ballot(EmbeddedObject):
|
|||||||
return Ballot(encrypted_answers=encrypted_answers_deaudit, election_id=self.election_id, election_hash=self.election_hash)
|
return Ballot(encrypted_answers=encrypted_answers_deaudit, election_id=self.election_id, election_hash=self.election_hash)
|
||||||
|
|
||||||
class Vote(EmbeddedObject):
|
class Vote(EmbeddedObject):
|
||||||
|
_ver = StringField(default='0.4')
|
||||||
|
|
||||||
ballot = EmbeddedObjectField()
|
ballot = EmbeddedObjectField()
|
||||||
cast_at = DateTimeField()
|
cast_at = DateTimeField()
|
||||||
|
|
||||||
|
cast_ip = StringField(is_protected=True)
|
||||||
|
cast_fingerprint = BlobField(is_protected=True)
|
||||||
|
|
||||||
class Voter(EmbeddedObject):
|
class Voter(EmbeddedObject):
|
||||||
_id = UUIDField()
|
_id = UUIDField()
|
||||||
votes = EmbeddedObjectListField()
|
votes = EmbeddedObjectListField()
|
||||||
|
@ -84,6 +84,7 @@ DictField = PrimitiveField
|
|||||||
IntField = PrimitiveField
|
IntField = PrimitiveField
|
||||||
StringField = PrimitiveField
|
StringField = PrimitiveField
|
||||||
BooleanField = PrimitiveField
|
BooleanField = PrimitiveField
|
||||||
|
BlobField = PrimitiveField
|
||||||
|
|
||||||
class EmbeddedObjectField(Field):
|
class EmbeddedObjectField(Field):
|
||||||
def __init__(self, object_type=None, *args, **kwargs):
|
def __init__(self, object_type=None, *args, **kwargs):
|
||||||
|
@ -18,6 +18,7 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"semantic": "semantic-ui#^2.2.13",
|
"semantic": "semantic-ui#^2.2.13",
|
||||||
"nunjucks": "^3.0.1",
|
"nunjucks": "^3.0.1",
|
||||||
"dragula.js": "dragula#^3.7.2"
|
"dragula.js": "dragula#^3.7.2",
|
||||||
|
"fingerprintjs2": "^1.5.1"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -252,6 +252,16 @@ def election_api_cast_vote(election):
|
|||||||
# Cast the vote
|
# Cast the vote
|
||||||
ballot = EosObject.deserialise_and_unwrap(data['ballot'])
|
ballot = EosObject.deserialise_and_unwrap(data['ballot'])
|
||||||
vote = Vote(ballot=ballot, cast_at=DateTimeField.now())
|
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)
|
voter.votes.append(vote)
|
||||||
|
|
||||||
election.save()
|
election.save()
|
||||||
|
@ -19,7 +19,7 @@
|
|||||||
window = self; // Workaround for libraries
|
window = self; // Workaround for libraries
|
||||||
isLibrariesLoaded = false;
|
isLibrariesLoaded = false;
|
||||||
|
|
||||||
function generateEncryptedVote(election, answers) {
|
function generateEncryptedVote(election, answers, should_do_fingerprint) {
|
||||||
encrypted_answers = [];
|
encrypted_answers = [];
|
||||||
for (var q_num = 0; q_num < answers.length; q_num++) {
|
for (var q_num = 0; q_num < answers.length; q_num++) {
|
||||||
answer_json = answers[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));
|
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) {
|
onmessage = function(msg) {
|
||||||
|
@ -90,7 +90,8 @@
|
|||||||
url: "{{ election_base_url }}cast_ballot",
|
url: "{{ election_base_url }}cast_ballot",
|
||||||
type: "POST",
|
type: "POST",
|
||||||
data: eosjs.eos.core.objects.__all__.EosObject.to_json({
|
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",
|
contentType: "application/json",
|
||||||
dataType: "text"
|
dataType: "text"
|
||||||
|
@ -27,7 +27,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
encryptedAnswers = [];
|
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));
|
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_id = election._id;
|
||||||
booth.ballot.election_hash = eosjs.eos.core.hashing.__all__.SHA256().update_obj(election).hash_as_b64();
|
booth.ballot.election_hash = eosjs.eos.core.hashing.__all__.SHA256().update_obj(election).hash_as_b64();
|
||||||
|
|
||||||
|
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();
|
nextTemplate();
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
nextTemplate();
|
||||||
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
boothError(err);
|
boothError(err);
|
||||||
throw err;
|
throw err;
|
||||||
@ -52,7 +63,7 @@
|
|||||||
"action": "generateEncryptedVote",
|
"action": "generateEncryptedVote",
|
||||||
"static_base_url": "{{ static_base_url }}",
|
"static_base_url": "{{ static_base_url }}",
|
||||||
"election": eosjs.eos.core.objects.__all__.EosObject.serialise_and_wrap(election, null),
|
"election": eosjs.eos.core.objects.__all__.EosObject.serialise_and_wrap(election, null),
|
||||||
"answers": booth.answers,
|
"answers": booth.answers
|
||||||
});
|
});
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
boothError(err);
|
boothError(err);
|
||||||
|
@ -38,6 +38,9 @@
|
|||||||
<script src="{{ url_for('static', filename='js/eosjs.js') }}"></script>
|
<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>
|
<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>
|
<script>
|
||||||
var templates = {};
|
var templates = {};
|
||||||
@ -50,12 +53,14 @@
|
|||||||
|
|
||||||
var username = {% if session.user %}"{{ session.user.name }}"{% else %}null{% endif %};
|
var username = {% if session.user %}"{{ session.user.name }}"{% else %}null{% endif %};
|
||||||
var auth_methods = {{ auth_methods|safe }};
|
var auth_methods = {{ auth_methods|safe }};
|
||||||
|
var should_do_fingerprint = {{ 'true' if eosweb.app.config['CAST_FINGERPRINT'] else 'false' }};
|
||||||
|
|
||||||
function resetBooth() {
|
function resetBooth() {
|
||||||
booth = {
|
booth = {
|
||||||
"questionNum": 0,
|
"questionNum": 0,
|
||||||
"answers": [],
|
"answers": [],
|
||||||
"q_state": []
|
"q_state": [],
|
||||||
|
"fingerprint": []
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
resetBooth();
|
resetBooth();
|
||||||
|
@ -37,3 +37,8 @@ SMTP_FROM = 'eos@localhost'
|
|||||||
REDDIT_OAUTH_CLIENT_ID = 'xxxxxxxxxxxxxx'
|
REDDIT_OAUTH_CLIENT_ID = 'xxxxxxxxxxxxxx'
|
||||||
REDDIT_OAUTH_CLIENT_SECRET = 'xxxxxxxxxxxxxxxxxxxxxxxxxxx'
|
REDDIT_OAUTH_CLIENT_SECRET = 'xxxxxxxxxxxxxxxxxxxxxxxxxxx'
|
||||||
REDDIT_USER_AGENT = 'Application Title by /u/Your_Username'
|
REDDIT_USER_AGENT = 'Application Title by /u/Your_Username'
|
||||||
|
|
||||||
|
# Security
|
||||||
|
|
||||||
|
CAST_IP = True
|
||||||
|
CAST_FINGERPRINT = False
|
||||||
|
Loading…
Reference in New Issue
Block a user