Merge pull request #9 from vincentmdealmeida/EventPrep

General housekeeping such as adding package.json for Node server, bas…
This commit is contained in:
vincentmdealmeida 2018-07-02 10:17:59 +01:00 committed by GitHub
commit 0c354cd542
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
21 changed files with 337 additions and 696 deletions

2
.gitignore vendored
View file

@ -1,6 +1,8 @@
*.pyc *.pyc
*.sqlite *.sqlite
*.sqlite3 *.sqlite3
package-lock.json
node_modules/
__pycache__ __pycache__
migrations/ migrations/
build build

529
Node/package-lock.json generated
View file

@ -1,529 +0,0 @@
{
"requires": true,
"lockfileVersion": 1,
"dependencies": {
"accepts": {
"version": "1.3.4",
"resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.4.tgz",
"integrity": "sha1-hiRnWMfdbSGmR0/whKR0DsBesh8=",
"requires": {
"mime-types": "2.1.17",
"negotiator": "0.6.1"
}
},
"append-field": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/append-field/-/append-field-0.1.0.tgz",
"integrity": "sha1-bdxY+gg8e8VF08WZWygwzCNm1Eo="
},
"array-flatten": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
"integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI="
},
"body-parser": {
"version": "1.18.2",
"resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.18.2.tgz",
"integrity": "sha1-h2eKGdhLR9hZuDGZvVm84iKxBFQ=",
"requires": {
"bytes": "3.0.0",
"content-type": "1.0.4",
"debug": "2.6.9",
"depd": "1.1.1",
"http-errors": "1.6.2",
"iconv-lite": "0.4.19",
"on-finished": "2.3.0",
"qs": "6.5.1",
"raw-body": "2.3.2",
"type-is": "1.6.15"
}
},
"busboy": {
"version": "0.2.14",
"resolved": "https://registry.npmjs.org/busboy/-/busboy-0.2.14.tgz",
"integrity": "sha1-bCpiLvz0fFe7vh4qnDetNseSVFM=",
"requires": {
"dicer": "0.2.5",
"readable-stream": "1.1.14"
}
},
"bytes": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz",
"integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg="
},
"concat-stream": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.0.tgz",
"integrity": "sha1-CqxmL9Ur54lk1VMvaUeE5wEQrPc=",
"requires": {
"inherits": "2.0.3",
"readable-stream": "2.3.3",
"typedarray": "0.0.6"
},
"dependencies": {
"isarray": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
"integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE="
},
"readable-stream": {
"version": "2.3.3",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.3.tgz",
"integrity": "sha512-m+qzzcn7KUxEmd1gMbchF+Y2eIUbieUaxkWtptyHywrX0rE8QEYqPC07Vuy4Wm32/xE16NcdBctb8S0Xe/5IeQ==",
"requires": {
"core-util-is": "1.0.2",
"inherits": "2.0.3",
"isarray": "1.0.0",
"process-nextick-args": "1.0.7",
"safe-buffer": "5.1.1",
"string_decoder": "1.0.3",
"util-deprecate": "1.0.2"
}
},
"string_decoder": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz",
"integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==",
"requires": {
"safe-buffer": "5.1.1"
}
}
}
},
"content-disposition": {
"version": "0.5.2",
"resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.2.tgz",
"integrity": "sha1-DPaLud318r55YcOoUXjLhdunjLQ="
},
"content-type": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz",
"integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA=="
},
"cookie": {
"version": "0.3.1",
"resolved": "https://registry.npmjs.org/cookie/-/cookie-0.3.1.tgz",
"integrity": "sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s="
},
"cookie-parser": {
"version": "1.4.3",
"resolved": "https://registry.npmjs.org/cookie-parser/-/cookie-parser-1.4.3.tgz",
"integrity": "sha1-D+MfoZ0AC5X0qt8fU/3CuKIDuqU=",
"requires": {
"cookie": "0.3.1",
"cookie-signature": "1.0.6"
}
},
"cookie-signature": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
"integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw="
},
"core-util-is": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
"integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac="
},
"cors": {
"version": "2.8.4",
"resolved": "https://registry.npmjs.org/cors/-/cors-2.8.4.tgz",
"integrity": "sha1-K9OB8usgECAQXNUOpZ2mMJBpRoY=",
"requires": {
"object-assign": "4.1.1",
"vary": "1.1.2"
},
"dependencies": {
"object-assign": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
"integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM="
}
}
},
"debug": {
"version": "2.6.9",
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
"integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
"requires": {
"ms": "2.0.0"
}
},
"depd": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/depd/-/depd-1.1.1.tgz",
"integrity": "sha1-V4O04cRZ8G+lyif5kfPQbnoxA1k="
},
"destroy": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz",
"integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA="
},
"dicer": {
"version": "0.2.5",
"resolved": "https://registry.npmjs.org/dicer/-/dicer-0.2.5.tgz",
"integrity": "sha1-WZbAhrszIYyBLAkL3cCc0S+stw8=",
"requires": {
"readable-stream": "1.1.14",
"streamsearch": "0.1.2"
}
},
"ee-first": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
"integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0="
},
"encodeurl": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.1.tgz",
"integrity": "sha1-eePVhlU0aQn+bw9Fpd5oEDspTSA="
},
"escape-html": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
"integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg="
},
"etag": {
"version": "1.8.1",
"resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
"integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc="
},
"express": {
"version": "4.16.2",
"resolved": "https://registry.npmjs.org/express/-/express-4.16.2.tgz",
"integrity": "sha1-41xt/i1kt9ygpc1PIXgb4ymeB2w=",
"requires": {
"accepts": "1.3.4",
"array-flatten": "1.1.1",
"body-parser": "1.18.2",
"content-disposition": "0.5.2",
"content-type": "1.0.4",
"cookie": "0.3.1",
"cookie-signature": "1.0.6",
"debug": "2.6.9",
"depd": "1.1.1",
"encodeurl": "1.0.1",
"escape-html": "1.0.3",
"etag": "1.8.1",
"finalhandler": "1.1.0",
"fresh": "0.5.2",
"merge-descriptors": "1.0.1",
"methods": "1.1.2",
"on-finished": "2.3.0",
"parseurl": "1.3.2",
"path-to-regexp": "0.1.7",
"proxy-addr": "2.0.2",
"qs": "6.5.1",
"range-parser": "1.2.0",
"safe-buffer": "5.1.1",
"send": "0.16.1",
"serve-static": "1.13.1",
"setprototypeof": "1.1.0",
"statuses": "1.3.1",
"type-is": "1.6.15",
"utils-merge": "1.0.1",
"vary": "1.1.2"
}
},
"finalhandler": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.0.tgz",
"integrity": "sha1-zgtoVbRYU+eRsvzGgARtiCU91/U=",
"requires": {
"debug": "2.6.9",
"encodeurl": "1.0.1",
"escape-html": "1.0.3",
"on-finished": "2.3.0",
"parseurl": "1.3.2",
"statuses": "1.3.1",
"unpipe": "1.0.0"
}
},
"forwarded": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz",
"integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ="
},
"fresh": {
"version": "0.5.2",
"resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz",
"integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac="
},
"http-errors": {
"version": "1.6.2",
"resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.2.tgz",
"integrity": "sha1-CgAsyFcHGSp+eUbO7cERVfYOxzY=",
"requires": {
"depd": "1.1.1",
"inherits": "2.0.3",
"setprototypeof": "1.0.3",
"statuses": "1.3.1"
},
"dependencies": {
"setprototypeof": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.0.3.tgz",
"integrity": "sha1-ZlZ+NwQ+608E2RvWWMDL77VbjgQ="
}
}
},
"iconv-lite": {
"version": "0.4.19",
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.19.tgz",
"integrity": "sha512-oTZqweIP51xaGPI4uPa56/Pri/480R+mo7SeU+YETByQNhDG55ycFyNLIgta9vXhILrxXDmF7ZGhqZIcuN0gJQ=="
},
"inherits": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
"integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4="
},
"ipaddr.js": {
"version": "1.5.2",
"resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.5.2.tgz",
"integrity": "sha1-1LUFvemUaYfM8PxY2QEP+WB+P6A="
},
"isarray": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz",
"integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8="
},
"media-typer": {
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
"integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g="
},
"merge-descriptors": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz",
"integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E="
},
"methods": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz",
"integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4="
},
"milagro-crypto-js": {
"version": "file:milagro-crypto-js"
},
"mime": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/mime/-/mime-1.4.1.tgz",
"integrity": "sha512-KI1+qOZu5DcW6wayYHSzR/tXKCDC5Om4s1z2QJjDULzLcmf3DvzS7oluY4HCTrc+9FiKmWUgeNLg7W3uIQvxtQ=="
},
"mime-db": {
"version": "1.30.0",
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.30.0.tgz",
"integrity": "sha1-dMZD2i3Z1qRTmZY0ZbJtXKfXHwE="
},
"mime-types": {
"version": "2.1.17",
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.17.tgz",
"integrity": "sha1-Cdejk/A+mVp5+K+Fe3Cp4KsWVXo=",
"requires": {
"mime-db": "1.30.0"
}
},
"minimist": {
"version": "0.0.8",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz",
"integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0="
},
"mkdirp": {
"version": "0.5.1",
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz",
"integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=",
"requires": {
"minimist": "0.0.8"
}
},
"ms": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
},
"multer": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/multer/-/multer-1.3.0.tgz",
"integrity": "sha1-CSsmcPaEb6SRSWXvyM+Uwg/sbNI=",
"requires": {
"append-field": "0.1.0",
"busboy": "0.2.14",
"concat-stream": "1.6.0",
"mkdirp": "0.5.1",
"object-assign": "3.0.0",
"on-finished": "2.3.0",
"type-is": "1.6.15",
"xtend": "4.0.1"
}
},
"negotiator": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.1.tgz",
"integrity": "sha1-KzJxhOiZIQEXeyhWP7XnECrNDKk="
},
"object-assign": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-3.0.0.tgz",
"integrity": "sha1-m+3VygiXlJvKR+f/QIBi1Un1h/I="
},
"on-finished": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz",
"integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=",
"requires": {
"ee-first": "1.1.1"
}
},
"parseurl": {
"version": "1.3.2",
"resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.2.tgz",
"integrity": "sha1-/CidTtiZMRlGDBViUyYs3I3mW/M="
},
"path-to-regexp": {
"version": "0.1.7",
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz",
"integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w="
},
"process-nextick-args": {
"version": "1.0.7",
"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz",
"integrity": "sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M="
},
"proxy-addr": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.2.tgz",
"integrity": "sha1-ZXFQT0e7mI7IGAJT+F3X4UlSvew=",
"requires": {
"forwarded": "0.1.2",
"ipaddr.js": "1.5.2"
}
},
"qs": {
"version": "6.5.1",
"resolved": "https://registry.npmjs.org/qs/-/qs-6.5.1.tgz",
"integrity": "sha512-eRzhrN1WSINYCDCbrz796z37LOe3m5tmW7RQf6oBntukAG1nmovJvhnwHHRMAfeoItc1m2Hk02WER2aQ/iqs+A=="
},
"range-parser": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.0.tgz",
"integrity": "sha1-9JvmtIeJTdxA3MlKMi9hEJLgDV4="
},
"raw-body": {
"version": "2.3.2",
"resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.3.2.tgz",
"integrity": "sha1-vNYMd9Prk83gBQKVw/N5OJvIj4k=",
"requires": {
"bytes": "3.0.0",
"http-errors": "1.6.2",
"iconv-lite": "0.4.19",
"unpipe": "1.0.0"
}
},
"readable-stream": {
"version": "1.1.14",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz",
"integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=",
"requires": {
"core-util-is": "1.0.2",
"inherits": "2.0.3",
"isarray": "0.0.1",
"string_decoder": "0.10.31"
}
},
"safe-buffer": {
"version": "5.1.1",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz",
"integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg=="
},
"send": {
"version": "0.16.1",
"resolved": "https://registry.npmjs.org/send/-/send-0.16.1.tgz",
"integrity": "sha512-ElCLJdJIKPk6ux/Hocwhk7NFHpI3pVm/IZOYWqUmoxcgeyM+MpxHHKhb8QmlJDX1pU6WrgaHBkVNm73Sv7uc2A==",
"requires": {
"debug": "2.6.9",
"depd": "1.1.1",
"destroy": "1.0.4",
"encodeurl": "1.0.1",
"escape-html": "1.0.3",
"etag": "1.8.1",
"fresh": "0.5.2",
"http-errors": "1.6.2",
"mime": "1.4.1",
"ms": "2.0.0",
"on-finished": "2.3.0",
"range-parser": "1.2.0",
"statuses": "1.3.1"
}
},
"serve-static": {
"version": "1.13.1",
"resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.13.1.tgz",
"integrity": "sha512-hSMUZrsPa/I09VYFJwa627JJkNs0NrfL1Uzuup+GqHfToR2KcsXFymXSV90hoyw3M+msjFuQly+YzIH/q0MGlQ==",
"requires": {
"encodeurl": "1.0.1",
"escape-html": "1.0.3",
"parseurl": "1.3.2",
"send": "0.16.1"
}
},
"setprototypeof": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz",
"integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ=="
},
"statuses": {
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/statuses/-/statuses-1.3.1.tgz",
"integrity": "sha1-+vUbnrdKrvOzrPStX2Gr8ky3uT4="
},
"streamsearch": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-0.1.2.tgz",
"integrity": "sha1-gIudDlb8Jz2Am6VzOOkpkZoanxo="
},
"string_decoder": {
"version": "0.10.31",
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz",
"integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ="
},
"type-is": {
"version": "1.6.15",
"resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.15.tgz",
"integrity": "sha1-yrEPtJCeRByChC6v4a1kbIGARBA=",
"requires": {
"media-typer": "0.3.0",
"mime-types": "2.1.17"
}
},
"typedarray": {
"version": "0.0.6",
"resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz",
"integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c="
},
"unpipe": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
"integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw="
},
"util-deprecate": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
"integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8="
},
"utils-merge": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz",
"integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM="
},
"vary": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
"integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw="
},
"xtend": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz",
"integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68="
}
}
}

23
Node/package.json Normal file
View file

@ -0,0 +1,23 @@
{
"name": "Node DEMOS2 Cryptography Server",
"version": "1.0.0",
"description": "Exposes Cryptographic Functionality from Various Endpoints",
"main": "index.js",
"directories": {
"test": "test"
},
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"repository": {
"type": "git",
"url": "https://github.com/vincentmdealmeida/DEMOS2"
},
"keywords": [],
"author": "Bingsheng Zang, Thomas Smith",
"license": "ISC",
"dependencies": {
"express": "^4.16.3",
"milagro-crypto-js": "git+https://github.com/milagro-crypto/milagro-crypto-js.git"
}
}

View file

@ -1,10 +1,10 @@
# DEMOS2 # DEMOS2
Prototype Django based e-voting application, to demonstrate DEMOS2's client-side encryption e-voting. Prototype Django-based e-voting application, to demonstrate DEMOS2's client-side encryption e-voting.
The previous repository for DEMOS2 by Carey Williams can be found at: https://github.com/CareyJWilliams/DEMOS2 The previous repository for DEMOS2 by Carey Williams can be found at: https://github.com/CareyJWilliams/DEMOS2
### Dependencies ### Main Application Dependencies
Python: Version 2.7 (Anything higher than this will not currently work) Python: Version 2.7 (Anything higher than this will not currently work)
Python packages: Specified in 'requirements.txt' - PyCharm will detect these dependencies and offer installation Python packages: Specified in 'requirements.txt' - PyCharm will detect these dependencies and offer installation
@ -17,9 +17,23 @@ Finally, with all the above dependencies in place, you can simply issue the foll
python manage.py migrate python manage.py migrate
'aullauthdemo/settings.py' specifies the Google reCAPTCHA site key and private key which will need changing when deployed 'aullauthdemo/settings.py' specifies the Google reCAPTCHA site key and private key which will need changing when deployed
onto a new domain. onto a new domain. There is also a DOMAIN setting within the file that needs updating during deployment as things
like email functionality depend on this setting for correct URL generation during event preparation etc.
### Running the server and creating a new user account Emails from the application are currently sent from the following email account which can be updated within the settings:
demos2.no.reply@gmail.com
### NodeJS Dependencies
The Node.js crypto server depends on the milagro-crypto-js and express modules. A package.json file can be found in the
Node/ directory with these dependency requirements and therefore from this folder you can run:
npm install
Once the dependencies have been installed, you can then run the node server as per the below instructions.
### Step 1: Running the Python app and creating a new user account
You can run the server with the following command: You can run the server with the following command:
@ -33,8 +47,16 @@ You can then click on 'Join' to create a new user account. Currently, a server e
email account saying something like 'Too Many Attempts'. Rest assured that the account will have been created. Navigate email account saying something like 'Too Many Attempts'. Rest assured that the account will have been created. Navigate
back to the home page and you should be able to log in. This will hopefully be fixed in a future version. back to the home page and you should be able to log in. This will hopefully be fixed in a future version.
### Other ### Step 2: Running Celery
This was included in the previous readme and may be required: Celery is used to run tasks asynchronously and the DEMOS2 application can't run without this application. A bash script
called 'start_celery_worker.sh' is provided to make starting a worker as easy as possible:
The Node.js encryption server depends on the milagro-crypto-js library. Download the source and follow the instructions for installation: https://github.com/milagro-crypto/milagro-crypto-js. To install, place the package's files (`package.json` level) into the directory Node/milagro-crypto-js (a new folder) then run `npm install` in the Node folder. This should install dependencies including the local package you just added. ./start_celery_worker.sh
### Step 3: Running the NodeJS Server
The NodeJS server exposes a lot of cryptographic operations that the application depends on throughout. To run the
server, issue the following command line request from the Node/ folder:
node index.js

View file

@ -4,18 +4,21 @@ import subprocess
import json import json
import urllib2 import urllib2
#change this file name etc., temporary change to get it working for the meantime
''' '''
All functions in this file have been re-implemenented by Thomas Smith All functions in this file have been re-implemenented by Thomas Smith
File then updated by Vincent de Almeida. Changes include:
-Update filename to 'crypto_rpc' to reflect the RPC nature of the methods
''' '''
def param(): def param():
jsondict = json.load(urllib2.urlopen('http://localhost:8080/param')) url = 'http://localhost:8080/param' # RPC URL
jsondict = json.load(urllib2.urlopen(url))
return json.dumps(jsondict) return json.dumps(jsondict)
def combpk(amount, pks): def combpk(amount, pks):
url = 'http://localhost:8080/cmpkstring' url = 'http://localhost:8080/cmpkstring' # RPC URL
querystring = '?number='+str(amount) querystring = '?number='+str(amount)
for pk in pks: for pk in pks:
querystring += '&PK='+pk querystring += '&PK='+pk
@ -26,7 +29,7 @@ def combpk(amount, pks):
return json.dumps(jsondict) return json.dumps(jsondict)
def addec(amount, ciphers): def addec(amount, ciphers):
url = 'http://localhost:8080/addec' url = 'http://localhost:8080/addec' # RPC URL
querystring = '?number='+str(amount) querystring = '?number='+str(amount)
c1s = ciphers['c1s'] c1s = ciphers['c1s']
c2s = ciphers['c2s'] c2s = ciphers['c2s']
@ -40,7 +43,7 @@ def addec(amount, ciphers):
return json.dumps(jsondict) return json.dumps(jsondict)
def tally(amount, param, decs, cipher): def tally(amount, param, decs, cipher):
url = 'http://localhost:8080/tally' url = 'http://localhost:8080/tally' # RPC URL
querystring = '?number='+str(amount) querystring = '?number='+str(amount)
querystring += '&param='+urllib2.quote(str(param)) querystring += '&param='+urllib2.quote(str(param))

View file

@ -1,7 +1,8 @@
from __future__ import unicode_literals from __future__ import unicode_literals
from datetime import datetime import json
from django.core.mail import send_mail
from django.db import models from django.db import models
from django.utils import timezone from django.utils import timezone
@ -9,9 +10,17 @@ from allauthdemo.auth.models import DemoUser
class EmailUser(models.Model): class EmailUser(models.Model):
email = models.CharField(max_length=80, unique=True) email = models.CharField(max_length=80, unique=True)
def send_email(self, subject, message, from_email=None):
"""
Sends an email to this User.
"""
send_mail(subject, message, from_email, [self.email])
def __unicode__(self): def __unicode__(self):
return self.email return self.email
class Event(models.Model): class Event(models.Model):
users_organisers = models.ManyToManyField(DemoUser, blank=True, related_name="organisers") users_organisers = models.ManyToManyField(DemoUser, blank=True, related_name="organisers")
users_trustees = models.ManyToManyField(EmailUser, blank=True, related_name="trustees") users_trustees = models.ManyToManyField(EmailUser, blank=True, related_name="trustees")
@ -26,11 +35,32 @@ class Event(models.Model):
c_email = models.CharField(max_length=512, blank=True) c_email = models.CharField(max_length=512, blank=True)
trustees = models.CharField(max_length=4096) trustees = models.CharField(max_length=4096)
def EID_hr(self):
EID_json = json.loads(self.EID)
return EID_json['hr']
def EID_crypto(self):
EID_json = json.loads(self.EID)
EID_crypto_str = EID_json['crypto']
return json.loads(EID_crypto_str)
def duration(self): def duration(self):
duration_str = self.start_time.strftime("%d-%m-%y %H:%M") duration_str = self.start_time_formatted()
duration_str = duration_str + " - " + self.end_time.strftime("%d-%m-%y %H:%M %Z") duration_str = duration_str + " - " + self.end_time_formatted_utc()
return duration_str return duration_str
def start_time_formatted(self):
return self.start_time.strftime("%d-%m-%y %H:%M")
def start_time_formatted_utc(self):
return self.start_time.strftime("%d-%m-%y %H:%M %Z")
def end_time_formatted(self):
return self.end_time.strftime("%d-%m-%y %H:%M")
def end_time_formatted_utc(self):
return self.end_time.strftime("%d-%m-%y %H:%M %Z")
def status(self): def status(self):
status_str = "" status_str = ""
@ -113,14 +143,4 @@ class Organiser(models.Model):
email = models.CharField(max_length=100, blank=False, null=False) email = models.CharField(max_length=100, blank=False, null=False)
event = models.ForeignKey(Event, on_delete=models.CASCADE) event = models.ForeignKey(Event, on_delete=models.CASCADE)
'''
class Organiser(models.Model):
user = models.ForeignKey(DemoUser, on_delete=models.CASCADE)
event = models.ForeignKey(Event, on_delete=models.CASCADE)
class Trustee(models.Model):
user = models.ForeignKey(DemoUser, on_delete=models.CASCADE)
event = models.ForeignKey(Event, on_delete=models.CASCADE)
'''
#class EventOrganisers():
#event = models.ForeignKey(Event, on_delete=models.CASCADE)

View file

@ -1,14 +1,29 @@
from __future__ import absolute_import from __future__ import absolute_import
import csv
from os import urandom
import base64 import base64
from io import StringIO import json
from os import urandom
from celery import task from celery import task
from django.core.exceptions import ValidationError from django.core.exceptions import ValidationError
from django.core.validators import EmailValidator from django.core.validators import EmailValidator
from django.core.mail import send_mail from django.core.mail import send_mail
from allauthdemo.polls.models import Ballot, Event, EmailUser, AccessKey from django.conf import settings
from .cpp_calls import param, combpk, addec, tally
from allauthdemo.polls.models import AccessKey
from .crypto_rpc import param, combpk, addec, tally
'''
Goal: This py file defines celery tasks that can be initiated
The following tasks were re-implemented by Thomas Smith: generate_event_param, tally_results, generate_combpk, generate_enc
This file was also updated by Vincent de Almeida
'''
# Will store the result of the initial cal to param() from .cpp_calls
group_param = None
def is_valid_email(email): def is_valid_email(email):
try: try:
@ -23,36 +38,59 @@ def create_ballots(poll):
for voter in poll.event.voters.all(): for voter in poll.event.voters.all():
ballot = poll.ballots.create(voter=voter, poll=poll) ballot = poll.ballots.create(voter=voter, poll=poll)
'''
Will generate a key for accessing either the event preparation page or the voting page
'''
def gen_access_key():
return base64.urlsafe_b64encode(urandom(16)).decode('utf-8')
'''
Emails an event preparation URL containing an access key for all of the trustees for an event
'''
@task() @task()
def create_voters(csvfile, event): def email_trustees_prep(trustees, event):
print("Creating voters for event " + event.title) email_subject = "Key Generation and Preparation for Event '" + event.title + "'"
reader = csv.reader(csvfile, delimiter=',')
string = "" # Plain text email - this could be replaced for a HTML-based email in the future
for row in reader: email_body = "Please visit the following URL to prepare the event and generate your trustee secret key:\n\n"
email = string.join(row) url_base = "http://" + settings.DOMAIN + "/event/" + str(event.pk) + "/prepare/?key="
print(email) email_body = email_body + url_base
#testvoter = EmailUser.objects.get_or_create(email='notarealemail@live.com')[0]
#event.voters.add(testvoter) for trustee in trustees:
if (is_valid_email(email)): # Generate a key and create an AccessKey object
voter = EmailUser.objects.get_or_create(email=email)[0] key = gen_access_key()
event.voters.add(voter) AccessKey.objects.create(user=trustee, event=event, key=key)
key = base64.urlsafe_b64encode(urandom(16)).decode('utf-8')
trustee.send_email(email_subject, email_body + key)
'''
Emails the access keys for all of the voters for an event
'''
@task()
def email_voters_a_key(voters, event):
email_subject = "Voting Access for Event '" + event.title + "'"
email_body = 'Key: '
for voter in voters:
# Generate a key and create an AccessKey object
key = gen_access_key()
AccessKey.objects.create(user=voter, event=event, key=key) AccessKey.objects.create(user=voter, event=event, key=key)
send_mail(
'Your Voting Key', voter.send_email(email_subject, email_body + key)
'Key: ' + key,
'from@example.com',
[string.join(row)],
fail_silently=False,
)
''' '''
Updates the EID of an event to contain 2 event IDs: a human readable one (hr) and a crypto one (GP from param())
Starting here: functions re-implemented by Thomas Smith
''' '''
@task() @task()
def generate_event_param(event): def update_EID(event):
event.EID = param() global group_param
if group_param is None:
group_param = param()
EID = {}
EID['hr'] = event.EID
EID['crypto'] = group_param
event.EID = json.dumps(EID)
event.save() event.save()
@task() @task()
@ -98,20 +136,4 @@ def generate_enc(poll):
poll.enc = addec(amount, ciphers) poll.enc = addec(amount, ciphers)
poll.save() poll.save()
'''
End of re-implemented code
'''
@task()
def add(x, y):
return x + y
@task()
def mul(x, y):
return x * y
@task()
def xsum(numbers):
return sum(numbers)

View file

@ -1,13 +1,9 @@
import re import re
from datetime import datetime from datetime import datetime
from django.utils.dateparse import parse_datetime from django.utils.dateparse import parse_datetime
from allauthdemo.polls.models import Event from allauthdemo.polls.models import Event, Poll, PollOption, EmailUser
from allauthdemo.polls.models import Poll
from allauthdemo.polls.models import PollOption
from allauthdemo.polls.models import EmailUser
from allauthdemo.auth.models import DemoUser from allauthdemo.auth.models import DemoUser
''' '''
@ -382,6 +378,7 @@ class EventModelAdaptor:
errors_summary = errors_summary + str(i + 1) + " " errors_summary = errors_summary + str(i + 1) + " "
self.invalid_form_fields['polls_data'] = {'val': polls_json} self.invalid_form_fields['polls_data'] = {'val': polls_json}
self.invalid_form_fields['poll_count'] = {'val': poll_count}
if not valid and len(errors_summary) > 34: if not valid and len(errors_summary) > 34:
errors_summary = errors_summary + "and can be corrected by editing them." errors_summary = errors_summary + "and can be corrected by editing them."
@ -536,7 +533,7 @@ class EventModelAdaptor:
organisers_list = self.form_data.pop('organiser-email-input') organisers_list = self.form_data.pop('organiser-email-input')
for organiser in organisers_list: for organiser in organisers_list:
if organiser != '' and DemoUser.objects.filter(email=organiser).count() == 1: if organiser != '' and DemoUser.objects.filter(email=organiser).exists():
self.organisers.append(DemoUser.objects.filter(email=organiser).get()) self.organisers.append(DemoUser.objects.filter(email=organiser).get())
# Extract the list of trustees # Extract the list of trustees
@ -544,7 +541,7 @@ class EventModelAdaptor:
for trustee in trustees_list: for trustee in trustees_list:
if trustee != '': if trustee != '':
if EmailUser.objects.filter(email=trustee).count() == 1: if EmailUser.objects.filter(email=trustee).exists():
self.trustees.append(EmailUser.objects.filter(email=trustee).get()) self.trustees.append(EmailUser.objects.filter(email=trustee).get())
else: else:
self.trustees.append(EmailUser(email=trustee)) self.trustees.append(EmailUser(email=trustee))
@ -555,7 +552,7 @@ class EventModelAdaptor:
for voter_email in voters_email_list: for voter_email in voters_email_list:
if voter_email != '': if voter_email != '':
if EmailUser.objects.filter(email=voter_email).count() == 1: if EmailUser.objects.filter(email=voter_email).exists():
self.voters.append(EmailUser.objects.filter(email=voter_email).get()) self.voters.append(EmailUser.objects.filter(email=voter_email).get())
else: else:
self.voters.append(EmailUser(email=voter_email)) self.voters.append(EmailUser(email=voter_email))
@ -634,14 +631,15 @@ class EventModelAdaptor:
# Add the list of trustees to the event, making sure they're instantiated # Add the list of trustees to the event, making sure they're instantiated
for trustee in self.trustees: for trustee in self.trustees:
if EmailUser.objects.filter(email=trustee.email).count() == 0: if not EmailUser.objects.filter(email=trustee.email).exists():
trustee.save() trustee.save()
self.event.users_trustees = self.trustees self.event.users_trustees = self.trustees
# Add the list of voters to the event, making sure they're instantiated # Add the list of voters to the event, making sure they're instantiated
# Additionally, generating the AccessKey for voters
for voter in self.voters: for voter in self.voters:
if EmailUser.objects.filter(email=voter.email).count() == 0: if not EmailUser.objects.filter(email=voter.email).exists():
voter.save() voter.save()
self.event.voters = self.voters self.event.voters = self.voters
@ -655,10 +653,10 @@ class EventModelAdaptor:
self.event.save() self.event.save()
# Finally perform a data clean up # Finally return a reference to the event
self.__clear_data() return self.event
def __clear_data(self): def clear_data(self):
self.form_data = None self.form_data = None
self.form_data_validation = None self.form_data_validation = None
self.invalid_form_fields = {} self.invalid_form_fields = {}

View file

@ -17,8 +17,7 @@ from .forms import EventForm, PollForm, OptionFormset, QuestionFormset, Organise
from .models import Event, Poll, PollOption, EmailUser, Ballot, TrusteeKey, Decryption from .models import Event, Poll, PollOption, EmailUser, Ballot, TrusteeKey, Decryption
from allauthdemo.auth.models import DemoUser from allauthdemo.auth.models import DemoUser
from .tasks import create_voters, create_ballots, generate_event_param, generate_combpk, generate_enc, tally_results from .tasks import email_trustees_prep, update_EID, generate_combpk, generate_enc, tally_results
from .cpp_calls import param, addec, combpk, tally
from .utils.EventModelAdaptor import EventModelAdaptor from .utils.EventModelAdaptor import EventModelAdaptor
@ -38,6 +37,7 @@ class EventDetailView(generic.DetailView):
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
context = super(EventDetailView, self).get_context_data(**kwargs) context = super(EventDetailView, self).get_context_data(**kwargs)
context['is_organiser'] = ((not self.request.user.is_anonymous()) and (self.object.users_organisers.filter(email=self.request.user.email).exists())) context['is_organiser'] = ((not self.request.user.is_anonymous()) and (self.object.users_organisers.filter(email=self.request.user.email).exists()))
#context['now'] = timezone.now() #context['now'] = timezone.now()
return context return context
@ -153,28 +153,42 @@ def view_poll(request, event_id, poll_num):
}) })
def event_trustee_setup(request, event_id): def event_trustee_setup(request, event_id):
# Obtain the event and the event preparation access key that's been supplied
event = get_object_or_404(Event, pk=event_id) event = get_object_or_404(Event, pk=event_id)
access_key = request.GET.get('key', None) access_key = request.GET.get('key', None)
if (access_key):
# If the a_key is present, check it's valid and related to a trustee EmailUser instance for this event
if access_key:
email_key = event.keys.filter(key=access_key) email_key = event.keys.filter(key=access_key)
if (email_key.exists() and event.users_trustees.filter(email=email_key[0].user.email).exists()): if email_key.exists() and event.users_trustees.filter(email=email_key[0].user.email).exists():
if (TrusteeKey.objects.filter(event=event, user=email_key[0].user).exists()): if TrusteeKey.objects.filter(event=event, user=email_key[0].user).exists():
messages.add_message(request, messages.WARNING, 'You have already submitted your key for this event') messages.add_message(request, messages.WARNING, 'You have already submitted your key for this event')
return HttpResponseRedirect(reverse("user_home")) return HttpResponseRedirect(reverse("user_home"))
if (request.method == "POST"): if request.method == "POST":
form = EventSetupForm(request.POST) form = EventSetupForm(request.POST)
if (form.is_valid()):
# If form data is valid, create a TrusteeKey object with the supplied public key
if form.is_valid():
public_key = request.POST["public_key"] public_key = request.POST["public_key"]
key = TrusteeKey.objects.get_or_create(event=event, user=email_key[0].user)[0] key = TrusteeKey.objects.get_or_create(event=event, user=email_key[0].user)[0]
key.key = public_key key.key = public_key
key.save() key.save()
if (event.trustee_keys.count() == event.users_trustees.count()): # ready for combpk
# When all trustees have supplied their public key, we can combine them to create a master key
# The event will now be ready to receive votes on the various polls that have been defined -
# voters therefore need to be informed
if event.trustee_keys.count() == event.users_trustees.count():
generate_combpk.delay(event) generate_combpk.delay(event)
messages.add_message(request, messages.SUCCESS, 'You have successfully submitted your public key for this event') # TODO: Create Celery task that generates voting URLs for voters as well as creates the ballots
success_msg = 'You have successfully submitted your public key for this event'
messages.add_message(request, messages.SUCCESS, success_msg)
# This re-direct may not be appropriate for trustees that don't have logins
return HttpResponseRedirect(reverse("user_home")) return HttpResponseRedirect(reverse("user_home"))
else: else:
form = EventSetupForm() form = EventSetupForm()
return render(request, "polls/event_setup.html", {"event": event, "form": form }) return render(request, "polls/event_setup.html", {"event": event, "form": form})
#if no key or is invalid? #if no key or is invalid?
messages.add_message(request, messages.WARNING, 'You do not have permission to access: ' + request.path) messages.add_message(request, messages.WARNING, 'You do not have permission to access: ' + request.path)
@ -247,11 +261,11 @@ def manage_questions(request, event_id):
poll.save() poll.save()
formset = OptionFormset(request.POST, prefix="formset_organiser", instance=poll) formset = OptionFormset(request.POST, prefix="formset_organiser", instance=poll)
if formset.is_valid(): if formset.is_valid():
for form in formset:
formset.save() formset.save()
create_ballots.delay(poll) #create_ballots.delay(poll)
messages.add_message(request, messages.SUCCESS, 'Poll created successfully') messages.add_message(request, messages.SUCCESS, 'Poll created successfully')
return HttpResponseRedirect(reverse('polls:view-poll', kwargs={'event_id': poll.event_id, 'poll_num': event.polls.count() })) return HttpResponseRedirect(reverse('polls:event-polls', args=[poll.event_id]))
return render(request, "polls/create_poll.html", {"event": event, "question_form": form, "option_formset": formset}) return render(request, "polls/create_poll.html", {"event": event, "question_form": form, "option_formset": formset})
elif request.method == "GET": elif request.method == "GET":
@ -296,17 +310,28 @@ def create_event(request):
'''Process form data based on above results''' '''Process form data based on above results'''
if result['success']: if result['success']:
if form_data_valid: if form_data_valid:
# Create the new event using the form data
adaptor.extractData() adaptor.extractData()
adaptor.updateModel() new_event = adaptor.updateModel()
# Update the EID to include the GP in its EID
update_EID.delay(new_event)
# Send an email to all trustees for event preparation
trustees = new_event.users_trustees.all()
email_trustees_prep.delay(trustees, new_event)
adaptor.clear_data()
return HttpResponseRedirect(reverse('polls:index')) return HttpResponseRedirect(reverse('polls:index'))
else: else:
invalid_fields = adaptor.getInvalidFormFields() invalid_fields = adaptor.getInvalidFormFields()
adaptor.clear_data()
return render_invalid(request, events, demo_users, invalid_fields) return render_invalid(request, events, demo_users, invalid_fields)
else: else:
invalid_fields = adaptor.getInvalidFormFields() invalid_fields = adaptor.getInvalidFormFields()
invalid_fields['recaptcha'] = {'error': 'The reCAPTCHA server validation failed, please try again.'} invalid_fields['recaptcha'] = {'error': 'The reCAPTCHA server validation failed, please try again.'}
adaptor.clear_data()
return render_invalid(request, events, demo_users, invalid_fields) return render_invalid(request, events, demo_users, invalid_fields)
elif request.method == "GET": elif request.method == "GET":

View file

@ -26,6 +26,9 @@ TEMPLATE_DEBUG = True
ALLOWED_HOSTS = ['web.server.com'] ALLOWED_HOSTS = ['web.server.com']
# Domain the application is deployed on (Needs changing for production)
# This must not include the protocol nor any trailing slashes as application code should just add this in
DOMAIN = "127.0.0.1:8000"
# Application definition # Application definition
@ -163,8 +166,8 @@ MESSAGE_STORAGE = 'django.contrib.messages.storage.session.SessionStorage'
#EMAIL_PORT = 1025 #EMAIL_PORT = 1025
EMAIL_HOST = 'smtp.gmail.com' EMAIL_HOST = 'smtp.gmail.com'
EMAIL_HOST_USER = 'username@gmail.com' EMAIL_HOST_USER = 'demos2.no.reply@gmail.com'
EMAIL_HOST_PASSWORD = 'password' EMAIL_HOST_PASSWORD = 'Demos2LancsUni'
EMAIL_PORT = 587 EMAIL_PORT = 587
EMAIL_USE_TLS = True EMAIL_USE_TLS = True

View file

@ -150,7 +150,7 @@
//new function //new function
demosEncrypt.generateKeys = function() { demosEncrypt.generateKeys = function() {
parameter = $("#event-param").val(); parameter = $("#event-param").val();
var tempParams = JSON.parse(parameter); var tempParams = JSON.parse(JSON.parse(parameter).crypto);
//the full objects need to be initalised as per the library, then copy the values we need into it //the full objects need to be initalised as per the library, then copy the values we need into it
//I follow Bingsheng's code as to what objects are used in the parameter object //I follow Bingsheng's code as to what objects are used in the parameter object
var ctx = new CTX("BN254CX"); //new context we can use var ctx = new CTX("BN254CX"); //new context we can use

View file

@ -26,11 +26,13 @@
} }
{% endfor %} {% endfor %}
]; ];
{% if invalid_fields.poll_count %}pollCount = {{ invalid_fields.poll_count.val }};{% endif %}
</script> </script>
<!-- The following UI was ported from the Election Authority UI in DEMOS1 by Vincent de Almeida --> <!-- The following UI was ported from the Election Authority UI in DEMOS1 by Vincent de Almeida -->
<!-- The DEMOS1 repository can be found at: https://github.com/mlevogiannis/demos-voting --> <!-- The DEMOS1 repository can be found at: https://github.com/mlevogiannis/demos-voting -->
<!-- TODO: look into i18n translations as this was a feature implemented in DEMOS1 --> <!-- TODO: look into i18n translations as this was a feature implemented in DEMOS1 to enable automatic translations -->
<div class="container"> <div class="container">
<div class="page-header"> <div class="page-header">
<h2>Create New Event with Polls</h2> <h2>Create New Event with Polls</h2>
@ -419,7 +421,7 @@
</div> </div>
</div> </div>
<!-- { Hidden field: Number of Polls } --> <!-- { Hidden field: Number of Polls } -->
<input type="number" id="poll-count-input" name="poll-count-input" class="hidden"> <input type="number" id="poll-count-input" name="poll-count-input" class="hidden" {% if invalid_fields.poll_count %}value="{{ invalid_fields.poll_count.val }}"{% endif %}>
<!-- Organisers --> <!-- Organisers -->
<div class="form-group"> <div class="form-group">
<label for="organisers-input" class="col-sm-3 col-md-2 control-label">Organisers:</label> <!-- This text can be a template variable --> <label for="organisers-input" class="col-sm-3 col-md-2 control-label">Organisers:</label> <!-- This text can be a template variable -->

View file

@ -6,30 +6,45 @@
<div class="container"> <div class="container">
<a href="{% url 'polls:index' %}"><< Back to Events List</a> <a href="{% url 'polls:index' %}"><< Back to Events List</a>
{% if is_organiser %}
<div>
<!-- Heading -->
<div class="col-xs-7 col-sm-9 col-md-10">
<h2>Event: {{object.title}}</h2>
</div>
<!-- Edit Button -->
<div class="col-xs-5 col-sm-3 col-md-2 marginTopEditButton">
<a href="{% url 'polls:edit-event' event.id %}" class="btn btn-primary" style="float: right;">
<span class="fa fa-pencil"></span> Edit
</a>
</div>
</div>
{% else %}
<br/>
<h2>Event: {{object.title}}</h2>
{% endif %}
<div class="overviewPadding {% if is_organiser %}marginTopOverview{% endif %}">
<hr/>
<span>By: {{object.users_organisers.all}}</span>
<br/>
<span>Ready / Prepared: {{ object.prepared }}</span>
<br/>
<span>Event Status: {{ object.status }}</span>
</div>
<br/> <br/>
<h1>Event: {{object.title}}</h1>
<p>By {{object.users_organisers.all}}</p>
<ul class="nav nav-tabs"> <ul class="nav nav-tabs">
<li class="{% block event_nav_details %}{% endblock %}"> <li class="{% block event_nav_details %}{% endblock %}">
<a href="{% url 'polls:view-event' event.id %}">Details</a> <a href="{% url 'polls:view-event' event.id %}"><strong>Summary</strong></a>
</li> </li>
<li class="{% block event_nav_polls %}{% endblock %}"> <li class="{% block event_nav_polls %}{% endblock %}">
<a href="{% url 'polls:event-polls' event.id %}">Polls</a> <a href="{% url 'polls:event-polls' event.id %}"><strong>Polls ({{ object.polls.count }})</strong></a>
</li> </li>
<li class="{% block event_nav_organisers %}{% endblock %}"> <li class="{% block event_nav_organisers %}{% endblock %}">
<a href="{% url 'polls:event-organisers' event.id %}">Organisers</a> <a href="{% url 'polls:event-organisers' event.id %}"><strong>Entities</strong></a>
</li> </li>
{% if event.prepared == False and is_trustee %}
<li class="">
<a href="{% url 'polls:prepare-event' event.id %}">Prepare Event</a>
</li>
{% endif %}
{% if is_organiser %} {% if is_organiser %}
<li class="">
<a href="{% url 'polls:edit-event' event.id %}"><span class="fa fa-pencil"></span> Edit Event</a>
</li>
<li class="{% block event_nav_launch %}{% endblock %}"> <li class="{% block event_nav_launch %}{% endblock %}">
<a href="{% url 'polls:launch-event' event.id %}">Launch Event</a> <a href="{% url 'polls:launch-event' event.id %}"><strong>Advanced</strong></a>
</li> </li>
{% endif %} {% endif %}
</ul> </ul>

View file

@ -4,10 +4,17 @@
{% block event_nav_details %}active{% endblock %} {% block event_nav_details %}active{% endblock %}
{% block event_content %} {% block event_content %}
<h2>Event Details</h2> <br/>
<span>Ready/Prepared: {{ event.prepared }}</span> <span><strong>Start Time:</strong> {{ event.start_time_formatted_utc }}</span>
<br /> <br />
<span>Start Time: {{ event.start_time }}</span> <span><strong>End Time:</strong> {{ event.end_time_formatted_utc }}</span>
<br /> <br/>
<span>End Time: {{ event.end_time }}</span> <br/>
<span><strong>Number of Polls:</strong> {{ event.polls.count }}</span>
<br/>
<span><strong>Number of Organisers:</strong> {{ event.users_organisers.count }}</span>
<br/>
<span><strong>Number of Trustees:</strong> {{ event.users_trustees.count }}</span>
<br/>
<span><strong>Number of Voters:</strong> {{ event.voters.count }}</span>
{% endblock %} {% endblock %}

View file

@ -4,11 +4,16 @@
{% block event_nav_launch %}active{% endblock %} {% block event_nav_launch %}active{% endblock %}
{% block event_content %} {% block event_content %}
<h2>Event Details</h2> <br/>
<span>Trustee keys: {{ event.trustee_keys.count }} / {{ event.users_trustees.count }}</span> <span><strong>Trustee Keys Received:</strong> {{ event.trustee_keys.count }} / {{ event.users_trustees.count }}</span>
<br /> <br />
<span>EID (param): {{ event.EID }} </span> <br/>
<span><strong>Human-readable Event ID:</strong> {{ event.EID_hr }} </span>
<br /> <br />
<span>Public key: {{ event.public_key }} </span> <br/>
<span><strong>Group Param ID:</strong> {{ event.EID_crypto }} </span>
<br />
<br/>
<span><strong>Public key:</strong> {{ event.public_key }} </span>
{% endblock %} {% endblock %}

View file

@ -4,7 +4,8 @@
{% block event_nav_organisers %}active{% endblock %} {% block event_nav_organisers %}active{% endblock %}
{% block event_content %} {% block event_content %}
<h2>Event Organisers</h2> <h2>Event Organisers</h2>
<hr/>
{% if object.users_organisers.all %} {% if object.users_organisers.all %}
<ul class="list-group"> <ul class="list-group">
{% for user in object.users_organisers.all %} {% for user in object.users_organisers.all %}
@ -14,7 +15,9 @@
{% else %} {% else %}
<p>No organisers for this Event.</p> <p>No organisers for this Event.</p>
{% endif %} {% endif %}
<hr/>
<h2>Event Trustees</h2> <h2>Event Trustees</h2>
<hr/>
{% if object.users_trustees.all %} {% if object.users_trustees.all %}
<ul class="list-group"> <ul class="list-group">
{% for user in object.users_trustees.all %} {% for user in object.users_trustees.all %}
@ -24,7 +27,9 @@
{% else %} {% else %}
<p>No trustees for this Event.</p> <p>No trustees for this Event.</p>
{% endif %} {% endif %}
<hr/>
<h2>Voters</h2> <h2>Voters</h2>
<hr/>
{% if object.voters.all %} {% if object.voters.all %}
<ul class="list-group"> <ul class="list-group">
{% for voter in object.voters.all %} {% for voter in object.voters.all %}

View file

@ -4,10 +4,8 @@
{% block event_nav_polls %}active{% endblock %} {% block event_nav_polls %}active{% endblock %}
{% block event_content %} {% block event_content %}
<h2>Event Polls</h2>
{% if object.polls.all %} {% if object.polls.all %}
{% for poll in object.polls.all %} {% for poll in object.polls.all %}
<hr/>
<h3>Poll: {{ poll.question_text }} (<a href="{% url 'polls:view-poll' event_id=event.id poll_num=forloop.counter %}">Edit</a>)</h3> <h3>Poll: {{ poll.question_text }} (<a href="{% url 'polls:view-poll' event_id=event.id poll_num=forloop.counter %}">Edit</a>)</h3>
<br/> <br/>
<h4>Poll Options:</h4> <h4>Poll Options:</h4>
@ -17,12 +15,12 @@
{% endfor %} {% endfor %}
</ul> </ul>
<p>Minimum Number of Option Selections: {{ poll.min_num_selections }}. Maximum Number of Option Selections: {{ poll.max_num_selections }}.</p> <p>Minimum Number of Option Selections: {{ poll.min_num_selections }}. Maximum Number of Option Selections: {{ poll.max_num_selections }}.</p>
<hr/>
{% endfor %} {% endfor %}
{% else %} {% else %}
<p>No polls are available for this Event.</p> <p>No polls are available for this Event.</p>
{% endif %} {% endif %}
{% if is_organiser %} {% if is_organiser %}
<hr/>
<a href="{% url 'polls:create-poll' event.id %}" class="btn btn-default" role="button">Add Poll</a> <a href="{% url 'polls:create-poll' event.id %}" class="btn btn-default" role="button">Add Poll</a>
{% endif %} {% endif %}
{% endblock %} {% endblock %}

View file

@ -7,28 +7,31 @@
{% block content %} {% block content %}
<div class="container"> <div class="container">
<h1>Event: {{event.title}}</h1> <h2>Trustee Event Setup for Event '{{ event.title }}'</h2>
<h2>Trustee Setup</h2> <hr/>
<div class="panel panel-default"> <div class="panel panel-default">
<div class="panel-heading">Public Key</div> <div class="panel-heading"><strong>Step 1: Generate Your Secret Key</strong></div>
<div class="panel panel-body">
<input id="secret-key" class="textinput textInput form-control" type="text"/>
<input id="event-param" type="text" value="{{event.EID}}" hidden/>
<div class="alert alert-warning" role="alert" style="margin-top: 0.75em;">
<strong>Warning:</strong> This key can <strong>NOT</strong> be recalculated if forgotten or lost! Ensure you back this up.
</div>
<button id="keygen-btn" onclick="demosEncrypt.generateKeys()" class="btn btn-success">Generate</button>
<a id="download-btn" role="button" href="#" class="btn btn-primary" disabled>Download</a>
</div>
</div>
<div class="panel panel-default">
<div class="panel-heading"><strong>Step 2: Submit Your Public Key</strong></div>
<div class="panel panel-body"> <div class="panel panel-body">
{% load crispy_forms_tags %} {% load crispy_forms_tags %}
<form method="post" action="" class=""> <form method="post" action="" class="">
{% crispy form %} {% crispy form %}
<input id="public-submit" class="btn btn-default" type="submit" value="Submit" disabled="true"/> <p>Ensure your secret key is backed up before submitting.</p>
<input id="public-submit" class="btn btn-danger" type="submit" value="Submit" disabled/>
</form> </form>
</div> </div>
</div> </div>
<div class="panel panel-default">
<div class="panel-heading">Secret Key</div>
<div class="panel panel-body">
<input id="secret-key" class="textinput textInput form-control" type="text"></input>
<input id="event-param" type="text" value="{{event.EID}}" hidden></input>
<p>Make a backup of this secret key before submitting your public key. This can NOT be recalculated if forgotten!</p>
<button id="keygen-btn" onclick="demosEncrypt.generateKeys()" class="btn btn-default">Generate</button>
<a id="download-btn" role="button" href="#" class="btn btn-default" disabled>Download</a>
</div>
</div>
</div> </div>
{% endblock %} {% endblock %}

1
start_celery_worker.sh Executable file
View file

@ -0,0 +1 @@
celery -A allauthdemo worker -l info

View file

@ -154,7 +154,7 @@ input[type="file"] {
display: none; display: none;
} }
/* Events List page */ /* Events List page / Events Detail */
.statusBtn { .statusBtn {
width: 74px; width: 74px;
@ -167,3 +167,15 @@ input[type="file"] {
.marginTopCreateButton { .marginTopCreateButton {
margin-top: 1.75em; margin-top: 1.75em;
} }
.marginTopEditButton {
margin-top: 0.85em;
}
.marginTopOverview {
margin-top: 5em;
}
.overviewPadding {
padding-left: 16px;
}

View file

@ -705,7 +705,11 @@ function processFileChange(event) {
} }
} }
document.getElementById('files').addEventListener('change', processFileChange, false); var filesHandle = document.getElementById('files');
if(filesHandle) {
filesHandle.addEventListener('change', processFileChange, false);
}
// reCAPTCHA // reCAPTCHA