Initial commit of DEMOS2 with the upgraded 'Create Event' UI. However, there is no input validation currently

This commit is contained in:
vince0656 2018-06-12 13:31:38 +01:00
commit 7084bd1b16
155 changed files with 8102 additions and 0 deletions

9
.gitignore vendored Executable file
View File

@ -0,0 +1,9 @@
*.pyc
*.sqlite
*.sqlite3
__pycache__
migrations/
build
/venv*/
/.idea/

25
LICENSE Executable file
View File

@ -0,0 +1,25 @@
demo-allauth-bootstrap: Copyright (c) 2014 A. Ellerton
django-allauth: Copyright (c) 2010 Raymond Penners and contributors
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
`

26
Makefile Executable file
View File

@ -0,0 +1,26 @@
default: run
DATABASE_NAME=db.sqlite3
configure:
python configure.py
rebuild: deldb syncdb initdb
deldb:
rm -f $(DATABASE_NAME)
syncdb:
python manage.py syncdb --noinput
initdb:
sqlite3 $(DATABASE_NAME) < seed.sql
run:
python manage.py runserver
clean:
find . -name "*.pyc" -print0 | xargs -0 rm
veryclean: deldb clean
rm -f allauthdemo/settings_generated.py

231
Node/demos2-booth.js Executable file
View File

@ -0,0 +1,231 @@
/*
Cryptography functions written by Bingsheng Zhang
Uses the milagro-crypto-js library at:
https://github.com/milagro-crypto/milagro-crypto-js
*/
//Group parameter generator: returns rng object and generators g1,g2 for G1,G2 as well as order
gpGen = function(){
//init, and base generators
var ctx = new CTX("BN254CX");
var n=new ctx.BIG(0); n.rcopy(ctx.ROM_CURVE.CURVE_Order);
//get generator P for G1
P = new ctx.ECP(0);
gx = new ctx.BIG(0);
gx.rcopy(ctx.ROM_CURVE.CURVE_Gx);
if (ctx.ECP.CURVETYPE != ctx.ECP.MONTGOMERY) {
gy = new ctx.BIG(0);
gy.rcopy(ctx.ROM_CURVE.CURVE_Gy);
P.setxy(gx, gy);
} else P.setx(gx);
//get generator Q for G2
var A=new ctx.BIG(0);
var B=new ctx.BIG(0);
A.rcopy(ctx.ROM_CURVE.CURVE_Pxa);
B.rcopy(ctx.ROM_CURVE.CURVE_Pxb);
var Qx=new ctx.FP2(0); Qx.bset(A,B);
A.rcopy(ctx.ROM_CURVE.CURVE_Pya);
B.rcopy(ctx.ROM_CURVE.CURVE_Pyb);
var Qy=new ctx.FP2(0); Qy.bset(A,B);
var Q=new ctx.ECP2();
Q.setxy(Qy,Qy);
return{
n:n,
g1:P,
g2:Q
}
}
//creates ElGamal public and secret key
keyGen=function(params){
var ctx = new CTX("BN254CX");
//set rng
var RAW = [];
var d = new Date();//time for seed, not secure
var rng = new ctx.RAND();
rng.clean();
RAW[0] = d.getSeconds();
RAW[1] = d.getMinutes();
RAW[2] = d.getMilliseconds();
rng.seed(3, RAW);
//ElGamal
var sk = new ctx.BIG(0);
sk = ctx.BIG.randomnum(params.n,rng);
var pk = new ctx.ECP(0);
pk = ctx.PAIR.G1mul(params.g1,sk);
return{
PK:pk,
SK:sk
}
}
//combine multiple public key together
//the input is an array of PKs
combine=function(PKs){
var ctx = new CTX("BN254CX");
var pk=new ctx.ECP();
//copy the first pk
pk.copy(PKs[0]);
//multiple the rest PKs
for(i=1;i<PKs.length;i++){
pk.add(PKs[i]);
}
return{
PK:pk
}
}
//ElGamal encryption
encrypt=function(params,PK, m){
var ctx = new CTX("BN254CX");
//set rand
var RAW = [];
var d = new Date();//time for seed, not secure
var rng = new ctx.RAND();
rng.clean();
RAW[0] = d.getSeconds();
RAW[1] = d.getMinutes();
RAW[2] = d.getMilliseconds();
rng.seed(3, RAW);
var r=new ctx.BIG.randomnum(params.n,rng);
var M=new ctx.BIG(m);
var C1=new ctx.ECP();
C1 = ctx.PAIR.G1mul(params.g1,r);
var gM=new ctx.ECP();
gM = ctx.PAIR.G1mul(params.g1,M);
var C2=new ctx.ECP();
C2 = ctx.PAIR.G1mul(PK,r);
C2.mul(r);
C2.add(gM);
return{
C1:C1,
C2:C2
}
}
//add ciphertexts
add=function(Ciphers){
var ctx = new CTX("BN254CX");
var s1=new ctx.ECP();
var s2=new ctx.ECP();
//copy the first cipher
s1.copy(Ciphers[0].C1);
s2.copy(Ciphers[0].C2);
//multiple the rest ciphertexts
for(i=1;i<Ciphers.length;i++){
s1.add(Ciphers[i].C1);
}
//no idea why I need two loops
for(j=1;j<Ciphers.length;j++){
s2.add(Ciphers[j].C2);
}
return{
C1:s1,
C2:s2
}
}
//ElGamal decryption
decrypt=function(params,SK, C){
var ctx = new CTX("BN254CX");
var D=new ctx.ECP();
D = ctx.PAIR.G1mul(C.C1,SK);
var gM=new ctx.ECP();
gM.copy(C.C2);
gM.sub(D);
//search for message by brute force
var B;
for (j = 0; j < 1000; j++) {
//use D as temp var
B = new ctx.BIG(j);
D = ctx.PAIR.G1mul(params.g1,B);
if (D.equals(gM))
return{
M:j
}
};
return{
M: "Error"
}
}
//ElGamal partial decryption
partDec=function(SK, C){
var ctx = new CTX("BN254CX");
var D=new ctx.ECP();
D = ctx.PAIR.G1mul(C.C1,SK);
return{
D: D
}
}
//Tally, combine partial decryption
//Ds is the array of partial decryptions; C is the ciphertext.
tally=function(params,Ds, C){
var ctx = new CTX("BN254CX");
var D=new ctx.ECP();
D.copy(Ds[0].D);
//combine D
for(i=1;i<Ds.length;i++){
D.add(Ds[i].D);
}
var gM=new ctx.ECP();
gM.copy(C.C2);
gM.sub(D);
//search for message by brute force
var B;
for (j = 0; j < 1000; j++) {
//use D as temp var
B = new ctx.BIG(j);
D = ctx.PAIR.G1mul(params.g1,B);
if (D.equals(gM))
return{
M:j
}
};
return{
M: "Error"
}
}

173
Node/example.html Executable file
View File

@ -0,0 +1,173 @@
<!DOCTYPE html>
<!--- Example code written by Bingsheng Zhang -->
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset="utf-8">
<title>Demos2</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<!-- Bootstrap core CSS -->
<link rel="stylesheet" href="http://netdna.bootstrapcdn.com/bootstrap/3.0.3/css/bootstrap.min.css">
<!-- Optional theme -->
<link rel="stylesheet" href="http://netdna.bootstrapcdn.com/bootstrap/3.0.3/css/bootstrap-theme.min.css">
<style type="text/css">
/* Sticky footer styles */
html,
body {
height: 100%;
/* The html and body elements cannot have any padding or margin. */
}
/* Wrapper for page content to push down footer */
#wrap {
min-height: 100%;
height: auto;
/* Negative indent footer by its height */
margin: 0 auto -60px;
/* Pad bottom by footer height */
padding: 0 0 60px;
}
</style>
<!-- HTML5 Shim and Respond.js IE8 support of HTML5 elements and media queries -->
<!-- WARNING: Respond.js doesn't work if you view the page via file:// -->
<!--[if lt IE 9]>
<script src="https://oss.maxcdn.com/libs/html5shiv/3.7.0/html5shiv.js"></script>
<script src="https://oss.maxcdn.com/libs/respond.js/1.3.0/respond.min.js"></script>
<![endif]-->
</head>
<body>
<!-- Wrap all page content here -->
<div id="wrap">
<div class="form-group">
<input type="text" id="numa" name="A" placeholder="Message" class="form-control">
</br>
<input type="text" id="numc" name="C" placeholder="Key" class="form-control">
</br>
<button type="button" id="add" class="btn btn-success">Encrypt</button>
</div>
<input type="text" id="numb" name="B" placeholder="Ciphertext" class="form-control">
</br>
</br>
<ul id="DecomList">
</ul>
</div>
<!-- Footer -->
<div id="footer">
<div class="container">
<p class="text-muted">Test trustee API</p>
</div>
</div>
<!-- jQuery (necessary for Bootstrap's JavaScript plugins) -->
<script src="https://code.jquery.com/jquery.js"></script>
<!-- Bootstrap core JavaScript -->
<script src="http://netdna.bootstrapcdn.com/bootstrap/3.0.3/js/bootstrap.min.js"></script>
<!-- Crypto JS -->
<script type="text/javascript" src=./core/rand.js></script>
<script type="text/javascript" src=./core/rom_curve.js></script>
<script type="text/javascript" src=./core/rom_field.js></script>
<script type="text/javascript" src=./core/uint64.js></script>
<script type="text/javascript" src=./core/aes.js></script>
<script type="text/javascript" src=./core/big.js></script>
<script type="text/javascript" src=./core/gcm.js></script>
<script type="text/javascript" src=./core/hash256.js></script>
<script type="text/javascript" src=./core/hash384.js></script>
<script type="text/javascript" src=./core/hash512.js></script>
<script type="text/javascript" src=./core/sha3.js></script>
<script type="text/javascript" src=./core/newhope.js></script>
<script type="text/javascript" src=./core/nhs.js></script>
<script type="text/javascript" src=./core/fp.js></script>
<script type="text/javascript" src=./core/fp2.js></script>
<script type="text/javascript" src=./core/fp4.js></script>
<script type="text/javascript" src=./core/fp12.js></script>
<script type="text/javascript" src=./core/ff.js></script>
<script type="text/javascript" src=./core/rsa.js></script>
<script type="text/javascript" src=./core/ecp.js></script>
<script type="text/javascript" src=./core/ecp2.js></script>
<script type="text/javascript" src=./core/ecdh.js></script>
<script type="text/javascript" src=./core/pair.js></script>
<script type="text/javascript" src=./core/mpin.js></script>
<script type="text/javascript" src=./core/ctx.js></script>
<script type="text/javascript" src="demos2-booth.js"></script>
</body>
<script type="text/javascript">
$(document).ready(function(){
$("#add").click(function(){
var params = gpGen();
var keys = keyGen(params);
console.log(keys.PK.toString());
console.log(keys.SK.toString());
var cipher = encrypt(params,keys.PK, 5);
var string_c1 = cipher.C1.toString();
console.log(cipher.C1.toString());
console.log(cipher.C2.toString());
//test decrypt
var message = decrypt(params, keys.SK, cipher);
console.log(message);
//test combine key
var k1 = keyGen(params);
var k2 = keyGen(params);
console.log(k1.PK.toString());
console.log(k2.PK.toString());
var PKs = new Array(k1.PK,k2.PK);
var pk = combine(PKs);
console.log(pk.PK.toString());
//test add cipher
var c1 = encrypt(params,keys.PK, 3);
var c2 = encrypt(params,keys.PK, 4);
var cArray = new Array(c1,c2);
var S = add(cArray);
console.log(S.C1.toString());
console.log(S.C2.toString());
var msg = decrypt(params, keys.SK, S);
console.log(msg);
//test tally
var Tc = encrypt(params,pk.PK, 3);
var D1 = partDec(k1.SK, Tc);
var D2 = partDec(k2.SK, Tc);
var Ds = new Array(D1,D2);
var tar = tally(params, Ds, Tc);
console.log(tar);
//window.document.write("Testing ElGamal encryption"+ "<br>");
//window.document.write("C1: "+ string_c1 + "<br>");
//window.document.write("C1: "+ string_c1 + "<br>");
});
});
</script>
</html>

469
Node/index.js Executable file
View File

@ -0,0 +1,469 @@
/*
Code by Thomas Smith
*/
var port = 8080;
var express = require('express');
var Buffer = require('buffer').Buffer;
var CTX = require('milagro-crypto-js')
var app = express();
/*
var cors = require('cors')
app.use(cors());
*/
app.use(express.static('test'));
//default test
app.get('/', function(request, response){
var data = {
message: 'hello world',
value: 5
}
//response.send('Hey there'+request.ip);
response.json(data);
console.log('request from'+request.ip);
});
//parameter generation function
app.get('/param', function(request, response){
var param = gpGen();
console.log('Generated Param:' + param);
response.json(param);
})
//combine public keys and return the full combined one - JSON Version
app.get('/combpk', function(request, response){
var partials = request.query['PK']
var parsed = [];
console.log('Combining...');
for (var i = partials.length - 1; i >= 0; i--) {
console.log('PK' +i+ ': '+partials[i]);
parsed.push(JSON.parse(partials[i]));
}
var PK = combine(parsed);
response.json(PK);
})
//byte array version
app.get('/cmpkstring', function(request, response){
var ctx = new CTX("BN254CX");
var partials = request.query['PK']
//if there is only one key, partials will be an array of the individual bytes
//if more than one, it will be an array of arrays
//we need to factor for this in code
var noOfKeys = request.query['number'];
var parsed = [];
if(noOfKeys == partials.length)//if we're submitting more than one key
{
console.log('Combining' + noOfKeys + " keys...");
for (var i = partials.length - 1; i >= 0; i--) {
console.log('PK' +i+ ': '+partials[i]);
var bytes = Buffer.from(partials[i].split(','), 'hex');
console.log(bytes)
var pk = new ctx.ECP.fromBytes(bytes);
parsed.push(pk);
}
}
else if(noOfKeys == 1)
{
console.log("Combining just one key");
var bytes = Buffer.from(partials.split(','), 'hex');
console.log(bytes);
var pk = new ctx.ECP.fromBytes(bytes);
parsed.push(pk);
}
response.json(combine(parsed));
})
//addition function on homomorphically encrypted variables
//this may need some work, different method of serialisation maybe?
app.get('/addec', function(request, response){
var c1 = request.query['C1'];
var c2 = request.query['C2'];
var number = request.query['number']; //number of ciphertexts to add
//all the list of ciphertext objects to give to the function
var parsed = [];
var ctx = new CTX("BN254CX");
console.log('Addec:');
if(number == c1.length)
{
for (var i = 0; i < c1.length; i++) {
console.log(i + ".C1: " + c1[i]);
var c1Bytes = Buffer.from(c1[i].split(','), 'hex');
var newC1 = new ctx.ECP.fromBytes(c1Bytes);
var cipher =
{
C1:newC1,
C2:null
};
parsed.push(cipher);
}
for (var j = 0; j < c2.length; j++) {
console.log(j + ".C2: " + c2[j]);
var c2Bytes = Buffer.from(c2[j].split(','), 'hex');
var newC2 = new ctx.ECP.fromBytes(c2Bytes);
parsed[j].C2 = newC2;
}
}
else if(number == 1)
{
console.log("only one cipher");
var c1Bytes = Buffer.from(c1.split(','), 'hex');
var newC1 = new ctx.ECP.fromBytes(c1Bytes);
console.log("C1: " + c1);
var c2Bytes = Buffer.from(c2.split(','), 'hex');
var newC2 = new ctx.ECP.fromBytes(c2Bytes);
console.log("C2: " + c2);
var cipher =
{
C1:newC1,
C2:newC2
};
parsed.push(cipher);
}
response.json(add(parsed));
})
//tally partially decrypted ciphertexts
app.get('/tally', function(request, response){
console.log("called tally");
var amount = request.query['number'];//number of decryptions taking in
var paramString = request.query['param'];//event group parameter in JSON
var partialsStrings = request.query['decs'];//array of partial decryption(s) in bytes
var ciphertextString = request.query['cipher'];//ciphertext being decrypted in JSON
//re-build parameters
var tempParams = JSON.parse(paramString);
var ctx = new CTX("BN254CX"); //new context we can use
var n = new ctx.BIG();
var g1 = new ctx.ECP();
var g2 = new ctx.ECP2();
//copying the values
n.copy(tempParams.n);
g1.copy(tempParams.g1);
g2.copy(tempParams.g2);
var params = {
n:n,
g1:g1,
g2:g2
}
//re-build partial decryptions
var partials = []
if(amount == partialsStrings.length)
{
console.log(amount + " partial decryptions");
for(var i = 0; i < partialsStrings.length; i++)
{
var bytes = Buffer.from(partialsStrings[i].split(','), 'hex');
var dec = {
D:new ctx.ECP.fromBytes(bytes)
}
partials.push(dec);
}
}
else if(amount == 1)
{
console.log("Only one partial decryption received")
console.log(paramString)
var bytes = Buffer.from(partialsStrings.split(','), 'hex');
var dec = {
D:new ctx.ECP.fromBytes(bytes)
}
partials.push(dec);
}
//re-build combined ciphertext
var tempCipher = JSON.parse(ciphertextString);
cipher = {
C1: new ctx.ECP(),
C2: new ctx.ECP()
}
cipher.C1.copy(tempCipher.C1);
cipher.C2.copy(tempCipher.C2);
response.json(tally(params, partials, cipher))
})
var server = app.listen(port, function(){
var host = server.address().address;
var appPort = server.address().port;
console.log('Server listening on ' + host + ':'+ port);
});
/*
Cryptography functions written by Bingsheng Zhang
Uses the milagro-crypto-js library at:
https://github.com/milagro-crypto/milagro-crypto-js
*/
//Group parameter generator: returns rng object and generators g1,g2 for G1,G2 as well as order
gpGen = function(){
//init, and base generators
var ctx = new CTX("BN254CX");
var n=new ctx.BIG(0); n.rcopy(ctx.ROM_CURVE.CURVE_Order);
//get generator P for G1
P = new ctx.ECP(0);
gx = new ctx.BIG(0);
gx.rcopy(ctx.ROM_CURVE.CURVE_Gx);
if (ctx.ECP.CURVETYPE != ctx.ECP.MONTGOMERY) {
gy = new ctx.BIG(0);
gy.rcopy(ctx.ROM_CURVE.CURVE_Gy);
P.setxy(gx, gy);
} else P.setx(gx);
//get generator Q for G2
var A=new ctx.BIG(0);
var B=new ctx.BIG(0);
A.rcopy(ctx.ROM_CURVE.CURVE_Pxa);
B.rcopy(ctx.ROM_CURVE.CURVE_Pxb);
var Qx=new ctx.FP2(0); Qx.bset(A,B);
A.rcopy(ctx.ROM_CURVE.CURVE_Pya);
B.rcopy(ctx.ROM_CURVE.CURVE_Pyb);
var Qy=new ctx.FP2(0); Qy.bset(A,B);
var Q=new ctx.ECP2();
Q.setxy(Qy,Qy);
return{
n:n,
g1:P,
g2:Q
}
}
//creates ElGamal public and secret key
keyGen=function(params){
var ctx = new CTX("BN254CX");
//set rng
var RAW = [];
var d = new Date();//time for seed, not secure
var rng = new ctx.RAND();
rng.clean();
RAW[0] = d.getSeconds();
RAW[1] = d.getMinutes();
RAW[2] = d.getMilliseconds();
rng.seed(3, RAW);
//ElGamal
var sk = new ctx.BIG(0);
sk = ctx.BIG.randomnum(params.n,rng);
var pk = new ctx.ECP(0);
pk = ctx.PAIR.G1mul(params.g1,sk);
return{
PK:pk,
SK:sk
}
}
//combine multiple public key together
//the input is an array of PKs
combine=function(PKs){
var ctx = new CTX("BN254CX");
var pk=new ctx.ECP();
//copy the first pk
pk.copy(PKs[0]);
//multiple the rest PKs
for(i=1;i<PKs.length;i++){
pk.add(PKs[i]);
}
return{
PK:pk
}
}
//ElGamal encryption
encrypt=function(params,PK, m){
var ctx = new CTX("BN254CX");
//set rand
var RAW = [];
var d = new Date();//time for seed, not secure
var rng = new ctx.RAND();
rng.clean();
RAW[0] = d.getSeconds();
RAW[1] = d.getMinutes();
RAW[2] = d.getMilliseconds();
rng.seed(3, RAW);
var r=new ctx.BIG.randomnum(params.n,rng);
var M=new ctx.BIG(m);
var C1=new ctx.ECP();
C1 = ctx.PAIR.G1mul(params.g1,r);
var gM=new ctx.ECP();
gM = ctx.PAIR.G1mul(params.g1,M);
var C2=new ctx.ECP();
C2 = ctx.PAIR.G1mul(PK,r);
C2.mul(r);
C2.add(gM);
return{
C1:C1,
C2:C2
}
}
//add ciphertexts
add=function(Ciphers){
var ctx = new CTX("BN254CX");
var s1=new ctx.ECP();
var s2=new ctx.ECP();
//copy the first cipher
s1.copy(Ciphers[0].C1);
s2.copy(Ciphers[0].C2);
//multiple the rest ciphertexts
for(i=1;i<Ciphers.length;i++){
s1.add(Ciphers[i].C1);
}
//no idea why I need two loops
for(j=1;j<Ciphers.length;j++){
s2.add(Ciphers[j].C2);
}
return{
C1:s1,
C2:s2
}
}
//ElGamal decryption
decrypt=function(params,SK, C){
var ctx = new CTX("BN254CX");
var D=new ctx.ECP();
D = ctx.PAIR.G1mul(C.C1,SK);
var gM=new ctx.ECP();
gM.copy(C.C2);
gM.sub(D);
//search for message by brute force
var B;
for (j = 0; j < 1000; j++) {
//use D as temp var
B = new ctx.BIG(j);
D = ctx.PAIR.G1mul(params.g1,B);
if (D.equals(gM))
return{
M:j
}
};
return{
M: "Error"
}
}
//ElGamal partial decryption
partDec=function(SK, C){
var ctx = new CTX("BN254CX");
var D=new ctx.ECP();
D = ctx.PAIR.G1mul(C.C1,SK);
return{
D: D
}
}
//Tally, combine partial decryption
//Ds is the array of partial decryptions; C is the ciphertext.
tally=function(params,Ds, C){
var ctx = new CTX("BN254CX");
var D=new ctx.ECP();
D.copy(Ds[0].D);
//combine D
for(i=1;i<Ds.length;i++){
D.add(Ds[i].D);
}
var gM=new ctx.ECP();
gM.copy(C.C2);
gM.sub(D);
//search for message by brute force
var B;
for (j = 0; j < 1000; j++) {
//use D as temp var
B = new ctx.BIG(j);
D = ctx.PAIR.G1mul(params.g1,B);
if (D.equals(gM))
return{
M:j
}
};
return{
M: "Error"
}
}

529
Node/package-lock.json generated Executable file
View File

@ -0,0 +1,529 @@
{
"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="
}
}
}

232
Node/test/demos2-booth.js Executable file
View File

@ -0,0 +1,232 @@
/*
Cryptography functions written by Bingsheng Zhang
Uses the milagro-crypto-js library at:
https://github.com/milagro-crypto/milagro-crypto-js
*/
//Group parameter generator: returns rng object and generators g1,g2 for G1,G2 as well as order
gpGen = function(){
//init, and base generators
var ctx = new CTX("BN254CX");
var n=new ctx.BIG(0); n.rcopy(ctx.ROM_CURVE.CURVE_Order);
//get generator P for G1
P = new ctx.ECP(0);
gx = new ctx.BIG(0);
gx.rcopy(ctx.ROM_CURVE.CURVE_Gx);
if (ctx.ECP.CURVETYPE != ctx.ECP.MONTGOMERY) {
gy = new ctx.BIG(0);
gy.rcopy(ctx.ROM_CURVE.CURVE_Gy);
P.setxy(gx, gy);
} else P.setx(gx);
//get generator Q for G2
var A=new ctx.BIG(0);
var B=new ctx.BIG(0);
A.rcopy(ctx.ROM_CURVE.CURVE_Pxa);
B.rcopy(ctx.ROM_CURVE.CURVE_Pxb);
var Qx=new ctx.FP2(0); Qx.bset(A,B);
A.rcopy(ctx.ROM_CURVE.CURVE_Pya);
B.rcopy(ctx.ROM_CURVE.CURVE_Pyb);
var Qy=new ctx.FP2(0); Qy.bset(A,B);
var Q=new ctx.ECP2();
Q.setxy(Qy,Qy);
return{
n:n,
g1:P,
g2:Q
}
}
//creates ElGamal public and secret key
keyGen=function(params){
var ctx = new CTX("BN254CX");
//set rng
var RAW = [];
var d = new Date();//time for seed, not secure
var rng = new ctx.RAND();
rng.clean();
RAW[0] = d.getSeconds();
RAW[1] = d.getMinutes();
RAW[2] = d.getMilliseconds();
rng.seed(3, RAW);
//ElGamal
var sk = new ctx.BIG(0);
sk = ctx.BIG.randomnum(params.n,rng);
var pk = new ctx.ECP(0);
pk = ctx.PAIR.G1mul(params.g1,sk);
return{
PK:pk,
SK:sk
}
}
//combine multiple public key together
//the input is an array of PKs
combine=function(PKs){
var ctx = new CTX("BN254CX");
var pk=new ctx.ECP();
//copy the first pk
pk.copy(PKs[0]);
//multiple the rest PKs
for(i=1;i<PKs.length;i++){
pk.add(PKs[i]);
}
return{
PK:pk
}
}
//ElGamal encryption
encrypt=function(params,PK, m){
var ctx = new CTX("BN254CX");
//set rand
var RAW = [];
var d = new Date();//time for seed, not secure
var rng = new ctx.RAND();
rng.clean();
RAW[0] = d.getSeconds();
RAW[1] = d.getMinutes();
RAW[2] = d.getMilliseconds();
rng.seed(3, RAW);
var r=new ctx.BIG.randomnum(params.n,rng);
var M=new ctx.BIG(m);
var C1=new ctx.ECP();
C1 = ctx.PAIR.G1mul(params.g1,r);
var gM=new ctx.ECP();
gM = ctx.PAIR.G1mul(params.g1,M);
var C2=new ctx.ECP();
C2 = ctx.PAIR.G1mul(PK,r);
C2.mul(r);
C2.add(gM);
return{
C1:C1,
C2:C2
}
}
//add ciphertexts
add=function(Ciphers){
var ctx = new CTX("BN254CX");
var s1=new ctx.ECP();
var s2=new ctx.ECP();
//copy the first cipher
s1.copy(Ciphers[0].C1);
s2.copy(Ciphers[0].C2);
//multiple the rest ciphertexts
for(i=1;i<Ciphers.length;i++){
s1.add(Ciphers[i].C1);
}
//no idea why I need two loops
for(j=1;j<Ciphers.length;j++){
s2.add(Ciphers[j].C2);
}
return{
C1:s1,
C2:s2
}
}
//ElGamal decryption
decrypt=function(params,SK, C){
var ctx = new CTX("BN254CX");
var D=new ctx.ECP();
D = ctx.PAIR.G1mul(C.C1,SK);
var gM=new ctx.ECP();
gM.copy(C.C2);
gM.sub(D);
//search for message by brute force
var B;
for (j = 0; j < 1000; j++) {
//use D as temp var
B = new ctx.BIG(j);
D = ctx.PAIR.G1mul(params.g1,B);
if (D.equals(gM))
return{
M:j
}
};
return{
M: "Error"
}
}
//ElGamal partial decryption
partDec=function(SK, C){
var ctx = new CTX("BN254CX");
var D=new ctx.ECP();
D = ctx.PAIR.G1mul(C.C1,SK);
return{
D: D
}
}
//Tally, combine partial decryption
//Ds is the array of partial decryptions; C is the ciphertext.
tally=function(params,Ds, C){
var ctx = new CTX("BN254CX");
var D=new ctx.ECP();
D.copy(Ds[0].D);
//combine D
for(i=1;i<Ds.length;i++){
D.add(Ds[i].D);
}
var gM=new ctx.ECP();
gM.copy(C.C2);
gM.sub(D);
//search for message by brute force
var B;
for (j = 0; j < 1000; j++) {
//use D as temp var
B = new ctx.BIG(j);
D = ctx.PAIR.G1mul(params.g1,B);
if (D.equals(gM))
return{
M:j
}
};
return{
M: "Error"
}
}

288
Node/test/test_webserver.html Executable file
View File

@ -0,0 +1,288 @@
<!DOCTYPE html>
<html>
<head>
<!-- jQuery (necessary for Bootstrap's JavaScript plugins) -->
<script src="https://code.jquery.com/jquery.js"></script>
<!-- Bootstrap core JavaScript -->
<script src="http://netdna.bootstrapcdn.com/bootstrap/3.0.3/js/bootstrap.min.js"></script>
</head>
<body>
<!-- Crypto JS -->
<script type="text/javascript" src=./core/rand.js></script>
<script type="text/javascript" src=./core/rom_curve.js></script>
<script type="text/javascript" src=./core/rom_field.js></script>
<script type="text/javascript" src=./core/uint64.js></script>
<script type="text/javascript" src=./core/aes.js></script>
<script type="text/javascript" src=./core/big.js></script>
<script type="text/javascript" src=./core/gcm.js></script>
<script type="text/javascript" src=./core/hash256.js></script>
<script type="text/javascript" src=./core/hash384.js></script>
<script type="text/javascript" src=./core/hash512.js></script>
<script type="text/javascript" src=./core/sha3.js></script>
<script type="text/javascript" src=./core/newhope.js></script>
<script type="text/javascript" src=./core/nhs.js></script>
<script type="text/javascript" src=./core/fp.js></script>
<script type="text/javascript" src=./core/fp2.js></script>
<script type="text/javascript" src=./core/fp4.js></script>
<script type="text/javascript" src=./core/fp12.js></script>
<script type="text/javascript" src=./core/ff.js></script>
<script type="text/javascript" src=./core/rsa.js></script>
<script type="text/javascript" src=./core/ecp.js></script>
<script type="text/javascript" src=./core/ecp2.js></script>
<script type="text/javascript" src=./core/ecdh.js></script>
<script type="text/javascript" src=./core/pair.js></script>
<script type="text/javascript" src=./core/mpin.js></script>
<script type="text/javascript" src=./core/ctx.js></script>
<script type="text/javascript" src="demos2-booth.js"></script>
<h1>DEMOS2 Node.js Server testing page</h1>
<button type="button" id="gpGen" class="btn">gpGen</button>
<p id="gpGenLocal">GPGen Local results</p>
<p id="gpGenServer">GPGen Server results</p>
<button type="button" id="addec" class="btn">addec</button>
<p id="addecLocal">addec Local results</p>
<p id="addecServer">addec Server results</p>
<p id="addecResult">addec comparison results</p>
<button type="button" id="combpk" class="btn">combpk</button>
<p id="combpkLocal">combpk Local results</p>
<p id="combpkServer">combpk Server results</p>
<p id="combpkResult">compk comparison results</p>
<button type="button" id="combpkOne" class="btn">combpk (one key)</button>
<p id="combpkLocalOne">combpk Local results</p>
<p id="combpkServerOne">combpk Server results</p>
<p id="combpkResultOne">compk comparison results</p>
<button type="button" id="tally" class="btn">tally</button>
<p id="tallyLocal">tally Local results</p>
<p id="tallyServer">tally Server results</p>
<p id="tallyResult">compk comparison results</p>
<script>
$(document).ready(function(){
$("#gpGen").click(function(){
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
document.getElementById("gpGenServer").innerHTML = this.responseText;
var params = gpGen();
document.getElementById("gpGenLocal").innerHTML = JSON.stringify(params);
}
};
xhttp.open("GET", "/param", true);
xhttp.send();
})
var params = gpGen();
var keys = keyGen(params);
//encrypt number 5
var cipher = encrypt(params,keys.PK, 5);
//test decrypt
var message = decrypt(params, keys.SK, cipher);
$("#addec").click(function(){
var c1 = encrypt(params,keys.PK, 3);
var c2 = encrypt(params,keys.PK, 4);
var cArray = new Array(c1,c2);
var bytes = [];
var queryparams = "?number=2"
queryparams += "&C1=";
c1.C1.toBytes(bytes);
queryparams += bytes.toString();
queryparams += "&C2=";
c1.C2.toBytes(bytes);
queryparams += bytes.toString();
queryparams += '&C1=';
c2.C1.toBytes(bytes);
queryparams += bytes.toString();
queryparams += '&C2=';
c2.C2.toBytes(bytes);
queryparams += bytes.toString();
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
var localAdd = add(cArray);
var localM = decrypt(params, keys.SK, localAdd);
console.log(localM);
document.getElementById("addecLocal").innerHTML = JSON.stringify(localAdd);
console.log("Request: /addec"+queryparams);
document.getElementById("addecServer").innerHTML = this.responseText;
//build object from server
var temp = JSON.parse(this.responseText);
//the values need to be copied in otherwise decryption doesn't work
var ctx = new CTX("BN254CX");
var s1=new ctx.ECP();
var s2=new ctx.ECP();
//copy the first cipher
s1.copy(temp.C1);
s2.copy(temp.C2);
var serverAdd = {
C1:s1,
C2:s2
}
var serverM = decrypt(params, keys.SK, serverAdd);
console.log(serverM);
document.getElementById("addecResult").innerHTML = "Local results: " + localM.M + ", Server results: " + serverM.M + "\n JSON string match: " + (JSON.stringify(localAdd) == this.responseText);
}
};
xhttp.open("GET", "/addec"+queryparams, true);
xhttp.send();
})
$("#combpk").click(function(){
var k1 = keyGen(params);
var k2 = keyGen(params);
var bytes = [];
var queryparams = "?number=2";
queryparams += "&PK=";
k1.PK.toBytes(bytes);
queryparams += bytes.toString();
queryparams += "&PK=";
k2.PK.toBytes(bytes);
queryparams += bytes.toString();
console.log(queryparams);
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
//test combine key
var PKs = new Array(k1.PK,k2.PK);
var pk = combine(PKs);
document.getElementById("combpkServer").innerHTML = this.responseText;
document.getElementById("combpkLocal").innerHTML = JSON.stringify(pk);
var match = (this.responseText == JSON.stringify(pk));
document.getElementById("combpkResult").innerHTML = "Matching strings: " + match;
}
};
xhttp.open("GET", "/cmpkstring"+queryparams, true);
xhttp.send();
})
$("#combpkOne").click(function(){
var k1 = keyGen(params);
var bytes = [];
var queryparams = "?number=1";
queryparams += "&PK=";
k1.PK.toBytes(bytes);
queryparams += bytes.toString();
console.log(queryparams);
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
//test combine key
var PKs = new Array(k1.PK);
var pk = combine(PKs);
document.getElementById("combpkServerOne").innerHTML = this.responseText;
document.getElementById("combpkLocalOne").innerHTML = JSON.stringify(pk);
var match = (this.responseText == JSON.stringify(pk));
document.getElementById("combpkResultOne").innerHTML = "Matching strings: " + match;
}
};
xhttp.open("GET", "/cmpkstring"+queryparams, true);
xhttp.send();
})
$("#tally").click(function(){
//combine some keys first to test tally
var k1 = keyGen(params);
var k2 = keyGen(params);
var PKs = new Array(k1.PK,k2.PK);
var pk = combine(PKs);
var Tc = encrypt(params,pk.PK, 3);
var D1 = partDec(k1.SK, Tc);
var D2 = partDec(k2.SK, Tc);
var Ds = new Array(D1,D2);
var queryparams = "?number=2";
queryparams += "&param=";//JSON format
queryparams += JSON.stringify(params);
queryparams +="&decs=";//will be in byte array format
var bytes = [];
D1.D.toBytes(bytes);
queryparams += bytes.toString();
queryparams +="&decs=";
D2.D.toBytes(bytes);
queryparams += bytes.toString();
queryparams +="&cipher=";//JSON, since it came from the server before
queryparams += JSON.stringify(Tc);
console.log(queryparams);
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
//test tally results
var tar = tally(params, Ds, Tc);
document.getElementById("tallyServer").innerHTML = this.responseText;
document.getElementById("tallyLocal").innerHTML = JSON.stringify(tar);
var match = (this.responseText == JSON.stringify(tar));
document.getElementById("tallyResult").innerHTML = "Matching strings: " + match;
}
};
xhttp.open("GET", "/tally"+queryparams, true);
xhttp.send();
})
});
</script>
</body>
</html>

7
README.md Executable file
View File

@ -0,0 +1,7 @@
# DEMOS2
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 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.

5
allauthdemo/__init__.py Executable file
View File

@ -0,0 +1,5 @@
from __future__ import absolute_import
# This will make sure the app is always imported when
# Django starts so that shared_task will use this app.
from .celery import app as celery_app # noqa

2
allauthdemo/auth/__init__.py Executable file
View File

@ -0,0 +1,2 @@
# See https://docs.djangoproject.com/en/1.7/ref/applications/#for-application-authors
default_app_config = 'allauthdemo.auth.apps.AllAuthDemoAuthAppConfig'

87
allauthdemo/auth/admin.py Executable file
View File

@ -0,0 +1,87 @@
from django.contrib import admin
#from django.utils.html import format_html_join
#from django.utils.safestring import mark_safe
#from django.utils.encoding import python_2_unicode_compatible
from django.utils.translation import ugettext_lazy as _
from django.contrib.auth.admin import UserAdmin
try:
from django.utils.encoding import force_text
except ImportError:
from django.utils.encoding import force_unicode as force_text
from .models import DemoUser, UserProfile
from .forms import DemoUserAdminForm
class UserProfileAdmin(admin.ModelAdmin):
search_fields = ('user', 'dob')
ordering = ('user',)
list_select_related = ('user',)
admin.site.register(UserProfile, UserProfileAdmin)
class UserProfileAdminInline(admin.TabularInline):
model = UserProfile
class DemoUserAdmin(UserAdmin):
"""The project uses a custom User model, so it uses a custom User admin model.
Some related notes at:
https://github.com/dabapps/django-email-as-username/blob/master/emailusernames/admin.py
And:
.../lib/python2.7/site-packages/django/contrib/auth/admin.py
"""
inlines = [
UserProfileAdminInline,
]
#readonly_fields = ('private_uuid', 'public_id')
fieldsets = (
(None, {'fields': ('email', 'password')}),
(_('Personal info'), {'fields': ('first_name', 'last_name', 'display_name')}),
(_('Permissions'), {'fields': ('is_active', 'is_staff', 'is_superuser',
'groups', 'user_permissions')}),
(_('Important dates'), {'fields': ('last_login', 'date_joined')}),
#(_('Ids'), {'fields': ('private_uuid', 'public_id')}),
)
add_fieldsets = (
(None, {
'classes': ('wide',),
'fields': ('email', 'password1', 'password2')}
),
)
list_display = ('email', 'first_name', 'last_name', 'display_name', 'is_staff')
search_fields = ('first_name', 'last_name', 'display_name', 'email')
ordering = ('email',)
form = DemoUserAdminForm
# *** NOTE ***
# As the site uses email instead of username, I'm changing how a User object
# displays or identifies itself in admin. The default in Django (file is
# lib/python2.7/site-packages/django/contrib/auth/models.py) is
#
# def __str__(self):
# return self.get_username()
#
# def natural_key(self):
# return (self.get_username(),)
#
# I'm overriding that a cheap way. I'm not sure if I should replace the entire
# User object ... might be better.
#
#User.__unicode__ = lambda(u): u.email
#User.natural_key = lambda(u): (u.email,)
#admin.site.unregister(DjangoDefaultUser)
admin.site.register(DemoUser, DemoUserAdmin)

8
allauthdemo/auth/apps.py Executable file
View File

@ -0,0 +1,8 @@
from django.apps import AppConfig
class AllAuthDemoAuthAppConfig(AppConfig):
label = "allauthdemo_auth"
name = "allauthdemo.auth" # "all_auth_demo_auth"
verbose_name = "AllAuthDemo Auth"

46
allauthdemo/auth/forms.py Executable file
View File

@ -0,0 +1,46 @@
from django import forms
from django.core.validators import MinLengthValidator
from .models import DemoUser
from captcha.fields import ReCaptchaField
class DemoUserEditForm(forms.ModelForm):
"""Form for viewing and editing name fields in a DemoUser object.
A good reference for Django forms is:
http://pydanny.com/core-concepts-django-modelforms.html
"""
def __init__(self, *args, **kwargs):
# TODO: this doesn't seem to work. Need to get to the bottom of it.
#self.base_fields["display_name"].min_length = 2
#self.base_fields["display_name"].validators.append(MinLengthValidator)
#print self.base_fields['display_name'].validators
super(forms.ModelForm, self).__init__(*args, **kwargs)
class Meta:
model = DemoUser
fields = ('first_name', 'last_name', 'display_name')
class DemoUserAdminForm(forms.ModelForm):
class Meta:
model = DemoUser
fields = ('email', 'first_name', 'last_name', 'display_name', 'is_staff', 'is_active', 'date_joined')
def is_valid(self):
#log.info(force_text(self.errors))
return super(DemoUserAdminForm, self).is_valid()
class NameForm(forms.Form):
your_name = forms.CharField(label='Your name', max_length=100)
class RegistrationForm(forms.Form):
captcha = ReCaptchaField()
def signup(self, request, user):
user.save()

199
allauthdemo/auth/models.py Executable file
View File

@ -0,0 +1,199 @@
import hashlib
from django.db import models
from django.contrib.auth.models import AbstractBaseUser, PermissionsMixin, UserManager
from django.utils.encoding import python_2_unicode_compatible
from django.utils.http import urlquote
from django.core.mail import send_mail
from django.dispatch import receiver
from django.utils import timezone
from django.utils.translation import ugettext_lazy as _
try:
from django.utils.encoding import force_text
except ImportError:
from django.utils.encoding import force_unicode as force_text
from allauth.account.signals import user_signed_up
class MyUserManager(UserManager):
"""
Custom User Model manager.
It overrides default User Model manager's create_user() and create_superuser,
which requires username field.
"""
def create_user(self, email, password=None, **kwargs):
user = self.model(email=email, **kwargs)
user.set_password(password)
user.save()
return user
def create_superuser(self, email, password, **kwargs):
user = self.model(email=email, is_staff=True, is_superuser=True, **kwargs)
user.set_password(password)
user.save()
return user
class DemoUser(AbstractBaseUser, PermissionsMixin):
"""A site-specific user model.
Important: You don't have to use a custom user model. I did it here because
I didn't want a username to be part of the system and I wanted other data
to be part of the user and not in a separate table.
You can avoid the username issue without writing a custom model but it
becomes increasingly obtuse as time goes on. Write a custom user model, then
add a custom admin form and model.
Remember to change ``AUTH_USER_MODEL`` in ``settings.py``.
"""
email = models.EmailField(_('email address'), blank=False, unique=True)
first_name = models.CharField(_('first name'), max_length=40, blank=True, null=True, unique=False)
last_name = models.CharField(_('last name'), max_length=40, blank=True, null=True, unique=False)
display_name = models.CharField(_('display name'), max_length=14, blank=True, null=True, unique=False)
is_staff = models.BooleanField(_('staff status'), default=False,
help_text=_('Designates whether the user can log into this admin '
'site.'))
is_active = models.BooleanField(_('active'), default=True,
help_text=_('Designates whether this user should be treated as '
'active. Unselect this instead of deleting accounts.'))
date_joined = models.DateTimeField(_('date joined'), default=timezone.now)
objects = MyUserManager()
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = []
class Meta:
verbose_name = _('user')
verbose_name_plural = _('users')
db_table = 'auth_user'
abstract = False
def get_absolute_url(self):
# TODO: what is this for?
return "/users/%s/" % urlquote(self.email) # TODO: email ok for this? better to have uuid?
@property
def name(self):
if self.first_name:
return self.first_name
elif self.display_name:
return self.display_name
return 'You'
def get_full_name(self):
"""
Returns the first_name plus the last_name, with a space in between.
"""
full_name = '%s %s' % (self.first_name, self.last_name)
return full_name.strip()
def get_short_name(self):
"Returns the short name for the user."
return self.first_name
def guess_display_name(self):
"""Set a display name, if one isn't already set."""
if self.display_name:
return
if self.first_name and self.last_name:
dn = "%s %s" % (self.first_name, self.last_name[0]) # like "Andrew E"
elif self.first_name:
dn = self.first_name
else:
dn = 'You'
self.display_name = dn.strip()
def email_user(self, subject, message, from_email=None):
"""
Sends an email to this User.
"""
send_mail(subject, message, from_email, [self.email])
def __str__(self):
return self.email
def natural_key(self):
return (self.email,)
@python_2_unicode_compatible
class UserProfile(models.Model):
"""Profile data about a user.
Certain data makes sense to be in the User model itself, but some
is more "profile" data than "user" data. I think this is things like
date-of-birth, favourite colour, etc. If you have domain-specific
profile information you might create additional profile classes, like
say UserGeologistProfile.
"""
user = models.OneToOneField(DemoUser, on_delete=models.CASCADE, primary_key=True, verbose_name='user', related_name='profile')
# I oscillate between whether the ``avatar_url`` should be
# a) in the User model
# b) in this UserProfile model
# c) in a table of it's own to track multiple pictures, with the
# "current" avatar as a foreign key in User or UserProfile.
avatar_url = models.CharField(max_length=256, blank=True, null=True)
dob=models.DateField(verbose_name="dob", blank=True, null=True)
def __str__(self):
return force_text(self.user.email)
class Meta():
db_table = 'user_profile'
@receiver(user_signed_up)
def set_initial_user_names(request, user, sociallogin=None, **kwargs):
"""
When a social account is created successfully and this signal is received,
django-allauth passes in the sociallogin param, giving access to metadata on the remote account, e.g.:
sociallogin.account.provider # e.g. 'twitter'
sociallogin.account.get_avatar_url()
sociallogin.account.get_profile_url()
sociallogin.account.extra_data['screen_name']
See the socialaccount_socialaccount table for more in the 'extra_data' field.
From http://birdhouse.org/blog/2013/12/03/django-allauth-retrieve-firstlast-names-from-fb-twitter-google/comment-page-1/
"""
preferred_avatar_size_pixels=256
picture_url = "http://www.gravatar.com/avatar/{0}?s={1}".format(
hashlib.md5(user.email.encode('UTF-8')).hexdigest(),
preferred_avatar_size_pixels
)
if sociallogin:
# Extract first / last names from social nets and store on User record
if sociallogin.account.provider == 'twitter':
name = sociallogin.account.extra_data['name']
user.first_name = name.split()[0]
user.last_name = name.split()[1]
if sociallogin.account.provider == 'facebook':
user.first_name = sociallogin.account.extra_data['first_name']
user.last_name = sociallogin.account.extra_data['last_name']
#verified = sociallogin.account.extra_data['verified']
picture_url = "http://graph.facebook.com/{0}/picture?width={1}&height={1}".format(
sociallogin.account.uid, preferred_avatar_size_pixels)
if sociallogin.account.provider == 'google':
user.first_name = sociallogin.account.extra_data['given_name']
user.last_name = sociallogin.account.extra_data['family_name']
#verified = sociallogin.account.extra_data['verified_email']
picture_url = sociallogin.account.extra_data['picture']
profile = UserProfile(user=user, avatar_url=picture_url)
profile.save()
user.guess_display_name()
user.save()

3
allauthdemo/auth/tests.py Executable file
View File

@ -0,0 +1,3 @@
from django.test import TestCase
# Create your tests here.

53
allauthdemo/auth/views.py Executable file
View File

@ -0,0 +1,53 @@
from django.contrib import messages
from django.views.generic.base import TemplateResponseMixin, View
from django.views.generic.edit import FormView, ContextMixin, FormMixin, UpdateView
from django.contrib.auth.decorators import login_required
from django.core.urlresolvers import reverse_lazy
from .forms import DemoUserEditForm
class MyModelInstanceMixin(FormMixin):
def get_model_instance(self):
return None
def get_form_kwargs(self):
kwargs = super(MyModelInstanceMixin, self).get_form_kwargs()
instance = self.get_model_instance()
if instance:
kwargs.update({'instance': instance})
return instance
class DemoUserEditView(UpdateView):
"""Allow view and update of basic user data.
In practice this view edits a model, and that model is
the DemoUser object itself, specifically the names that
a user has.
The key to updating an existing model, as compared to creating
a model (i.e. adding a new row to a database) by using the
Django generic view ``UpdateView``, specifically the
``get_object`` method.
"""
form_class = DemoUserEditForm
template_name = "auth/profile.html"
#success_url = '/email-sent/'
view_name = 'account_profile'
success_url = reverse_lazy(view_name)
def get_object(self):
return self.request.user
def form_valid(self, form):
# TODO: not sure how to enforce *minimum* length of a field.
#print "form valid..."
#print "save to user:", self.request.user, form.cleaned_data
form.save()
messages.add_message(self.request, messages.INFO, 'User profile updated')
return super(DemoUserEditView, self).form_valid(form)
account_profile = login_required(DemoUserEditView.as_view())

22
allauthdemo/celery.py Executable file
View File

@ -0,0 +1,22 @@
from __future__ import absolute_import
import os
from celery import Celery
# set the default Django settings module for the 'celery' program.
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'allauthdemo.settings')
from django.conf import settings # noqa
app = Celery('allauthdemo')
# Using a string here means the worker will not have to
# pickle the object when using Windows.
app.config_from_object('django.conf:settings')
app.autodiscover_tasks(lambda: settings.INSTALLED_APPS)
@app.task(bind=True)
def debug_task(self):
print('Request: {0!r}'.format(self.request))

0
allauthdemo/polls/__init__.py Executable file
View File

43
allauthdemo/polls/admin.py Executable file
View File

@ -0,0 +1,43 @@
from django.contrib import admin
# Register your models here.
from allauthdemo.auth.models import DemoUser
from .models import Event, PollOption, Poll, Organiser
"""
from .models import Question, Choice
class ChoiceInline(admin.TabularInline):
model = Choice
extra = 3
class QuestionAdmin(admin.ModelAdmin):
fieldsets = [
(None, {'fields': ['question_text']}),
('Date information', {'fields': ['pub_date'], 'classes': ['collapse']}),
]
inlines = [ChoiceInline]
list_display = ('question_text', 'pub_date', 'was_published_recently')
list_filter = ['pub_date']
search_fields = ['question_text']
"""
class PollAdminInline(admin.TabularInline):
model = Poll
class PollOptionAdminInline(admin.TabularInline):
model = PollOption
class EventAdmin(admin.ModelAdmin):
list_display = ("title",)
filter_horizontal = ('users_organisers', 'users_trustees')
class PollAdmin(admin.ModelAdmin):
inlines = [PollOptionAdminInline]
list_display = ("question_text",)
admin.site.register(Event, EventAdmin)
admin.site.register(Poll, PollAdmin)

7
allauthdemo/polls/apps.py Executable file
View File

@ -0,0 +1,7 @@
from __future__ import unicode_literals
from django.apps import AppConfig
class PollsConfig(AppConfig):
name = 'polls'

61
allauthdemo/polls/cpp_calls.py Executable file
View File

@ -0,0 +1,61 @@
import os
import shlex
import subprocess
import json
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
'''
def param():
jsondict = json.load(urllib2.urlopen('http://localhost:8080/param'))
return json.dumps(jsondict)
def combpk(amount, pks):
url = 'http://localhost:8080/cmpkstring'
querystring = '?number='+str(amount)
for pk in pks:
querystring += '&PK='+pk
print(url+querystring)
jsondict = json.load(urllib2.urlopen(url+querystring))
print(json.dumps(jsondict))
return json.dumps(jsondict)
def addec(amount, ciphers):
url = 'http://localhost:8080/addec'
querystring = '?number='+str(amount)
c1s = ciphers['c1s']
c2s = ciphers['c2s']
for i, value in enumerate(c1s):
querystring += "&C1="+str(c1s[i])
querystring += "&C2="+str(c2s[i])
print(url+querystring)
jsondict = json.load(urllib2.urlopen(url+querystring))
print(json.dumps(jsondict))
return json.dumps(jsondict)
def tally(amount, param, decs, cipher):
url = 'http://localhost:8080/tally'
querystring = '?number='+str(amount)
querystring += '&param='+urllib2.quote(str(param))
testquerystring = '?number='+str(amount)
testquerystring += '&param='+str(param)
for i, value in enumerate(decs):
querystring += "&decs="+str(value)
testquerystring += "&decs="+str(value)
querystring += '&cipher=' + urllib2.quote(str(cipher))
testquerystring += '&cipher=' + str(cipher)
print(url+querystring)
print(url+testquerystring)
jsondict = json.load(urllib2.urlopen(url+querystring))
print('tally: ' + str(jsondict['M']))
return str(jsondict['M'])

383
allauthdemo/polls/forms.py Executable file
View File

@ -0,0 +1,383 @@
from functools import partial
from django import forms
from django.core.validators import MinLengthValidator
from django.template.loader import render_to_string
from django.template import Context
from django.core.exceptions import ValidationError
from django.core.validators import EmailValidator
from django.core.mail import send_mail
from crispy_forms.helper import FormHelper
from crispy_forms.layout import LayoutObject, Layout, TEMPLATE_PACK, Fieldset, ButtonHolder, Submit, Div, Field, HTML
from crispy_forms.bootstrap import StrictButton, TabHolder, Tab, FormActions, PrependedText, PrependedAppendedText, Accordion, AccordionGroup
from captcha.fields import ReCaptchaField
from allauthdemo.auth.models import DemoUser
from .models import Event, Poll, PollOption, Organiser
def is_valid_email(email):
try:
valid_email = EmailValidator()
valid_email(email)
return True
except ValidationError:
return False
class EventForm(forms.ModelForm):
#trustees = forms.CharField(label="Trustee list", widget=forms.Textarea(attrs={'width':"100%", 'cols' : "80", 'rows': "20", }))
voters = forms.CharField(label="Voters", required=False, widget=forms.Textarea(attrs={'width':"100%", 'cols' : "80", 'rows': "20", }))
#self.voters.widget=forms.Textarea(attrs={'width':"100%", 'cols' : "80", 'rows': "20", })
votersTextFile = forms.FileField(required=False)
captcha = ReCaptchaField()
def __init__(self, *args, **kwargs):
self.helper = FormHelper()
self.helper.form_tag = False
self.helper.form_show_labels = False
self.helper.layout = Layout(
Accordion(
AccordionGroup('Event Details',
PrependedText('title', 'Title', placeholder="Title of the Event"),
Div(
PrependedAppendedText('start_time', 'Begins', '<span class="glyphicon glyphicon-calendar"></span>', placeholder="dd/mm/yyyy hh:mm"),
css_class="input-group date col-sm-6"
),
Div(
PrependedAppendedText('end_time', 'Ends', '<span class="glyphicon glyphicon-calendar"></span>', placeholder="dd/mm/yyyy hh:mm"),
css_class="input-group date col-sm-6"
),
Field('captcha')
),
AccordionGroup("Organisers",
HTML("<p>Event creators are automatically made an Organiser. Click and drag the tabs to reorder. Blank fields will be ignored.</p>"),
Formset("organiser_formset",
"polls/create_option.html",
OrganiserFormSetHelper()
),
),
AccordionGroup('Trustees',
HTML("<p>Click and drag the tabs to reorder. Blank fields will be ignored.</p>"),
Formset("trustee_formset",
"polls/create_option.html",
TrusteeFormSetHelper()
),
),
AccordionGroup('Voters',
'voters',
HTML("<p>Comma seperated (.csv) file of valid email addresses</p>"),
'votersTextFile'
),
),
)
super(EventForm, self).__init__(*args, **kwargs)
class Meta:
model = Event
fields = ('title', 'start_time', 'end_time', 'captcha') # TWEAK!!!
widgets = {
'voters': forms.Textarea(attrs={'cols': 80, 'rows': 20})
}
class EventEditForm(forms.ModelForm):
#trustees = forms.CharField(label="Trustee list", widget=forms.Textarea(attrs={'width':"100%", 'cols' : "80", 'rows': "20", }))
voters = forms.CharField(label="Voters", required=False, widget=forms.Textarea(attrs={'width':"100%", 'cols' : "80", 'rows': "20", }))
#self.voters.widget=forms.Textarea(attrs={'width':"100%", 'cols' : "80", 'rows': "20", })
votersTextFile = forms.FileField(required=False)
captcha = ReCaptchaField()
def __init__(self, *args, **kwargs):
self.helper = FormHelper()
self.helper.form_tag = False
self.helper.form_show_labels = False
self.helper.layout = Layout(
Accordion(
AccordionGroup('Event Details',
PrependedText('title', 'Title', placeholder="Title of the Event"),
Div(
PrependedAppendedText('start_time', 'Begins', '<span class="glyphicon glyphicon-calendar"></span>', placeholder="dd/mm/yyyy hh:mm"),
css_class="input-group date col-sm-6"
),
Div(
PrependedAppendedText('end_time', 'Ends', '<span class="glyphicon glyphicon-calendar"></span>', placeholder="dd/mm/yyyy hh:mm"),
css_class="input-group date col-sm-6"
),
Field('captcha')
),
AccordionGroup('Voters',
'voters',
HTML("<p>Comma seperated (.csv) file of valid email addresses</p>"),
'votersTextFile'
),
),
)
super(EventEditForm, self).__init__(*args, **kwargs)
class Meta:
model = Event
fields = ('title', 'start_time', 'end_time', 'captcha') # TWEAK!!!
widgets = {
'voters': forms.Textarea(attrs={'cols': 80, 'rows': 20})
}
class EventSetupForm(forms.Form):
public_key = forms.CharField(max_length=1024, required=True)
def __init__(self, *args, **kwargs):
self.helper = FormHelper()
self.helper.form_tag = False
self.helper.form_show_labels = False
self.helper.layout = Layout(
Field('public_key', id="public-key")
)
super(EventSetupForm, self).__init__(*args, **kwargs)
class Meta:
fields = ('public_key',)
class PollForm(forms.ModelForm):
question_text = forms.CharField(
max_length = 80,
required = True,
)
def __init__(self, *args, **kwargs):
option_formset = kwargs.pop('option_formset', None)
choices = option_formset.total_form_count() if option_formset else 2
self.helper = FormHelper()
self.helper.form_show_labels = False
self.helper.form_tag = False
self.helper.layout = Layout(
Accordion(
AccordionGroup("Poll Details",
PrependedText('question_text', 'Question', placeholder='The question or title of your poll')
),
AccordionGroup("Poll Options",
HTML("<p>Click and drag the tabs to reorder</p>"),
Formset("option_formset",
"polls/create_option.html",
PollOptionFormSetHelper()
)
)
),
)
super(PollForm, self).__init__(*args, **kwargs)
class Meta:
model = Poll
fields = ('question_text',)
class VoteModelChoiceField(forms.ModelChoiceField):
def label_from_instance(self, obj):
return obj.choice_text
class VoteForm(forms.ModelForm):
cipher_text_c1 = forms.CharField(
max_length = 1024,
required = True,
)
cipher_text_c2 = forms.CharField(
max_length = 1024,
required = True,
)
def __init__(self, *args, **kwargs):
super(VoteForm, self).__init__(*args, **kwargs)
self.helper = FormHelper(self)
self.helper.form_show_labels = False
self.helper.form_tag = False
self.helper.layout = Layout(
Field('cipher_text_c1', type="hidden"),
Field('cipher_text_c2', type="hidden")
)
class Meta:
model = Poll
fields = ()#'options')
class DecryptionForm(forms.Form):
text = forms.CharField(max_length=1024, required=True)
def __init__(self, *args, **kwargs):
super(DecryptionForm, self).__init__(*args, **kwargs)
self.helper = FormHelper(self)
self.helper.form_show_labels = False
self.helper.form_tag = False
self.layout = Layout(
PrependedText('text', 'Cipher'),
)
class Meta:
model = Poll
fields = ('enc',)#'options')
class EmailForm(forms.Form):
email = forms.CharField(
max_length = 80,
required = True,
)
def __init__(self, *args, **kwargs):
super(EmailForm, self).__init__(*args, **kwargs)
def clean_email(self):
email = self.cleaned_data['email']
if is_valid_email(email):
return email
raise forms.ValidationError(u'This doesn\'t appear to be a valid email address.')
class OrganiserForm(EmailForm):
def clean_email(self):
email = self.cleaned_data['email']
if is_valid_email(email):
if DemoUser.objects.filter(email=email).exists():
return email
raise forms.ValidationError(u'User "%s" does not exist.' % email)
raise forms.ValidationError(u'This doesn\'t appear to be a valid email address.')
class BaseFormSetHelper(FormHelper):
def __init__(self, *args, **kwargs):
super(BaseFormSetHelper, self).__init__(*args, **kwargs)
self.form_method = 'post'
self.form_show_labels = False
self.form_tag = False
self.layout = Layout()
#Field('organiser_email', placeholder="Option here")
self.render_required_fields = True
class OrganiserFormSetHelper(BaseFormSetHelper):
def __init__(self, *args, **kwargs):
super(OrganiserFormSetHelper, self).__init__(*args, **kwargs)
self.layout = Layout(
Div(
Field('DELETE', css_class='input-small hidden'),
PrependedAppendedText('email', 'Email ', "<span data-toggle='tooltip' title='Delete this Organiser' class='glyphicon glyphicon-trash'></span>", placeholder="Email address of the organiser"),
css_class="formset_object")
)
class DecryptionFormSetHelper(BaseFormSetHelper):
def __init__(self, *args, **kwargs):
super(DecryptionFormSetHelper, self).__init__(*args, **kwargs)
self.form_show_labels = False
self.layout = Layout(
Div(
PrependedText('text', 'Cipher '),
css_class="formset_object")
)
class TrusteeFormSetHelper(BaseFormSetHelper):
def __init__(self, *args, **kwargs):
super(TrusteeFormSetHelper, self).__init__(*args, **kwargs)
self.layout = Layout(
Div(
Field('DELETE', css_class='input-small hidden'),
PrependedAppendedText('email', 'Email ', "<span data-toggle='tooltip' title='Delete this Trustee' class='glyphicon glyphicon-trash'></span>", placeholder="Email address of the trustee"),
css_class="formset_object")
)
class PollOptionFormSetHelper(BaseFormSetHelper):
def __init__(self, *args, **kwargs):
super(PollOptionFormSetHelper, self).__init__(*args, **kwargs)
self.layout = Layout(
Div(
Field('DELETE', css_class='input-small hidden'),
PrependedAppendedText('choice_text', 'Option', "<span class='glyphicon glyphicon-trash'></span>", placeholder="Option"),
css_class="formset_object")
)
class PollOptionFormSetHelper(BaseFormSetHelper):
def __init__(self, *args, **kwargs):
super(PollOptionFormSetHelper, self).__init__(*args, **kwargs)
self.layout = Layout(
Div(
Field('DELETE', css_class='input-small hidden'),
PrependedAppendedText('choice_text', 'Option', "<span class='glyphicon glyphicon-trash'></span>", placeholder="Option"),
css_class="formset_object")
)
### EXPERIMENTAL https://stackoverflow.com/questions/15157262/django-crispy-forms-nesting-a-formset-within-a-form/22053952#22053952
class Formset(LayoutObject):
"""
Layout object. It renders an entire formset, as though it were a Field.
Example::
Formset("attached_files_formset")
"""
template = "%s/formset.html" % TEMPLATE_PACK
def __init__(self, formset_name_in_context, template=None, helper=None):
self.formset_name_in_context = formset_name_in_context
# crispy_forms/layout.py:302 requires us to have a fields property
self.fields = []
# Overrides class variable with an instance level variable
if template:
self.template = template
if helper:
self.helper = helper
def render(self, form, form_style, context, template_pack=TEMPLATE_PACK):
formset = context[self.formset_name_in_context]
return render_to_string(self.template, Context({'wrapper': self,
'formset': formset, 'helper': self.helper}))
class OptionForm(forms.ModelForm):
choice_text = forms.CharField(label=('Option'),
min_length=1, max_length=1024)
def clean_option(self):
return _trim_whitespace(self.cleaned_data['text'])
class Meta:
model = PollOption
fields = ('choice_text',)
OrganiserFormSet = forms.formset_factory(form=OrganiserForm, extra=0, min_num=1, max_num=10, can_delete=True)
TrusteeFormSet = forms.formset_factory(form=EmailForm, extra=1, min_num=1, max_num=10, can_delete=True)
DecryptionFormset = forms.formset_factory(form=DecryptionForm, extra=0, min_num=0, validate_min=True, max_num=20, can_delete=False)
OptionFormset = forms.inlineformset_factory(Poll, PollOption, form=OptionForm, min_num=2, max_num=20, validate_min=True, extra=0, fields=('choice_text',), can_delete=True)
QuestionFormset = forms.inlineformset_factory(Event, Poll, form=PollForm, extra=0, min_num=2, validate_min=True, max_num=20, can_delete=True)
"""
PartialQuestionFormSet = partial(forms.formset_factory, PollQuestionForm, extra=2,
validate_min=True, validate_max=True, min_num=1, max_num=10)
OptionFormset = forms.inlineformset_factory(PollQuestion, QuestionChoice, extra=3, fields=('choice_text',))
QuestionFormset = forms.inlineformset_factory(Poll, PollQuestion,
formset=BasePollQuestionFormset, extra=2, fields=('question_text',))
TenantFormset = forms.inlineformset_factory(Building, Tenant, extra=1, fields=('name',))
BuildingFormset = forms.inlineformset_factory(Block, Building,
formset=BaseBuildingFormset, extra=1, fields=('address',))
AccordionGroup('Poll Questions',
Formset("question_formset",
"polls/create_question.html"
)
),
"""
"""
class PollQuestionForm(forms.ModelForm):
question_text = forms.CharField(
label = "Poll Title",
max_length = 80,
required = True,
)
def __init__(self, *args, **kwargs):
self.helper = FormHelper()
self.helper.form_tag = False
self.helper.layout = Layout(
TabHolder(
Tab('question_text')
),
)
super(PollQuestionForm, self).__init__(*args, **kwargs)
class Meta:
model = PollQuestion
fields = ('question_text',)
"""

110
allauthdemo/polls/models.py Executable file
View File

@ -0,0 +1,110 @@
from __future__ import unicode_literals
from django.db import models
from django import forms
# Create your models here.
import datetime
from django.utils import timezone
from allauthdemo.auth.models import DemoUser
class EmailUser(models.Model):
email = models.CharField(max_length=80, unique=True)
def __unicode__(self):
return self.email
class Event(models.Model):
users_organisers = models.ManyToManyField(DemoUser, blank=True, related_name="organisers")
users_trustees = models.ManyToManyField(EmailUser, blank=True, related_name="trustees")
voters = models.ManyToManyField(EmailUser, blank=True, related_name="voters")
start_time = models.DateTimeField()
end_time = models.DateTimeField()
prepared = models.BooleanField(default=False)
public_key = models.CharField(null=True, blank=False, max_length=1024)
title = models.CharField(max_length=1024)
EID = models.CharField(max_length=2048, blank=True)
creator = models.CharField(max_length=256, blank=True)
c_email = models.CharField(max_length=512, blank=True)
trustees = models.CharField(max_length=4096)
def __str__(self):
return self.title
class TrusteeKey(models.Model):
event = models.ForeignKey(Event, on_delete=models.CASCADE, related_name="trustee_keys")
user = models.ForeignKey(EmailUser, on_delete=models.CASCADE, related_name="trustee_keys")
key = models.CharField(max_length=1024, unique=True) # ideally composite key here, but django doesn't really support yet
class AccessKey(models.Model):
event = models.ForeignKey(Event, on_delete=models.CASCADE, related_name="keys")
user = models.ForeignKey(EmailUser, on_delete=models.CASCADE, related_name="keys")
key = models.CharField(max_length=1024, unique=True) # ideally composite key here, but django doesn't really support yet
#total = models.IntegerField(blank=True, null=True, default=0)
def has_started(self):
return timezone.now() >= self.start
def has_ended(self):
return timezone.now() >= self.end
def __unicode__(self):
return self.title
class Poll(models.Model):
question_text = models.CharField(max_length=200)
total_votes = models.IntegerField(default=0)
min_num_selections = models.IntegerField(default=0)
max_num_selections = models.IntegerField(default=1)
event = models.ForeignKey(Event, on_delete=models.CASCADE, related_name="polls")
enc = models.CharField(max_length=4096, null=True)
#index = models.IntegerField()
def __str__(self):
return self.question_text
class Decryption(models.Model):
event = models.ForeignKey(Event, on_delete=models.CASCADE, related_name="decryptions")
poll = models.ForeignKey(Poll, on_delete=models.CASCADE, related_name="decryptions")
user = models.ForeignKey(EmailUser, on_delete=models.CASCADE, related_name="decryptions")
text = models.CharField(max_length=1024)
#some modification to this class
class Ballot(models.Model):
voter = models.ForeignKey(EmailUser, on_delete=models.CASCADE, related_name="ballots")
poll = models.ForeignKey(Poll, on_delete=models.CASCADE, related_name="ballots")
cipher_text_c1 = models.CharField(max_length=4096)#the encryption system uses two byte strings
cipher_text_c2 = models.CharField(max_length=4096)
cast = models.BooleanField(default=False)
class PollOption(models.Model):
choice_text = models.CharField(max_length=200)
votes = models.IntegerField(default=0)
question = models.ForeignKey(Poll, on_delete=models.CASCADE, related_name="options")
#index = models.IntegerField()
def __str__(self):
return self.choice_text
class Organiser(models.Model):
index = models.IntegerField(default=0)
email = models.CharField(max_length=100, blank=False, null=False)
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

View File

@ -0,0 +1,22 @@
from django.contrib import admin
# Register your models here.
from .models import Question, Choice
class ChoiceInline(admin.TabularInline):
model = Choice
extra = 3
class QuestionAdmin(admin.ModelAdmin):
fieldsets = [
(None, {'fields': ['question_text']}),
('Date information', {'fields': ['pub_date'], 'classes': ['collapse']}),
]
inlines = [ChoiceInline]
list_display = ('question_text', 'pub_date', 'was_published_recently')
list_filter = ['pub_date']
search_fields = ['question_text']
admin.site.register(Question, QuestionAdmin)

View File

@ -0,0 +1,7 @@
from __future__ import unicode_literals
from django.apps import AppConfig
class PollsConfig(AppConfig):
name = 'polls'

Binary file not shown.

View File

View File

@ -0,0 +1,32 @@
from __future__ import unicode_literals
from django.db import models
# Create your models here.
import datetime
from django.utils import timezone
class Question(models.Model):
question_text = models.CharField(max_length=200)
pub_date = models.DateTimeField('date published')
def was_published_recently(self):
now = timezone.now()
return now - datetime.timedelta(days=1) <= self.pub_date <= now
was_published_recently.admin_order_field = 'pub_date'
was_published_recently.boolean = True
was_published_recently.short_description = 'Published recently?'
def __str__(self):
return self.question_text
class Choice(models.Model):
question = models.ForeignKey(Question, on_delete=models.CASCADE)
choice_text = models.CharField(max_length=200)
votes = models.IntegerField(default=0)
def __str__(self):
return self.choice_text

View File

@ -0,0 +1,3 @@
li a {
color: green;
}

View File

@ -0,0 +1,9 @@
from django.test import TestCase
# Create your tests here.
import datetime
from django.utils import timezone
from django.test import TestCase
from django.core.urlresolvers import reverse

23
allauthdemo/polls/polls/urls.py Executable file
View File

@ -0,0 +1,23 @@
from django.conf.urls import url
from django.contrib.auth.decorators import login_required, permission_required
from . import views
app_name = 'polls'
#urlpatterns = [
# url(r'^$', views.index, name='index'),
# ex: /polls/5/
# url(r'^(?P<question_id>[0-9]+)/$', views.detail, name='detail'),
# ex: /polls/5/results/
# url(r'^(?P<question_id>[0-9]+)/results/$', views.results, name='results'),
# ex: /polls/5/vote/
# url(r'^(?P<question_id>[0-9]+)/vote/$', views.vote, name='vote'),
#]
urlpatterns = [
url(r'^$', views.IndexView.as_view(), name='index'),
url(r'^(?P<pk>[0-9]+)/$', login_required(views.DetailView.as_view()), name='detail'),
url(r'^(?P<pk>[0-9]+)/results/$', login_required(views.ResultsView.as_view()), name='results'),
url(r'^(?P<question_id>[0-9]+)/vote/$', login_required(views.vote), name='vote'),
]

View File

@ -0,0 +1,98 @@
from django.shortcuts import render
# Create your views here.
from django.http import HttpResponseRedirect, HttpResponse
from django.core.urlresolvers import reverse
from django.shortcuts import get_object_or_404, render
from django.utils import timezone
from .models import Question, Choice
from django.views import generic
""" from allauthdemo.auth.forms import RegistrationForm
def get_name(request):
# if this is a POST request we need to process the form data
if request.method == 'POST':
# create a form instance and populate it with data from the request:
form = RegistrationForm(request.POST)
# check whether it's valid:
if form.is_valid():
# process the data in form.cleaned_data as required
# ...
# redirect to a new URL:
return HttpResponseRedirect('/thanks/')
# if a GET (or any other method) we'll create a blank form
else:
form = RegistrationForm()
return render(request, 'polls/index.html', {'form': form}) """
class IndexView(generic.ListView):
template_name = 'polls/index.html'
context_object_name = 'latest_question_list'
def get_queryset(self):
"""
Return the last five published questions (not including those set to be
published in the future).
"""
return Question.objects.filter(
pub_date__lte=timezone.now()
).order_by('-pub_date')[:5]
class DetailView(generic.DetailView):
model = Question
template_name = 'polls/detail.html'
def get_queryset(self):
"""
Excludes any questions that aren't published yet.
"""
return Question.objects.filter(pub_date__lte=timezone.now())
class ResultsView(generic.DetailView):
model = Question
template_name = 'polls/results.html'
def index(request):
latest_question_list = Question.objects.order_by('-pub_date')[:5]
context = {'latest_question_list': latest_question_list}
return render(request, 'polls/index.html', context)
def detail(request, question_id):
return HttpResponse("You're looking at question %s." % question_id)
def results(request, question_id):
question = get_object_or_404(Question, pk=question_id)
return render(request, 'polls/results.html', {'question': question})
def vote(request, question_id):
question = get_object_or_404(Question, pk=question_id)
try:
selected_choice = question.choice_set.get(pk=request.POST['choice'])
except (KeyError, Choice.DoesNotExist):
# Redisplay the question voting form.
return render(request, 'polls/detail.html', {
'question': question,
'error_message': "You didn't select a choice.",
})
else:
selected_choice.votes += 1
selected_choice.save()
# Always return an HttpResponseRedirect after successfully dealing
# with POST data. This prevents data from being posted twice if a
# user hits the Back button.
return HttpResponseRedirect(reverse('polls:results', args=(question.id,)))
# ...
def detail(request, question_id):
question = get_object_or_404(Question, pk=question_id)
return render(request, 'polls/detail.html', {'question': question})

View File

@ -0,0 +1,3 @@
li a {
color: green;
}

117
allauthdemo/polls/tasks.py Executable file
View File

@ -0,0 +1,117 @@
from __future__ import absolute_import
import csv
from os import urandom
import base64
from io import StringIO
from celery import task
from django.core.exceptions import ValidationError
from django.core.validators import EmailValidator
from django.core.mail import send_mail
from allauthdemo.polls.models import Ballot, Event, EmailUser, AccessKey
from .cpp_calls import param, combpk, addec, tally
def is_valid_email(email):
try:
valid_email = EmailValidator(whitelist=None)
valid_email(email)
return True
except ValidationError:
return False
@task()
def create_ballots(poll):
for voter in poll.event.voters.all():
ballot = poll.ballots.create(voter=voter, poll=poll)
@task()
def create_voters(csvfile, event):
print("Creating voters for event " + event.title)
reader = csv.reader(csvfile, delimiter=',')
string = ""
for row in reader:
email = string.join(row)
print(email)
#testvoter = EmailUser.objects.get_or_create(email='notarealemail@live.com')[0]
#event.voters.add(testvoter)
if (is_valid_email(email)):
voter = EmailUser.objects.get_or_create(email=email)[0]
event.voters.add(voter)
key = base64.urlsafe_b64encode(urandom(16)).decode('utf-8')
AccessKey.objects.create(user=voter, event=event, key=key)
send_mail(
'Your Voting Key',
'Key: ' + key,
'from@example.com',
[string.join(row)],
fail_silently=False,
)
'''
Starting here: functions re-implemented by Thomas Smith
'''
@task()
def generate_event_param(event):
event.EID = param()
event.save()
@task()
def tally_results(event):
for poll in event.polls.all():
decs = list()
for dec in poll.decryptions.all():
decs.append(dec.text)
amount = len(decs)
result = tally(amount, event.EID, decs, poll.enc)
send_mail(
'Your Results:',
poll.question_text + ": " + result,
'from@example.com',
["fake@fake.com"],
fail_silently=False,
)
print(poll.question_text + ": " + result)
@task()
def generate_combpk(event):
pks = list()
for tkey in event.trustee_keys.all():
pks.append(str(tkey.key))
amount = len(pks)
event.public_key = combpk(amount, pks)
event.prepared = True
event.save()
@task
def generate_enc(poll):
c1s = list()#c1 components of ciphertexts
c2s = list()#c1 components of ciphertexts
for ballot in poll.ballots.all():
if (ballot.cast):
c1s.append(str(ballot.cipher_text_c1))
c2s.append(str(ballot.cipher_text_c2))
ciphers = {
'c1s':c1s,
'c2s':c2s
}
amount = len(c1s)
poll.enc = addec(amount, ciphers)
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

View File

@ -0,0 +1,9 @@
from django import template
register = template.Library()
#get a value for additively homomorphic encryption ballots
#we can't do maths in the template normally so a filter is a way around it
@register.filter
def get_ballot_value(value):
return pow(10, value-1)

12
allauthdemo/polls/tests.py Executable file
View File

@ -0,0 +1,12 @@
from django.test import TestCase
# Create your tests here.
import datetime
from django.utils import timezone
from django.test import TestCase
from django.core.urlresolvers import reverse
from .models import Event
# come up with some tests

36
allauthdemo/polls/urls.py Executable file
View File

@ -0,0 +1,36 @@
from django.conf.urls import url
from django.contrib.auth.decorators import login_required, permission_required
from . import views
app_name = 'polls'
#urlpatterns = [
# url(r'^$', views.index, name='index'),
# ex: /polls/5/
# url(r'^(?P<question_id>[0-9]+)/$', views.detail, name='detail'),
# ex: /polls/5/results/
# url(r'^(?P<question_id>[0-9]+)/results/$', views.results, name='results'),
# ex: /polls/5/vote/
# url(r'^(?P<question_id>[0-9]+)/vote/$', views.vote, name='vote'),
#]
urlpatterns = [
url(r'^vote/(?P<poll_id>[0-9]+)/$', views.test_poll_vote, name='vote-poll'),
url(r'^(?P<pk>[0-9]+)/$', views.EventDetailView.as_view(), name='view-event'),
url(r'^(?P<pk>[0-9]+)/polls$', views.EventDetailPollsView.as_view(), name='event-polls'),
url(r'^(?P<pk>[0-9]+)/organisers$', views.EventDetailOrganisersView.as_view(), name='event-organisers'),
url(r'^$', views.EventListView.as_view(), name='index'),
url(r'^create/$', login_required(views.create_event), name='create-event'),
url(r'^(?P<event_id>[0-9]+)/decrypt/$', login_required(views.event_trustee_decrypt), name='decrypt-event'),
url(r'^(?P<event_id>[0-9]+)/prepare/$', login_required(views.event_trustee_setup), name='prepare-event'),
url(r'^(?P<event_id>[0-9]+)/encrypt/$', login_required(views.event_addec), name='enc-event'),
url(r'^(?P<pk>[0-9]+)/launch/$', views.EventDetailLaunchView.as_view(), name='launch-event'),
url(r'^edit/(?P<event_id>[0-9]+)/$', login_required(views.edit_event), name='edit-event'),
url(r'^(?P<event_id>[0-9]+)/create/poll/$', login_required(views.manage_questions), name='create-poll'),
url(r'^(?P<event_id>[0-9]+)/poll/(?P<poll_num>[0-9]+)/$', login_required(views.view_poll), name='view-poll'),
url(r'^(?P<event_id>[0-9]+)/poll/(?P<poll_num>[0-9]+)/edit$', login_required(views.edit_poll), name='edit-poll'),
#url(r'^(?P<pk>[0-9]+)/$', login_required(views.DetailView.as_view()), name='detail'),
#url(r'^(?P<pk>[0-9]+)/results/$', login_required(views.ResultsView.as_view()), name='results'),
#url(r'^(?P<question_id>[0-9]+)/vote/$', login_required(views.vote), name='vote'),
]

View File

@ -0,0 +1,200 @@
from datetime import datetime
from allauthdemo.polls.models import Event
from allauthdemo.polls.models import Poll
from allauthdemo.polls.models import PollOption
from allauthdemo.polls.models import EmailUser
from allauthdemo.auth.models import DemoUser
'''
Goal: Convert the new form data (from the updated DEMOS2 UI) returned to '/event/create' into
an Event object that can be persisted via a Model to the DB
Author: Vincent de Almeida
Created: 11/07/2018
'''
# TODO: Define a validation function that can do back-end verification on top of the front end validation
# TODO: Validation can make use of __contains__ from QueryDict:
# TODO: https://docs.djangoproject.com/en/2.0/ref/request-response/#django.http.QueryDict
class CreateNewEventModelAdaptor:
# Raw data from form and django
form_data = None
user = None
# Extracted form data
event_name = None
identifier = None
starts_at = None
ends_at = None
min_num_selections = 0
max_num_selections = 0
organisers = []
trustees = []
voters = []
# Each element of the map has a sub array with 2 elements - poll and associated options
polls_options_map = []
# Event Model Object containing all the extracted data
event = None
def __init__(self, form_data, user):
self.form_data = form_data.copy()
self.user = user
# TODO: Call validation func here (incl functionality for verifying CSRF + reCAPTCHA)
self.__extractData()
def __extractData(self):
# Extract name and identifier first
self.event_name = self.form_data.pop('name-input')[0]
self.identifier = self.form_data.pop('identifier-input')[0]
# Extract start and end times as string and convert to datetime
starts_at = self.form_data.pop('vote-start-input')[0]
self.starts_at = datetime.strptime(starts_at, '%Y-%m-%d %H:%M')
ends_at = self.form_data.pop('vote-end-input')[0]
self.ends_at = datetime.strptime(ends_at, '%Y-%m-%d %H:%M')
# Extract the list of organisers
organisers_list = self.form_data.pop('organiser-email-input')
for organiser in organisers_list:
if organiser != '' and DemoUser.objects.filter(email=organiser).count() == 1:
self.organisers.append(DemoUser.objects.filter(email=organiser).get())
# Extract the list of trustees
trustees_list = self.form_data.pop('trustee-email-input')
for trustee in trustees_list:
if trustee != '':
if EmailUser.objects.filter(email=trustee).count() == 1:
self.trustees.append(EmailUser.objects.filter(email=trustee).get())
else:
self.trustees.append(EmailUser(email=trustee))
# Extract the email list of voters
voters_csv_string = self.form_data.pop('voters-list-input')[0].replace(' ', '')
voters_email_list = voters_csv_string.split(',')
for voter_email in voters_email_list:
if voter_email != '':
if EmailUser.objects.filter(email=voter_email).count() == 1:
self.voters.append(EmailUser.objects.filter(email=voter_email).get())
else:
self.voters.append(EmailUser(email=voter_email))
# Extract the min and max number of selections
self.min_num_selections = int(self.form_data.pop('minimum-input')[0])
self.max_num_selections = int(self.form_data.pop('maximum-input')[0])
# Create the Event model object - this does not persist it to the DB
self.event = Event(start_time=self.starts_at,
end_time=self.ends_at,
title=self.event_name,
EID=self.identifier,
creator=self.user.first_name + ' ' + self.user.last_name,
c_email=self.user.email,
trustees=voters_csv_string)
def __gen_polls_options_map(self):
# At the time of writing, you can only define one poll at event-creation time
# Generate PollOption objects from the option data defined in form_data
options = self.form_data.pop('option-name-input')
poll_options_list = []
for option in options:
if option != '':
poll_options_list.append(PollOption(choice_text=option, votes=0))
# Extract required Poll object data and create a poll with its PollOption objects
text = self.form_data.pop('question-input')[0]
votes = 0
poll = Poll(question_text=text,
total_votes=votes,
min_num_selections=self.min_num_selections,
max_num_selections=self.max_num_selections,
event=self.event)
self.polls_options_map.append([poll, poll_options_list])
# Instantiate all the polls and their associated poll options
def __get_instantiated_polls(self):
polls = []
for poll_option_map in self.polls_options_map:
poll = poll_option_map[0]
poll_options = poll_option_map[1]
# Save the poll to the db
poll.save()
# Instantiate poll options
for option in poll_options:
option.question = poll
option.save()
poll.options = poll_options
poll.save()
polls.append(poll)
return polls
def updateModel(self):
# First thing to do is persist the event object to the db
# with basic data before adding things like poll data
self.event.save()
# List of organisers should already be instantiated and present in the db
# so it can just be added
self.event.users_organisers = self.organisers
# Add the list of trustees to the event, making sure they're instantiated
for trustee in self.trustees:
if EmailUser.objects.filter(email=trustee.email).count() == 0:
trustee.save()
self.event.users_trustees = self.trustees
# Add the list of voters to the event, making sure they're instantiated
for voter in self.voters:
if EmailUser.objects.filter(email=voter.email).count() == 0:
voter.save()
self.event.voters = self.voters
# Extract all the poll data for the event and associated poll option data
# This can only be done at this point as the event has been persisted
self.__gen_polls_options_map()
# Get the instantiated list of polls which have already instantiated options
self.event.polls = self.__get_instantiated_polls()
self.event.save()
# Finally perform a data clean up
self.__clear_data()
def __clear_data(self):
self.form_data = None
self.user = None
self.event_name = None
self.identifier = None
self.starts_at = None
self.ends_at = None
self.min_num_selections = 0
self.max_num_selections = 0
self.organisers[:] = []
self.trustees[:] = []
self.voters[:] = []
self.polls_options_map[:] = []
self.event = None

View File

367
allauthdemo/polls/views.py Executable file
View File

@ -0,0 +1,367 @@
import os
from io import StringIO
from django.shortcuts import render
from django.forms import inlineformset_factory, formset_factory
from django.contrib.auth.decorators import user_passes_test
from django.contrib import messages
from django.http import HttpResponseRedirect, HttpResponse, Http404
from django.core.urlresolvers import reverse
from django.shortcuts import get_object_or_404, render, render_to_response
from django.template import RequestContext
from django.core.exceptions import ObjectDoesNotExist
from django.utils import timezone
from django.views import generic
from django.conf import settings
from .forms import EventForm, PollForm, OptionFormset, QuestionFormset, OrganiserFormSet, TrusteeFormSet, VoteForm, EventSetupForm, EventEditForm, DecryptionFormset, DecryptionFormSetHelper
from .models import Event, Poll, PollOption, EmailUser, Ballot, TrusteeKey, Decryption
from allauthdemo.auth.models import DemoUser
from .tasks import create_voters, create_ballots, generate_event_param, generate_combpk, generate_enc, tally_results
from .cpp_calls import param, addec, combpk, tally
from .utils.CreateNewEventModelAdaptor import CreateNewEventModelAdaptor
class EventListView(generic.ListView):
model = Event
def get_context_data(self, **kwargs):
context = super(EventListView, self).get_context_data(**kwargs)
#context['now'] = timezone.now()
return context
class EventDetailView(generic.DetailView):
template_name="polls/event_detail_details.html"
model = Event
def get_context_data(self, **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['now'] = timezone.now()
return context
class EventDetailPollsView(EventDetailView):
template_name="polls/event_detail_polls.html"
class EventDetailOrganisersView(EventDetailView):
template_name="polls/event_detail_organisers.html"
class EventDetailLaunchView(EventDetailView):
template_name="polls/event_detail_launch.html"
class PollDetailView(generic.View):
model = Poll
def get_context_data(self, **kwargs):
context = super(PollDetailView, self).get_context_data(**kwargs)
#context['now'] = timezone.now()
context['form'] = VoteForm(instance=self.object)
context['poll_count'] = self.object.event.polls.all().count()
return context
#my_value = self.kwargs.get('key', 'default_value')
def test_poll_detail(request, event_id, poll_num, key=None):
context = {}
context['form'] = VoteForm(instance=self.object)
context['poll_count'] = self.object.event.polls.all().count()
return render(request, "polls/event_setup.html", context)
def util_get_poll_by_event_index(event, poll_num):
try:
poll_num = int(poll_num)
if ((poll_num < 1) or (poll_num > event.polls.all().count())):
return None
poll = event.polls.filter().order_by('id')[poll_num-1] # index field eventually
except ValueError:
return None
return poll
def edit_poll(request, event_id, poll_num):
event = get_object_or_404(Event, pk=event_id)
event_poll_count = event.polls.all().count()
poll = util_get_poll_by_event_index(event, poll_num)
if (poll == None):
raise Http404("Poll does not exist")
form = PollForm(instance=poll, prefix="main")
formset = OptionFormset(instance=poll, prefix="formset_options")
return render(request, "polls/generic_form.html", {'form_title': "Edit Poll: " + poll.question_text, 'form': form, 'option_formset': formset})
def view_poll(request, event_id, poll_num):
#return HttpResponse(param("012345"))
#return HttpResponse(combpk(param("012345"), "ABzqvL+pqTi+DNLLRcM62RwCoaZTaXVbOs3sk4fc0+Dc 0 AAaQd6S1x+bcgnkDp2ev5mTt34ICQdZIzP9GaqG4x5sy 0" "ABhQay9jI4pZvkAETNwfo8iwJ8eBMkjqplqAiu/FZxMy 0 ABPxj0jVj3rt0VW54iv4tV02gYtujnR41t5gf97asrPs 0 ABfoiW03bsYIUgfAThmjurmOViKy9L89vfkIavhQIblm 1 ABhQay9jI4pZvkAETNwfo8iwJ8eBMkjqplqAiu/FZxMy 0 ABPxj0jVj3rt0VW54iv4tV02gYtujnR41t5gf97asrPs 0 ABfoiW03bsYIUgfAThmjurmOViKy9L89vfkIavhQIblm 1 ABhQay9jI4pZvkAETNwfo8iwJ8eBMkjqplqAiu/FZxMy 0 ABPxj0jVj3rt0VW54iv4tV02gYtujnR41t5gf97asrPs 0 ABfoiW03bsYIUgfAThmjurmOViKy9L89vfkIavhQIblm 1"))
#return HttpResponse(addec("ACMW70Yj3+mJ/FO+6VOSDGYPYHf7NoTXdpInbfzUqYpH 0 ABV4Mo496B0FW3AW/7gY6Fs+oz6BwfwilonMYeriUyV/ 0 AAg+bdGhs3sxSxAc/wcKdBNUy+el8A2b4yVYShNOb8uX 0 AAspJbn5V2AaY4CgLkzCkHwUWbC5nyxrBzw+o4Az8HVM 1 ABKI7o5Yhgi44XwpFnPpLnH0/czbXA8y5vM4ucV8vojo 1 AAwVrT9+dcQsqRZYoI7+QsJvWOgd7JaJpfI6envmC2jU 1 ABIZO0DK4OrdROD805of6iRk2RenonGYmo2qG2IB1sj/ 1 ACMUHQdjGN0wyCd2AgDHMk9u0TpnywNVtamHWopGho8L 0 ABNT5lbE4siC3QklQXRvTwSQPwtme91+UrIr9iXT3y84 1 ABib0mmQ9ZVCrErqFwDgoRp3jHPpjHGQR2vsMVlwM+vI 0 ABvf3cg1NSS8fn6EKJNnTomeoflcEY1WBxkPPKrBBFl+ 0 ACBUZAtolN4HNh+mw4jLZuHzD+/rYHKR5av16PUc6BJF 0", "2"))
#return HttpResponse(tally("ACNQLLQlh+lNm1Dc+X+dEI0ECVLTkxRHjRnzX1OA+HtW 0 AAWOsUZK/G/cjhUee/gPAXop3Bc0CTVG3iDdQxD6+XqV 0", "ACNQLLQlh+lNm1Dc+X+dEI0ECVLTkxRHjRnzX1OA+HtW 0 0 2", "2"))
event = get_object_or_404(Event, pk=event_id)
if (not event.prepared):
messages.add_message(request, messages.WARNING, "This Event isn\'t ready for voting yet.")
return HttpResponseRedirect(reverse("user_home"))
event_poll_count = event.polls.all().count()
prev_poll_index, next_poll_index = False, False
can_vote, has_voted, voter_email, vote_count = False, False, "", 0
poll = util_get_poll_by_event_index(event, poll_num)
if (poll == None):
raise Http404("Poll does not exist")
form = VoteForm(instance=poll)
poll_num = int(poll_num) # now known to be safe as it suceeded in the util function
if (poll_num > 1):
prev_poll_index = (poll_num - 1)
if (poll_num < event_poll_count):
next_poll_index = (poll_num + 1)
access_key = request.GET.get('key', None)
email_key = event.keys.filter(key=access_key)
vote_count = Ballot.objects.filter(poll=poll, cast=True).count()
if (email_key.exists() and event.voters.filter(email=email_key[0].user.email).exists()):
ballot = Ballot.objects.filter(voter=email_key[0].user, poll=poll)
if (ballot.exists() and ballot[0].cast):
has_voted = True
if (access_key and email_key.exists()): #or (can_vote(request.user, event))
voter_email = email_key[0].user.email
can_vote = True
if (request.method == "POST"):
form = VoteForm(request.POST, instance=poll)
if (email_key.exists()):
#return HttpResponse(email_key[0].key)
ballot = Ballot.objects.get_or_create(voter=email_key[0].user, poll=poll)[0]
if (form.is_valid()):
ballot.cipher_text_c1 = request.POST["cipher_text_c1"]
ballot.cipher_text_c2 = request.POST["cipher_text_c2"]
ballot.cast = True
ballot.save()
if (next_poll_index):
return HttpResponseRedirect(reverse('polls:view-poll', kwargs={'event_id': event.id, 'poll_num': next_poll_index }) + "?key=" + email_key[0].key)
else:
return HttpResponse("Voted successfully!") # finished all polls in event
return render(request, "polls/poll_detail.html",
{"object": poll, "poll_num": poll_num , "event": event, "form": form, "poll_count": event.polls.all().count(),
"prev_index": prev_poll_index , "next_index": next_poll_index,
"can_vote": can_vote, "voter_email": voter_email, "has_voted": has_voted, "vote_count": vote_count
})
def event_trustee_setup(request, event_id):
event = get_object_or_404(Event, pk=event_id)
access_key = request.GET.get('key', None)
if (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 (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')
return HttpResponseRedirect(reverse("user_home"))
if (request.method == "POST"):
form = EventSetupForm(request.POST)
if (form.is_valid()):
public_key = request.POST["public_key"]
key = TrusteeKey.objects.get_or_create(event=event, user=email_key[0].user)[0]
key.key = public_key
key.save()
if (event.trustee_keys.count() == event.users_trustees.count()): # ready for combpk
generate_combpk.delay(event)
messages.add_message(request, messages.SUCCESS, 'You have successfully submitted your public key for this event')
return HttpResponseRedirect(reverse("user_home"))
else:
form = EventSetupForm()
return render(request, "polls/event_setup.html", {"event": event, "form": form })
#if no key or is invalid?
messages.add_message(request, messages.WARNING, 'You do not have permission to access: ' + request.path)
return HttpResponseRedirect(reverse("user_home"))
def event_addec(request, event_id):
event = get_object_or_404(Event, pk=event_id)
for poll in event.polls.all():
generate_enc.delay(poll)
return HttpResponse("Generating enc.")
def event_trustee_decrypt(request, event_id):
event = get_object_or_404(Event, pk=event_id)
access_key = request.GET.get('key', None)
if (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 (Decryption.objects.filter(event=event, user=email_key[0].user).exists()):
messages.add_message(request, messages.WARNING, 'You have already provided your decryptions for this event')
#if (event.decryptions.count() == (event.polls.count() * event.users_trustees.count())):
# tally_results.delay(event) # all keys are in
return HttpResponseRedirect(reverse("user_home"))
elif (request.method == "GET"):
initial = []
for poll in event.polls.all():
initial.append({'text': poll.enc })
formset = DecryptionFormset(initial=initial)
else:
formset = DecryptionFormset(request.POST)
data = []
for form in formset:
if form.is_valid():
data.append(form.cleaned_data.get('text'))
if (len(data) == event.polls.count()):
for dec, poll in zip(data, event.polls.all()):
Decryption.objects.get_or_create(user=email_key[0].user, event=event, poll=poll, text=dec)
messages.add_message(request, messages.SUCCESS, 'Decryption complete.')
if (event.decryptions.count() == (event.polls.count() * event.users_trustees.count())):
tally_results.delay(event) # all keys are in
else:
messages.add_message(request, messages.ERROR, 'You didn\'t provide decryptions for every poll. Please try again.')
return HttpResponseRedirect(reverse("user_home"))
return render(request, "polls/event_decrypt.html", {"event": event, "formset": formset, "helper": DecryptionFormSetHelper() })
messages.add_message(request, messages.WARNING, 'You do not have permission to decrypt this Event.')
return HttpResponseRedirect(reverse("user_home"))
def test_poll_vote(request, poll_id):
poll = get_object_or_404(Poll, pk=poll_id)
form = VoteForm(instance=poll)
return render(request, "polls/vote_poll.html", {"vote_form": form, "poll": poll})
def manage_questions(request, event_id):
event = get_object_or_404(Event, pk=event_id)
if (request.user.is_anonymous()) or (not event.users_organisers.filter(email=request.user.email).exists()):
messages.add_message(request, messages.WARNING, 'You do not have permission to access: ' + request.path)
return HttpResponseRedirect(reverse("user_home"))
poll = Poll()
formset = OptionFormset(instance=poll, prefix="formset_organiser")
if request.method == "POST":
form = PollForm(request.POST, prefix="main")
formset = OptionFormset(request.POST, prefix="formset_organiser") # incase form fails, we still want to retain formset data
if form.is_valid():
poll = form.save(commit=False)
poll.event_id = event_id
poll.save()
formset = OptionFormset(request.POST, prefix="formset_organiser", instance=poll)
if formset.is_valid():
for form in formset:
formset.save()
create_ballots.delay(poll)
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 render(request, "polls/create_poll.html", {"event": event, "question_form": form, "option_formset": formset})
elif request.method == "GET":
form = PollForm(prefix="main") #, instance=poll
return render(request, "polls/create_poll.html", {"event": event, "question_form": form, "option_formset": formset})
else:
return HttpResponseNotAllowed()
def create_event(request):
#return HttpResponse(param(str(len("lol_age"))))
event = Event()
if request.method == "POST":
'''if request.FILES: # if there is a file we should ignore voters...?
csvfile = StringIO(request.FILES['votersTextFile'].read().decode('utf-8'))
print("got file from request:")
form = EventForm(request.POST)
organiser_formset = OrganiserFormSet(request.POST, prefix="formset_organiser") # incase form fails, we still want to retain formset data
trustee_formset = TrusteeFormSet(request.POST, prefix="formset_trustee")
if form.is_valid():
event = form.save()
generate_event_param.delay(event)
if request.FILES:
print("creating voters")
create_voters.delay(csvfile, event) # this will be done on event launch ultimately
if organiser_formset.is_valid():
#event.users_organisers.clear()
for oform in organiser_formset:
if (oform.cleaned_data.get('email')):
event.users_organisers.add(DemoUser.objects.get(email=oform.cleaned_data['email']))
event.users_organisers.add(request.user) # always add editor/creator
if trustee_formset.is_valid():
#event.users_trustees.clear()
for tform in trustee_formset:
if (tform.cleaned_data.get('email')):
event.users_trustees.add(EmailUser.objects.get_or_create(email=tform.cleaned_data['email'])[0])
return HttpResponseRedirect('/event/' + str(event.id) + '/create/poll') # change to reverse format
return render(request, "polls/create_event.html", {"event": event, "form": form, "organiser_formset": organiser_formset, "trustee_formset": trustee_formset})'''
adaptor = CreateNewEventModelAdaptor(request.POST, request.user)
adaptor.updateModel()
# TODO: Based on whether validation was successful within update model and whether
# TODO: data was actually persisted, either perform a redirect (success) or flag an error
return HttpResponseRedirect("/event")
elif request.method == "GET":
#form = EventForm()
#organiser_formset = OrganiserFormSet(prefix="formset_organiser", initial=[{'email': request.user.email }])
#trustee_formset = TrusteeFormSet(prefix="formset_trustee", initial=[{'email': request.user.email }])
# Create the formset, specifying the form and formset we want to use.
'''return render(request,
"polls/create_event.html",
{
"event": event,
"form": form,
"organiser_formset": organiser_formset,
"trustee_formset": trustee_formset,
"G_R_SITE_KEY": settings.RECAPTCHA_PUBLIC_KEY
})'''
return render(request, "polls/create_event.html", {"G_R_SITE_KEY": settings.RECAPTCHA_PUBLIC_KEY, "user_email": request.user.email})
else:
return HttpResponseNotAllowed()
def edit_event(request, event_id):
event = get_object_or_404(Event, pk=event_id)
if request.method == "GET":
form = EventEditForm(instance=event, prefix="main")
'''
organiser_initial_data = [{'email': request.user.email}]
trustee_initial_data = []
for user in event.users_organisers.exclude(email=request.user.email):
organiser_initial_data.append({'email': user.email})
organiser_formset = OrganiserFormSet(prefix="formset_organiser", initial=organiser_initial_data)
for trustee in event.users_trustees.all():
trustee_initial_data.append({'email': trustee.email})
trustee_formset = TrusteeFormSet(prefix="formset_trustee", initial=trustee_initial_data)
'''
elif request.method == "POST":
form = EventEditForm(request.POST, instance=event, prefix="main")
#trustee_formset = TrusteeFormSet(request.POST, prefix="formset_trustee")
#organiser_formset = OrganiserFormSet(request.POST, prefix="formset_organiser") # incase form fails, we still want to retain formset data
if form.is_valid():
form.save()
'''
if organiser_formset.is_valid():
event.users_organisers.clear()
for oform in organiser_formset:
if (oform.cleaned_data.get('email')):
event.users_organisers.add(DemoUser.objects.get(email=oform.cleaned_data['email']))
event.users_organisers.add(request.user) # always add editor/creator
if trustee_formset.is_valid():
event.users_trustees.clear()
for tform in trustee_formset:
if (tform.cleaned_data.get('email')):
event.users_trustees.add(EmailUser.objects.get_or_create(email=tform.cleaned_data['email'])[0])
'''
return HttpResponseRedirect(reverse('polls:view-event', kwargs={'pk': event.id}))
return render(request, "polls/generic_form.html", {"form_title": "Edit Event: " + event.title, "form": form}) #"organiser_formset": organiser_formset, "trustee_formset": trustee_formset})
#trustee_formset = TrusteeFormSet(request.POST, prefix="formset_trustee", instance=event)
#class CreatePoll(generic.View):
def can_vote(user, event):
if event.voters.filter(email=user.email).exists():
return True
return False

204
allauthdemo/settings.py Executable file
View File

@ -0,0 +1,204 @@
"""
Django settings for allauthdemo project.
For more information on this file, see
https://docs.djangoproject.com/en/1.6/topics/settings/
For the full list of settings and their values, see
https://docs.djangoproject.com/en/1.6/ref/settings/
"""
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
import os
BASE_DIR = os.path.dirname(os.path.dirname(__file__))
# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/1.6/howto/deployment/checklist/
# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = '!h8#n5wopc#7zq!_)i=l#t=q)7g0g-+&0!=kxv+*&2b7*xb8bm' # TODO: THIS NEEDS CHANGING!!!
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True
TEMPLATE_DEBUG = True
ALLOWED_HOSTS = ['web.server.com']
# Application definition
INSTALLED_APPS = (
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.sites',
'django.contrib.messages',
'django.contrib.staticfiles',
'bootstrap3', # optional module for making bootstrap forms easier
'crispy_forms',
'allauth',
'allauth.account',
'allauth.socialaccount',
#'allauth.socialaccount.providers.facebook',
#'allauth.socialaccount.providers.google',
#'allauth.socialaccount.providers.twitter',
# Core apps
'allauthdemo.auth',
'allauthdemo.polls',
# Celery and captcha
'kombu.transport.django',
'djcelery',
'captcha'
)
MIDDLEWARE_CLASSES = (
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
)
ROOT_URLCONF = 'allauthdemo.urls'
WSGI_APPLICATION = 'allauthdemo.wsgi.application'
# Database
# https://docs.djangoproject.com/en/1.6/ref/settings/#databases
'''
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
}
}
'''
DATABASES = {
'default':{
'ENGINE': 'django.db.backends.mysql',
'NAME':'DEMOS2',
'USER': 'username',
'PASSWORD' : 'password',
'HOST': 'localhost',
'PORT':'3306',
}
}
SILENCED_SYSTEM_CHECKS = ['mysql.E001']
# Internationalization
# https://docs.djangoproject.com/en/1.6/topics/i18n/
LANGUAGE_CODE = 'en-us'
TIME_ZONE = 'UTC'
USE_I18N = True
USE_L10N = True
USE_TZ = True
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/1.6/howto/static-files/
STATIC_URL = '/static/'
# Authentication
AUTHENTICATION_BACKENDS = (
"allauth.account.auth_backends.AuthenticationBackend",
)
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [
# allauth templates: you could copy this directory into your
# project and tweak it according to your needs
# os.path.join(PROJECT_ROOT, 'templates', 'uniform', 'allauth'),
# example project specific templates
os.path.join(BASE_DIR, 'allauthdemo', 'templates', 'plain', 'example'),
#os.path.join(BASE_DIR, 'allauthdemo', 'templates', 'bootstrap', 'allauth'),
os.path.join(BASE_DIR, 'allauthdemo', 'templates', 'allauth'),
os.path.join(BASE_DIR, 'allauthdemo', 'templates'),
],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
# needed for admin templates
'django.contrib.auth.context_processors.auth',
# these *may* not be needed
'django.template.context_processors.debug',
'django.template.context_processors.i18n',
'django.template.context_processors.media',
'django.template.context_processors.static',
'django.contrib.messages.context_processors.messages',
# allauth needs this from django
'django.template.context_processors.request',
# allauth specific context processors
#'allauth.account.context_processors.account',
#'allauth.socialaccount.context_processors.socialaccount',
],
},
}
]
MESSAGE_STORAGE = 'django.contrib.messages.storage.session.SessionStorage'
#EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'
#EMAIL_PORT = 1025
EMAIL_HOST = 'smtp.gmail.com'
EMAIL_HOST_USER = 'username@gmail.com'
EMAIL_HOST_PASSWORD = 'password'
EMAIL_PORT = 587
EMAIL_USE_TLS = True
STATICFILES_DIRS = (
os.path.join(BASE_DIR, "static"),
)
SITE_ID = 1
AUTH_USER_MODEL = 'allauthdemo_auth.DemoUser'
LOGIN_REDIRECT_URL = '/member/'
ACCOUNT_AUTHENTICATION_METHOD = 'email'
ACCOUNT_USERNAME_REQUIRED = False
ACCOUNT_EMAIL_REQUIRED = True
ACCOUNT_USERNAME_MIN_LENGTH = 3
# ACCOUNT_EMAIL_VERIFICATION = 'none' # testing...
ACCOUNT_USER_MODEL_USERNAME_FIELD = None
SOCIALACCOUNT_AUTO_SIGNUP = False # require social accounts to use the signup form ... I think
ACCOUNT_SIGNUP_FORM_CLASS = 'allauthdemo.auth.forms.RegistrationForm'
# For custom sign-up form:
# http://stackoverflow.com/questions/12303478/how-to-customize-user-profile-when-using-django-allauth
# Google reCAPTCHA
RECAPTCHA_PUBLIC_KEY = '6Ld1Z10UAAAAAG1ExO-I-AivOvQqakHIkYwu5adT'
RECAPTCHA_PRIVATE_KEY = '6Ld1Z10UAAAAAG3-XrkE3Ds0FnKIOa3LloA6wI14'
NOCAPTCHA = True # v2 (no puzzle, just click)
# crispy_forms
CRISPY_FAIL_SILENTLY = not DEBUG
CRISPY_TEMPLATE_PACK = 'bootstrap3'
CELERY_RESULT_BACKEND='djcelery.backends.database:DatabaseBackend'
BROKER_URL = 'django://'

166
allauthdemo/settings.template.py Executable file
View File

@ -0,0 +1,166 @@
"""
Django settings for allauthdemo project.
For more information on this file, see
https://docs.djangoproject.com/en/1.6/topics/settings/
For the full list of settings and their values, see
https://docs.djangoproject.com/en/1.6/ref/settings/
"""
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
import os
BASE_DIR = os.path.dirname(os.path.dirname(__file__))
# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/1.6/howto/deployment/checklist/
# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = '!h8#n5wopc#7zq!_)i=l#t=q)7g0g-+&0!=kxv+*&2b7*xb8bm'
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True
TEMPLATE_DEBUG = True
ALLOWED_HOSTS = []
# Application definition
INSTALLED_APPS = (
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.sites',
'django.contrib.messages',
'django.contrib.staticfiles',
'bootstrap3', # optional module for making bootstrap forms easier
'allauth',
'allauth.account',
'allauth.socialaccount',
{% if facebook or google %}
{% if facebook %}
'allauth.socialaccount.providers.facebook', # enabled by configure
{% endif %}
{% if google %}
'allauth.socialaccount.providers.google', # enabled by configure
{% endif %}
#'allauth.socialaccount.providers.dropbox',
#'allauth.socialaccount.providers.github',
#'allauth.socialaccount.providers.linkedin',
# etc
{% endif %}
'allauthdemo.auth',
'allauthdemo.demo',
)
MIDDLEWARE_CLASSES = (
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
)
ROOT_URLCONF = 'allauthdemo.urls'
WSGI_APPLICATION = 'allauthdemo.wsgi.application'
# Database
# https://docs.djangoproject.com/en/1.6/ref/settings/#databases
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
}
}
# Internationalization
# https://docs.djangoproject.com/en/1.6/topics/i18n/
LANGUAGE_CODE = 'en-us'
TIME_ZONE = 'UTC'
USE_I18N = True
USE_L10N = True
USE_TZ = True
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/1.6/howto/static-files/
STATIC_URL = '/static/'
# Authentication
AUTHENTICATION_BACKENDS = (
"allauth.account.auth_backends.AuthenticationBackend",
)
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [
# allauth templates: you could copy this directory into your
# project and tweak it according to your needs
# os.path.join(PROJECT_ROOT, 'templates', 'uniform', 'allauth'),
# example project specific templates
os.path.join(BASE_DIR, 'allauthdemo', 'templates', 'plain', 'example'),
#os.path.join(BASE_DIR, 'allauthdemo', 'templates', 'bootstrap', 'allauth'),
os.path.join(BASE_DIR, 'allauthdemo', 'templates', 'allauth'),
os.path.join(BASE_DIR, 'allauthdemo', 'templates'),
],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
# needed for admin templates
'django.contrib.auth.context_processors.auth',
# these *may* not be needed
'django.template.context_processors.debug',
'django.template.context_processors.i18n',
'django.template.context_processors.media',
'django.template.context_processors.static',
'django.contrib.messages.context_processors.messages',
# allauth needs this from django
'django.template.context_processors.request',
# allauth specific context processors
#'allauth.account.context_processors.account',
#'allauth.socialaccount.context_processors.socialaccount',
],
},
}
]
MESSAGE_STORAGE = 'django.contrib.messages.storage.session.SessionStorage'
EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'
STATICFILES_DIRS = (
os.path.join(BASE_DIR, "static"),
)
SITE_ID = 1
AUTH_USER_MODEL = 'allauthdemo_auth.DemoUser'
LOGIN_REDIRECT_URL = '/member/'
ACCOUNT_AUTHENTICATION_METHOD = 'email'
ACCOUNT_USERNAME_REQUIRED = False
ACCOUNT_EMAIL_REQUIRED = True
ACCOUNT_USERNAME_MIN_LENGTH = 3
# ACCOUNT_EMAIL_VERIFICATION = 'none' # testing...
ACCOUNT_USER_MODEL_USERNAME_FIELD = None
SOCIALACCOUNT_AUTO_SIGNUP = False # require social accounts to use the signup form ... I think
# For custom sign-up form:
# http://stackoverflow.com/questions/12303478/how-to-customize-user-profile-when-using-django-allauth

15
allauthdemo/setup.py Executable file
View File

@ -0,0 +1,15 @@
from distutils.core import setup, Extension
demos_encrypt = Extension('demos_encrypt',
sources = ['/Users/carey/Downloads/EC-ElGamal/BNsupport.cpp', '/Users/carey/Downloads/EC-ElGamal/bn_pair.cpp', '/Users/carey/Downloads/EC-ElGamal/zzn12a.cpp',
'/Users/carey/Downloads/EC-ElGamal/ecn2.cpp', '/Users/carey/Downloads/EC-ElGamal/zzn4.cpp', '/Users/carey/Downloads/EC-ElGamal/zzn2.cpp',
'/Users/carey/Downloads/EC-ElGamal/big.cpp', '/Users/carey/Downloads/EC-ElGamal/zzn.cpp', '/Users/carey/Downloads/EC-ElGamal/ecn.cpp'],
include_dirs = ['/Users/carey/Downloads/EC-ElGamal'],
library_dirs = ['/Users/carey/Downloads/EC-ElGamal'],
extra_link_args=[''],
libraries=['miracl'])
setup (name = 'demos_encrypt',
version = '1.0',
description = 'This is the demos2 package',
ext_modules = [demos_encrypt])

View File

@ -0,0 +1,3 @@
This are the files from the django-allauth example
pretty much as-is, except for some visual tweaks
and use of a different bootstrap form renderer.

View File

@ -0,0 +1,45 @@
{% extends "bases/bootstrap-member.html" %}
{% load i18n %}
{% load bootstrap3 %}
{% block content %}
<div class=container>
{% bootstrap_messages %}
<h1>{% trans 'My Account' %}</h1>
<ul class="nav nav-tabs">
<li class="{% block account_nav_events %}{% endblock %}">
<a href="{% url 'account_events' %}">{% trans 'My Events' %}</a>
</li>
<li class="{% block account_nav_email %}{% endblock %}">
<a href="{% url 'account_email' %}">{% trans 'E-mail Addresses' %}</a>
</li>
<li class="{% block account_nav_change_password %}{% endblock %}">
<a href="{% url 'account_change_password' %}">{% trans 'Change Password' %}</a>
</li>
{% url 'socialaccount_connections' as connections_url %}
{% if connections_url %}
<li class="{% block account_nav_socialaccount_connections %}{% endblock %}">
<a href="{{ connections_url}}">{% trans 'Connected Accounts' %}</a>
</li>
{% else %}
<li>No connections url</li>
{% endif %}
</ul>
{% block account_content %}
{% endblock %}
</div>
{% endblock %}
{#
{% block appjs %}
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
{% block appjs_jquery %}
{% endblock %}
{% endblock %}
#}

View File

@ -0,0 +1,38 @@
{% extends "bases/bootstrap-member.html" %}
{% load i18n %}
{% block content %}
<div class=container>
<h1>{% trans 'My Account' %}</h1>
<ul class="nav nav-tabs">
<li class="{% block account_tab_events %}{% endblock %}">
<a href="#">{% trans 'My Events' %}</a>
</li>
<li class="{% block account_nav_change_password %}{% endblock %}">
<a href="{% url 'account_change_password' %}">{% trans 'Change Password' %}</a>
</li>
{% url 'socialaccount_connections' as connections_url %}
{% if connections_url %}
<li class="{% block account_nav_socialaccount_connections %}{% endblock %}">
<a href="{{ connections_url}}">{% trans 'Connected Accounts' %}</a>
</li>
{% else %}
<li>No connections url</li>
{% endif %}
</ul>
{% block account_content %}
{% endblock %}
</div>
{% endblock %}
{#
{% block appjs %}
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
{% block appjs_jquery %}
{% endblock %}
{% endblock %}
#}

View File

@ -0,0 +1,90 @@
{% extends "account/base.html" %}
{% load i18n %}
{% load bootstrap3 %}
{% block head_title %}{% trans "Account" %}{% endblock %}
{% block account_nav_email %}active{% endblock %}
{% block account_content %}
{% if user.emailaddress_set.all %}
<p>{% trans 'The following e-mail addresses are associated to your account:' %}</p>
<form action="{% url 'account_email' %}" class="email_list uniForm" method="post">
{% csrf_token %}
<table class="table">
<thead>
<tr>
<th>
{% trans 'E-mail' %}
</th>
<th>
{% trans 'Status' %}
</th>
</tr>
</thead>
<tbody>
{% for emailaddress in user.emailaddress_set.all %}
<tr>
<td>
<label class="radio" for="email_radio_{{forloop.counter}}" class="{% if emailaddress.primary %}primary_email{%endif%}">
<input id="email_radio_{{forloop.counter}}" type="radio" name="email" {% if emailaddress.primary %}checked="checked"{%endif %} value="{{emailaddress.email}}"/>
{{ emailaddress.email }}
</label>
</td>
<td>
{% if emailaddress.verified %}
<span class="label label-info">{% trans "Verified" %}</span>
{% else %}
<span class="label label-warning">{% trans "Unverified" %}</span>
{% endif %}
{% if emailaddress.primary %}<span class="label label-success">{% trans "Primary" %}</span>{% endif %}
</td>
</tr>
{% endfor %}
</tbody>
</table>
<div class="form-actions">
<button class="btn btn-success" type="submit" name="action_primary" >{% trans 'Make Primary' %}</button>
<button class="btn" type="submit" name="action_send" >{% trans 'Re-send Verification' %}</button>
<button class="btn btn-danger" type="submit" name="action_remove" >{% trans 'Remove' %}</button>
</div>
</fieldset>
</form>
{% else %}
<p><strong>{% trans 'Warning:'%}</strong> {% trans "You currently do not have any e-mail address set up. You should really add an e-mail address so you can receive notifications, reset your password, etc." %}</p>
{% endif %}
<h2>{% trans "Add E-mail Address" %}</h2>
<form method="post" action="">
{% csrf_token %}
{% bootstrap_form add_email_form %}
<div class="form-actions">
<button class="btn btn-primary" name="action_add" type="submit">{% trans "Add E-mail" %}</button>
</div>
</form>
{% endblock %}
{% block appjs_jquery %}
<script type="text/javascript">
$(function(){
$("button[name='action_remove']").click(function(){
if (confirm("{% trans 'Do you really want to remove the selected e-mail address?' %}")) {
return true;
}
return false;
});
});
</script>
{% endblock %}

View File

@ -0,0 +1,31 @@
{% extends "bases/bootstrap-auth.html" %}
{% load i18n %}
{% load account socialaccount %}
{% block head_title %}{% trans "Confirm E-mail Address" %}{% endblock %}
{% block inner-content %}
<h1>{% trans "Confirm E-mail Address" %}</h1>
{% if confirmation %}
{% user_display confirmation.email_address.user as user_display %}
<p>{% blocktrans with confirmation.email_address.email as email %}Please confirm that <a href="mailto:{{email}}">{{ email }}</a> is an e-mail address for user {{ user_display }}.{% endblocktrans %}</p>
<form method="post" action="{% url 'account_confirm_email' confirmation.key %}">
{% csrf_token %}
<button class="btn btn-primary" type="submit">{% trans 'Confirm' %}</button>
</form>
{% else %}
{% url 'account_email' as email_url %}
<p>{% blocktrans %}This e-mail confirmation link expired or is invalid. Please <a href="{{ email_url}}">issue a new e-mail confirmation request</a>.{% endblocktrans %}</p>
{% endif %}
{% endblock %}

View File

@ -0,0 +1,41 @@
{% extends "bases/bootstrap-auth.html" %}
{% load i18n %}
{% load bootstrap3 %}
{% load account socialaccount %}
{% block head_title %}{% trans "Sign In" %}{% endblock %}
{% block inner-content %}
{% get_providers as socialaccount_providers %}
<h1 class="text-center">Log In</h1>
<hr>
<div class="row">
{% if socialaccount_providers %}
<div class="col-md-5 col-lg-5">
{% include "allauth/account/provider_panel.html" with process="login" %}
</div>
{% endif %}
<div class="{% if socialaccount_providers %}col-md-7 col-lg-7 {% else %} col-md-8 col-md-offset-2 col-lg-6 col-lg-offset-3 {% endif %}">
<form class="login" method="POST" action="{% url 'account_login' %}">
<span class="pull-right">Not yet a member? <a href="{% url 'account_signup' %}">Join</a></span>
{% csrf_token %}
{% bootstrap_form form %}
{% if redirect_field_value %}
<input type="hidden" name="{{ redirect_field_name }}" value="{{ redirect_field_value }}" />
{% endif %}
<div class="form-actions">
<button class="btn btn-primary pull-right" type="submit">{% trans "Sign In" %}</button>
<a class="btn" href="{% url 'account_reset_password' %}">{% trans "Forgot Password?" %}</a>
</div>
</form>
</div>
</div>
{% endblock %}

View File

@ -0,0 +1,21 @@
{% extends "bases/bootstrap-auth.html" %}
{% load i18n %}
{% block head_title %}{% trans "Sign Out" %}{% endblock %}
{% block inner-content %}
<h1>{% trans "Sign Out" %}</h1>
<p>{% trans 'Are you sure you want to sign out?' %}</p>
<form method="post" action="{% url 'account_logout' %}">
{% csrf_token %}
{% if redirect_field_value %}
<input type="hidden" name="{{redirect_field_name}}" value="{{redirect_field_value}}"/>
{% endif %}
<button class="btn btn-primary" type="submit">{% trans 'Sign Out' %}</button>
</form>
{% endblock %}

View File

@ -0,0 +1,90 @@
{% extends "account/base.html" %}
{% load i18n %}
{% load bootstrap3 %}
{% block head_title %}{% trans "Account" %}{% endblock %}
{% block account_tab_events %}active{% endblock %}
{% block account_content %}
{% if user.emailaddress_set.all %}
<p>{% trans 'The following e-mail addresses are associated to your account:' %}</p>
<form action="{% url 'account_email' %}" class="email_list uniForm" method="post">
{% csrf_token %}
<table class="table">
<thead>
<tr>
<th>
{% trans 'E-mail' %}
</th>
<th>
{% trans 'Status' %}
</th>
</tr>
</thead>
<tbody>
{% for emailaddress in user.emailaddress_set.all %}
<tr>
<td>
<label class="radio" for="email_radio_{{forloop.counter}}" class="{% if emailaddress.primary %}primary_email{%endif%}">
<input id="email_radio_{{forloop.counter}}" type="radio" name="email" {% if emailaddress.primary %}checked="checked"{%endif %} value="{{emailaddress.email}}"/>
{{ emailaddress.email }}
</label>
</td>
<td>
{% if emailaddress.verified %}
<span class="label label-info">{% trans "Verified" %}</span>
{% else %}
<span class="label label-warning">{% trans "Unverified" %}</span>
{% endif %}
{% if emailaddress.primary %}<span class="label label-success">{% trans "Primary" %}</span>{% endif %}
</td>
</tr>
{% endfor %}
</tbody>
</table>
<div class="form-actions">
<button class="btn btn-success" type="submit" name="action_primary" >{% trans 'Make Primary' %}</button>
<button class="btn" type="submit" name="action_send" >{% trans 'Re-send Verification' %}</button>
<button class="btn btn-danger" type="submit" name="action_remove" >{% trans 'Remove' %}</button>
</div>
</fieldset>
</form>
{% else %}
<p><strong>{% trans 'Warning:'%}</strong> {% trans "You currently do not have any e-mail address set up. You should really add an e-mail address so you can receive notifications, reset your password, etc." %}</p>
{% endif %}
<h2>{% trans "Add E-mail Address" %}</h2>
<form method="post" action="">
{% csrf_token %}
{% bootstrap_form add_email_form %}
<div class="form-actions">
<button class="btn btn-primary" name="action_add" type="submit">{% trans "Add E-mail" %}</button>
</div>
</form>
{% endblock %}
{% block appjs_jquery %}
<script type="text/javascript">
$(function(){
$("button[name='action_remove']").click(function(){
if (confirm("{% trans 'Do you really want to remove the selected e-mail address?' %}")) {
return true;
}
return false;
});
});
</script>
{% endblock %}

View File

@ -0,0 +1,17 @@
{% extends "account/base.html" %}
{% load i18n %}
{% load bootstrap3 %}
{% block head_title %}{% trans "Change Password" %}{% endblock %}
{% block account_nav_change_password %}active{% endblock %}
{% block account_content %}
<form method="POST" action="" class="password_change">
{% csrf_token %}
{% bootstrap_form password_change_form %}
<div class="form-actions">
<button class="btn btn-primary" type="submit" name="action">{% trans "Change Password" %}</button>
</div>
</form>
{% endblock %}

View File

@ -0,0 +1,33 @@
{% extends "bases/bootstrap-auth.html" %}
{% load i18n %}
{% load bootstrap3 %}
{% load account socialaccount %}
{% block head_title %}{% trans "Password Reset" %}{% endblock %}
{% block inner-content %}
<h1>{% trans "Password Reset" %}</h1>
{% if user.is_authenticated %}
{% include "account/snippets/already_logged_in.html" %}
{% endif %}
<p>{% trans "Forgotten your password? Enter your e-mail address below, and we'll send you an e-mail allowing you to reset it." %}</p>
<form method="POST" action="" >
{% csrf_token %}
{% bootstrap_form password_reset_form %}
<div class="form-actions">
<input class="btn btn-primary" type="submit" value="{% trans "Reset My Password" %}" />
</div>
</form>
<p>{% blocktrans %}Please contact us if you have any trouble resetting your password.{% endblocktrans %}</p>
{% endblock %}
{% block appjs_jquery %}
<script>
$("#id_email").focus();
</script>
{% endblock %}

View File

@ -0,0 +1,29 @@
{% extends "bases/bootstrap-auth.html" %}
{% load i18n %}
{% load bootstrap3 %}
{% block head_title %}{% trans "Change Password" %}{% endblock %}
{% block inner-content %}
<h1>{% if token_fail %}{% trans "Bad Token" %}{% else %}{% trans "Change Password" %}{% endif %}</h1>
{% if token_fail %}
{% url 'account_reset_password' as passwd_reset_url %}
<p>{% blocktrans %}The password reset link was invalid, possibly because it has already been used. Please request a <a href="{{ passwd_reset_url }}">new password reset</a>.{% endblocktrans %}</p>
{% else %}
{% if form %}
<form method="POST" action="" class="uniForm">
{% csrf_token %}
{% bootstrap_form form %}
<div class="form-actions">
<button class="btn btn-primary" type="submit">{% trans "Change Password" %}</button>
</div>
</form>
{% else %}
<p>{% trans 'Your password is now changed.' %}</p>
{% endif %}
{% endif %}
{% endblock %}

View File

@ -0,0 +1,17 @@
{% extends "account/base.html" %}
{% load i18n %}
{% load bootstrap3 %}
{% block head_title %}{% trans "Set Password" %}{% endblock %}
{% block account_nav_change_password %}active{% endblock %}
{% block account_content %}
<form method="POST" action="" class="password_set">
{% csrf_token %}
{% bootstrap_form password_set_form %}
<div class="form-actions">
<input class="btn btn-primary" type="submit" name="action" value="{% trans "Set Password" %}"/>
</div>
</form>
{% endblock %}

View File

@ -0,0 +1,22 @@
{% load i18n %}
{% load bootstrap3 %}
{% load account socialaccount %}
{% get_providers as socialaccount_providers %}
{% if socialaccount_providers %}
<!--
This is the raw "real" HTML that facebook recommends.
Leaving here for reference.
<div class="fb-login-button" data-max-rows="1" data-size="large" data-show-faces="false" data-auto-logout-link="false"></div>
-->
<div class="socialaccount_ballot">
<ul class="socialaccount_providers list-unstyled">
{% include "socialaccount/snippets/provider_list.html" with process="login" %}
</ul>
</div>
{% include "socialaccount/snippets/login_extra.html" %}
{% endif %}

View File

@ -0,0 +1,38 @@
{% extends "bases/bootstrap-auth.html" %}
{% load i18n %}
{% load bootstrap3 %}
{% load account socialaccount %}
{% block head_title %}{% trans "Signup" %}BS{% endblock %}
{% block inner-content %}
{% get_providers as socialaccount_providers %}
<h1>{% trans "Sign Up" %}</h1>
<div class="row">
{% if socialaccount_providers %}
<div class="col-md-5 col-lg-5">
{% include "allauth/account/provider_panel.html" with process="login" %}
</div>
{% endif %}
<div class="{% if socialaccount_providers %}col-md-7 col-lg-7 {% else %} col-md-8 col-md-offset-2 col-lg-6 col-lg-offset-3 {% endif %}">
<p>{% blocktrans %}Already have an account? Then please <a href="{{ login_url }}">sign in</a>.{% endblocktrans %}</p>
<form id="signup_form" method="post" action="{% url 'account_signup' %}">
{% csrf_token %}
{% bootstrap_form form %}
{% if redirect_field_value %}
<input type="hidden" name="{{ redirect_field_name }}" value="{{ redirect_field_value }}" />
{% endif %}
<div class="form-actions">
<button class="btn btn-primary" type="submit">{% trans "Sign Up" %}</button>
</div>
</form>
</div>
</div>
{% endblock %}

View File

@ -0,0 +1,81 @@
{% extends "socialaccount/base.html" %}
{% load i18n %}
{% block head_title %}{% trans "Connected Accounts" %}{% endblock %}
{% block account_nav_socialaccount_connections %}active{% endblock %}
{% block account_content %}
{% if form.accounts %}
<p>{% blocktrans %}You can sign in to your account using any of the following third party accounts:{% endblocktrans %}</p>
<form method="post">
{% csrf_token %}
{% if form.non_field_errors %}
<div class="alert alert-error">
<a class="close" data-dismiss="alert">&times;</a>
{% for non_field_error in form.non_field_errors %}
{{ non_field_error }}
{% endfor %}
</div>
{% endif %}
<table class="table">
<thead>
<tr>
<th>
{% trans 'Provider' %}
</th>
<th>
{% trans 'Account' %}
</th>
</tr>
</thead>
<tbody>
{% for base_account in form.accounts %}
{% with base_account.get_provider_account as account %}
<tr>
<td>
<label class="radio" for="id_account_{{base_account.id}}">
<input id="id_account_{{base_account.id}}" type="radio" name="account" value="{{base_account.id}}"/>
<span class="socialaccount_provider {{base_account.provider}} {{account.get_brand.id}}">{{account.get_brand.name}}</span>
</label>
</td>
<td>
{{account}}
</td>
</tr>
{% endwith %}
{% endfor %}
</tbody>
</table>
<div class="form-actions">
<button class="btn btn-danger" type="submit">{% trans 'Remove' %}</button>
</div>
</fieldset>
</form>
{% else %}
<div class="alert">
<strong>{% trans 'None!' %}</strong> {% trans 'You currently have no social network accounts connected to this account.' %}
</div>
{% endif %}
<h2>{% trans 'Add a 3rd Party Account' %}</h2>
<ul class="socialaccount_providers">
{% include "socialaccount/snippets/provider_list.html" with process="connect" %}
</ul>
{% include "socialaccount/snippets/login_extra.html" %}
{% endblock %}

View File

@ -0,0 +1,29 @@
{% extends "bases/bootstrap-auth.html" %}
{% load i18n %}
{% load bootstrap3 %}
{% block head_title %}{% trans "Signup" %}{% endblock %}
{% block inner-content %}
<h1>{% trans "Sign Up" %}</h1>
<p>{% blocktrans with provider_name=account.get_provider.name site_name=site.name %}You are about to use your {{provider_name}} account to login to
{{site_name}}. As a final step, please complete the following form:{% endblocktrans %}</p>
<form class="signup" id="signup_form" method="post" action="">
{% csrf_token %}
{% bootstrap_form form %}
{% if redirect_field_value %}
<input type="hidden" name="{{ redirect_field_name }}" value="{{ redirect_field_value }}" />
{% endif %}
<div class="form-actions">
<button class="btn btn-primary" type="submit">{% trans "Sign Up" %}</button>
</div>
</form>
{% endblock %}

View File

@ -0,0 +1,44 @@
{% extends "bases/bootstrap-member.html" %}
{% load bootstrap3 %}
{% block content %}
<div class="container">
<h1>Profile</h1>
{# Hmm. Not thrilled about this. #}
{# Could use django-bootstrap3 which removes some of this ugliness. #}
{# Or some AJAX-based way to retrieve messages. #}
{# I don't like the use of cookies for this. #}
{% bootstrap_messages %}
<div class="row">
<div class="col-md-6 col-lg-6">
<form action="{% url 'account_profile' %}" method="post" class="form">
{% csrf_token %}
{% bootstrap_form form %}
{% buttons %}
<button type="submit" class="btn btn-primary">
{% bootstrap_icon "star" %} Submit
</button>
{% endbuttons %}
<!--
<div class="form-group">
<div class="col-sm-12">
<button type="submit" class="btn btn-primary pull-right"> Submit </button>
</div>
</div>
-->
</form>
</div>
<div class="col-md-6 col-lg-6">
TODO: DOB, picture
</div>
</div>
</div>
{% endblock %}

View File

@ -0,0 +1,12 @@
{% extends "bases/bootstrap-minimal.html" %}
{% block content %}
<div class="container">
<div class="row">
<div class="col-md-8 col-md-offset-2 col-lg-8 col-lg-offset-2 big-box">
{% block inner-content %}
{% endblock %}
</div>
</div>
</div><!-- container -->
{% endblock %}

View File

@ -0,0 +1,267 @@
{% extends "bases/bootstrap.html" %}
{% load staticfiles %}
{% block tail_js %}
<script>
Module = {};
Module.memoryInitializerPrefixURL = "{% static 'js/' %}";
</script>
<script src="//code.jquery.com/jquery-2.2.4.min.js"></script>
<!-- <script>window.jQuery || document.write('<script src="js/jquery-1.10.1.min.js"><\/script>')</script> -->
<script src="//maxcdn.bootstrapcdn.com/bootstrap/3.3.5/js/bootstrap.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/moment.js/2.10.6/moment.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/bootstrap-datetimepicker/4.17.37/js/bootstrap-datetimepicker.min.js"></script>
<script src='https://www.google.com/recaptcha/api.js'></script>
<script
src="https://code.jquery.com/ui/1.12.1/jquery-ui.min.js"
integrity="sha256-VazP97ZCwtekAsvgPBSUwPFKdrwD3unUfSGVYrahUqU="
crossorigin="anonymous"></script>
<script src="{% static 'js/papaparse.min.js' %}" type="text/javascript"></script>
<script src="{% static 'js/create-event-poll.js' %}" type="text/javascript"></script>
<script src="{% static 'js/encrypt.js' %}" type="text/javascript"></script>
<script type="text/javascript" src="{% static 'js/core/rand.js' %}"></script>
<script type="text/javascript" src="{% static 'js/core/rom_curve.js' %}"></script>
<script type="text/javascript" src="{% static 'js/core/rom_field.js' %}"></script>
<script type="text/javascript" src="{% static 'js/core/uint64.js' %}"></script>
<script type="text/javascript" src="{% static 'js/core/aes.js' %}"></script>
<script type="text/javascript" src="{% static 'js/core/big.js' %}"></script>
<script type="text/javascript" src="{% static 'js/core/gcm.js' %}"></script>
<script type="text/javascript" src="{% static 'js/core/hash256.js' %}"></script>
<script type="text/javascript" src="{% static 'js/core/hash384.js' %}"></script>
<script type="text/javascript" src="{% static 'js/core/hash512.js' %}"></script>
<script type="text/javascript" src="{% static 'js/core/sha3.js' %}"></script>
<script type="text/javascript" src="{% static 'js/core/newhope.js' %}"></script>
<script type="text/javascript" src="{% static 'js/core/nhs.js' %}"></script>
<script type="text/javascript" src="{% static 'js/core/fp.js' %}"></script>
<script type="text/javascript" src="{% static 'js/core/fp2.js' %}"></script>
<script type="text/javascript" src="{% static 'js/core/fp4.js' %}"></script>
<script type="text/javascript" src="{% static 'js/core/fp12.js' %}"></script>
<script type="text/javascript" src="{% static 'js/core/ff.js' %}"></script>
<script type="text/javascript" src="{% static 'js/core/rsa.js' %}"></script>
<script type="text/javascript" src="{% static 'js/core/ecp.js' %}"></script>
<script type="text/javascript" src="{% static 'js/core/ecp2.js' %}"></script>
<script type="text/javascript" src="{% static 'js/core/ecdh.js' %}"></script>
<script type="text/javascript" src="{% static 'js/core/pair.js' %}"></script>
<script type="text/javascript" src="{% static 'js/core/mpin.js' %}"></script>
<script type="text/javascript" src="{% static 'js/core/ctx.js' %}"></script>
<script type="text/javascript" src="{% static 'js/demos2-booth.js' %}"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.12.0/jquery-ui.js" type="text/javascript"></script>
{% block app_js %}
<script type="text/javascript">
{% block app_js_vars %}
{% endblock %}
Module.memoryInitializerPrefixURL = "LOL";
var demosEncrypt = {
}
/*
Code written with "New function" comments have
been totally or mostly re-implemented by Thomas Smith
*/
//new function
demosEncrypt.encryptAndSubmit = function() {
var ctx = new CTX("BN254CX"); //new context we can use
var n = new ctx.BIG();
var g1 = new ctx.ECP();
var g2 = new ctx.ECP2();
var param = $('#event-param').val();
//console.log(param);
var tempParams = JSON.parse(param);
//copying the values
n.copy(tempParams.n);
g1.copy(tempParams.g1);
g2.copy(tempParams.g2);
var params = {
n:n,
g1:g1,
g2:g2
}
var tempPK = JSON.parse($('#comb_pk').val());
var pk = new ctx.ECP(0);
pk.copy(tempPK.PK);
var answer = $('#poll-options').val();
console.log(answer);
var cipher = encrypt(params, pk, answer);
var c1Bytes = [];
cipher.C1.toBytes(c1Bytes);
var c2Bytes = [];
cipher.C2.toBytes(c2Bytes);
$('#id_cipher_text_c1').val(c1Bytes.toString());
$('#id_cipher_text_c2').val(c2Bytes.toString());
$('#cipher-form').submit();
}
//new function
demosEncrypt.decryptCipher = function() {
var skString = $('#secret-key').val();
if (!skString) {
alert("Please enter your secret key");
}
else {
//rebuild our secret key
var ctx = new CTX("BN254CX");
var skBytes = skString.split(",");
var sk =new ctx.BIG.fromBytes(skBytes);
var inputs = $("form input[type=text]");
inputs.each(function() { //for each ciphertext to decrypt
var ciphertext = {
C1: new ctx.ECP(),
C2: new ctx.ECP()
}
var temp = JSON.parse($(this).val());
ciphertext.C1.copy(temp.C1);
ciphertext.C2.copy(temp.C2);
var partial = partDec(sk, ciphertext);//returns an object containing an ECP()
var bytes = [];
partial.D.toBytes(bytes);
$(this).val(bytes.toString());//submit in byte array form
})
$('input[type=submit]').prop("disabled", false);
}
}
//new function
demosEncrypt.generateKeys = function() {
parameter = $("#event-param").val();
var tempParams = JSON.parse(parameter);
//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
var ctx = new CTX("BN254CX"); //new context we can use
var n = new ctx.BIG();
var g1 = new ctx.ECP();
var g2 = new ctx.ECP2();
//copying the values
n.copy(tempParams.n);
g1.copy(tempParams.g1);
g2.copy(tempParams.g2);
var params = {
n:n,
g1:g1,
g2:g2
}
var PKbytes = [];
var SKbytes = [];
var keypair = keyGen(params);
keypair.PK.toBytes(PKbytes);
keypair.SK.toBytes(SKbytes);
$('input#public-key').val(PKbytes.toString());
$('input#secret-key').val(SKbytes.toString());
//mostly code from before here
var blob = new Blob([SKbytes.toString()], {type : 'text/plain'});
var dlBtn = $('a#download-btn');
var url = URL.createObjectURL(blob);
var fileName = $(dlBtn).attr("href", url);
$(dlBtn).attr("download", "sk-{% block sk-file-name %}{% endblock %}".replace(/[\W]/g, "-"));
$(dlBtn).attr("disabled", false);
$("#public-submit").attr("disabled", false);
}
//these other functions might not be used
//I don't think this is used
demosEncrypt.downloadSecretKey = function() {
var blob = new Blob([sk], {type : 'text/plain'});
var dlBtn = $('a#download-btn');
$(dlBtn).attr("disabled", true);
}
function getFormsetPrefix(id) {
id = id.replace(/(?:id_)?formset_/, ""); // strip generic part
return id.replace(/([A-Za-z0-9]+)[\w-]*/, "$1"); // return prefix
}
function setFormsetIndex(ele, prefix, index) {
ele = $(ele).find("div[id^='id_formset'], input[id^='id_formset']").each(function (i, el) {
var id = $(el).attr("id");
id = "id_formset_" + prefix + '-' + index + id.match(/-\w+$/);
$(el).attr("id", id);
if ($(el).is("input")) {
$(el).attr("name", id.replace(/^id_/, ""));
}
});
}
$('.formset').sortable({handle:".input-group-addon", items:".formset_object",
start: function(event, ui) {
ui.item.prevPos = ui.item.index();
console.log(ui.item.prevPos);
},
update: function(event, ui) {
ui.item.prevPos = null;
},
beforeStop: function(event, ui) {
$(ui.item).css("animation", "none"); // prevents firing of entry keyframe
}
});
//$('.glyphicon.glyphicon-trash').parent().hide();
$('.formset').find
$('.formset').on('click', '.input-group-addon', function() { // this makes the label a delete btn too :(
var ele = $(this).closest(".formset_object");
var prefix = $(this).closest(".formset_object").data("prefix") || getFormsetPrefix($(this).closest(".formset_object").find('input:first').attr("id"));
var current_total = parseInt($("#id_formset_" + prefix + "-TOTAL_FORMS").val());
if (current_total <= $("#id_formset_" + prefix + "-MIN_NUM_FORMS").val()) {
return; // don't allow removal of last element
}
ele.remove();
$("#id_formset_" + prefix + "-TOTAL_FORMS").val(current_total - 1);
$(".formset").sortable( "refresh" );
$(".formset").sortable( "refreshPositions" );
});
$('.add-another-btn').on('click',function() {
var new_formset_item = $(this).prevAll(".formset_object:first").clone();
var prefix = getFormsetPrefix(new_formset_item.find("input:first").attr("id"));
var current_total = parseInt($("#id_formset_" + prefix + "-TOTAL_FORMS").val());
if (current_total >= $("#id_formset_" + prefix + "-MAX_NUM_FORMS").val()) {
return; // don't allow more than max forms
}
new_formset_item.data("prefix", prefix);
$(this).before(new_formset_item);
new_formset_item.find("input").val("");
setFormsetIndex(new_formset_item, prefix, parseInt($("#id_formset_" + prefix + "-TOTAL_FORMS").val()));
$("#id_formset_" + prefix + "-TOTAL_FORMS").val(parseInt($("#id_formset_" + prefix + "-TOTAL_FORMS").val()) +1);
$(".formset").sortable( "refresh" );
$(".formset").sortable( "refreshPositions" );
});
// rudimentary accordion error handling
$('.has-error').closest('.panel').find('.panel-heading').addClass("error");
$('.alert.alert-block.alert-danger').closest('.panel').find('.panel-heading').addClass("error");
</script>
{% endblock %}
{% endblock %}

View File

@ -0,0 +1,42 @@
{% extends "bases/bootstrap-jquery.html" %}
{% load staticfiles %}
{% block nav %}
<!-- Fixed navbar -->
<div class="navbar navbar-default navbar-static-top navbar-shadow" role="navigation">
<div class="container">
<div class="navbar-header">
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="{% url 'user_home' %}">Demo Members Area</a>
</div>
<div class="navbar-collapse collapse">
<ul class="nav navbar-nav navbar-right">
<li><a href="{% url 'user_home' %}">Home</a></li>
<li><a href="{% url 'user_action' %}">Action</a></li>
<li><a href="{% url 'polls:index' %}">Events</a></li>
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown">
<strong> {{ user.display_name }}</strong> <b class="caret"></b>
</a>
<ul class="dropdown-menu">
<li class="dropdown-header">Account</li>
<li><a href="{% url 'account_profile' %}"><i class="fa fa-cog"></i> Settings</a></li>
<li><a href="{% url 'account_events' %}"><i class="fa fa-bell"></i> My Events</a></li>
<li><a href="{% url 'account_email' %}"><i class="fa fa-envelope"></i> Email Addresses</a></li>
<li><a href="{% url 'socialaccount_connections' %}"><i class="fa fa-facebook"></i> Social Networks</a></li>
<li><a href="{% url 'account_change_password' %}"><i class="fa fa-lock"></i> Change Password</a></li>
<li class="divider"></li>
<li><a href="{% url 'account_logout' %}"><i class="fa fa-sign-out"></i> Sign Out</a></li>
</ul>
</li>
<li>{% if user.profile.avatar_url %}<img alt="" style="width:50px; height:50px" src="{{user.profile.avatar_url}}">{% endif %}</li>
</ul>
</div>
</div>
</div>
{% endblock %}

View File

@ -0,0 +1,25 @@
{% extends "bases/bootstrap-jquery.html" %}
{% load staticfiles %}
{% block nav %}
<div class="navbar navbar-default navbar-static-top navbar-shadow" role="navigation">
<div class="container">
<div class="navbar-header">
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="/"><img src='{% static "img/demos-banner.png" %}' style="height:100%" title="demos2"></a>
</div>
<div class="navbar-collapse collapse">
<ul class="nav navbar-nav navbar-right">
<li><a href="{% url 'landing_index' %}"><strong>Home</strong></a></li>
<li><a href="{% url 'account_signup' %}"><strong>Join</strong></a></li>
<li><a href="{% url 'account_login' %}"><strong>Log In</strong></a></li>
</ul>
</div>
</div>
</div>
{% endblock %}

View File

@ -0,0 +1,29 @@
{% extends "bases/bootstrap-jquery.html" %}
{% load staticfiles %}
{% block nav %}
<!-- Fixed navbar -->
<div class="navbar navbar-default navbar-static-top navbar-shadow" role="navigation">
<div class="container">
<div class="navbar-header">
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="/"><img src='{% static "img/demos2-banner.png" %}' style="height:100%" title="demos2"></a>
</div>
<div class="navbar-collapse collapse">
<ul class="nav navbar-nav navbar-right">
<li><a href="{% url 'landing_index' %}">Welcome</a></li>
<li><a href="{% url 'landing_about' %}">About</a></li>
<li><a href="{% url 'polls:index' %}">Events</a></li>
<li><a href="{% url 'account_signup' %}"><strong>Join</strong></a></li>
<li><a href="{% url 'account_login' %}"><strong>Log In</strong></a></li>
</ul>
</div>
</div>
</div>
{% endblock %}

View File

@ -0,0 +1,48 @@
{% extends "bases/bootstrap-jquery.html" %}
{% load staticfiles %}
{% block nav %}
<!-- Fixed navbar -->
<div class="navbar navbar-default navbar-static-top navbar-shadow" role="navigation">
<div class="container">
<div class="navbar-header">
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="/"><img src='{% static "img/demos2-banner.png" %}' style="height:30px" title="demos2"></a>
</div>
<div class="navbar-collapse collapse">
<ul class="nav navbar-nav navbar-right">
<li><a href="{% url 'landing_index' %}">Welcome</a></li>
<li><a href="{% url 'landing_about' %}">About</a></li>
<li><a href="{% url 'polls:index' %}">Events</a></li>
{% if user.is_authenticated %}
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown">
<strong> {{ user.display_name }}</strong> <b class="caret"></b>
</a>
<ul class="dropdown-menu">
<li class="dropdown-header">Account</li>
<li><a href="{% url 'account_profile' %}"><i class="fa fa-cog"></i> Settings</a></li>
<li><a href="{% url 'account_events' %}"><i class="fa fa-bell"></i> My Events</a></li>
<li><a href="{% url 'account_email' %}"><i class="fa fa-envelope"></i> Email Addresses</a></li>
<li><a href="{% url 'socialaccount_connections' %}"><i class="fa fa-facebook"></i> Social Networks</a></li>
<li><a href="{% url 'account_change_password' %}"><i class="fa fa-lock"></i> Change Password</a></li>
<li class="divider"></li>
<li><a href="{% url 'account_logout' %}"><i class="fa fa-sign-out"></i> Sign Out</a></li>
</ul>
</li>
<li>{% if user.profile.avatar_url %}<img alt="" style="width:50px; height:50px" src="{{user.profile.avatar_url}}">{% endif %}</li>
{% else %}
<li><a href="{% url 'account_signup' %}"><strong>Join</strong></a></li>
<li><a href="{% url 'account_login' %}"><strong>Log In</strong></a></li>
{% endif %}
</ul>
</div>
</div>
</div>
{% endblock %}

View File

@ -0,0 +1,52 @@
{% load staticfiles %}
<!DOCTYPE html>
<html lang="en" {% block htmlattr %}{% endblock %}>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>{% block title %}dẽmos 2{% endblock %}</title>
<link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css">
<link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap-theme.min.css">
<link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/bootstrap-datetimepicker/4.17.37/css/bootstrap-datetimepicker.min.css">
<link rel="stylesheet" href="//netdna.bootstrapcdn.com/font-awesome/4.1.0/css/font-awesome.css">
<!-- HTML5 Shim and Respond.js IE8 support of HTML5 elements and media queries -->
<!-- WARNING: Respond.js doesn't work if you view the page via file:// -->
<!--[if lt IE 9]>
<script src="https://oss.maxcdn.com/libs/html5shiv/3.7.0/html5shiv.js"></script>
<script src="https://oss.maxcdn.com/libs/respond.js/1.4.2/respond.min.js"></script>
<![endif]-->
{% block head_css %}
<link rel="stylesheet" media="screen" href='{% static "css/main.css" %}'>
{% endblock %}
</head>
<body class='{% block pageclass %}{% endblock %}' {% block bodyattr %}{% endblock %}>
{% block nav %}{% endblock %}
{% block content %}{% endblock %}
{% block footer %}
<div class=container>
<hr>
<footer>
<ul class="list-inline pull-right">
<li><a href="{% url 'website_terms' %}">Terms</a></li>
<li><a href="{% url 'website_contact' %}">Contact</a></li>
</ul>
<p class=muted>{% include "copyright.html" %}</p>
</footer>
</div>
{% endblock %}
{% block tail_js %}
{% endblock %}
</body>
</html>

View File

@ -0,0 +1,12 @@
<div class="panel panel-default">
<div class="panel-heading">
<h4 class="panel-title">
<a class="accordion-toggle" data-toggle="collapse" data-parent="#{{ div.data_parent }}" href="#{{ div.css_id }}">{{ div.name }}</a>
</h4>
</div>
<div id="{{ div.css_id }}" class="panel-collapse collapse{% if div.active %} in{% endif %}" >
<div class="panel-body">
{{ fields|safe }}
</div>
</div>
</div>

View File

@ -0,0 +1,3 @@
<div class="panel-group" id="{{ accordion.css_id }}">
{{ content|safe }}
</div>

View File

@ -0,0 +1,22 @@
{% for fieldset in form.fieldsets %}
<fieldset class="fieldset-{{ forloop.counter }} {{ fieldset.classes }}">
{% if fieldset.legend %}
<legend>{{ fieldset.legend }}</legend>
{% endif %}
{% if fieldset.description %}
<p class="description">{{ fieldset.description }}</p>
{% endif %}
{% for field in fieldset %}
{% if field.is_hidden %}
{{ field }}
{% else %}
{% include "bootstrap3/field.html" %}
{% endif %}
{% endfor %}
{% if not forloop.last or not fieldset_open %}
</fieldset>
{% endif %}
{% endfor %}

View File

@ -0,0 +1,9 @@
{% if form.form_html %}
{% if include_media %}{{ form.media }}{% endif %}
{% if form_show_errors %}
{% include "bootstrap3/errors.html" %}
{% endif %}
{{ form.form_html }}
{% else %}
{% include "bootstrap3/uni_form.html" %}
{% endif %}

View File

@ -0,0 +1,8 @@
{% if form.non_field_errors %}
<div class="alert alert-block alert-danger">
{% if form_error_title %}<h4 class="alert-heading">{{ form_error_title }}</h4>{% endif %}
<ul>
{{ form.non_field_errors|unordered_list }}
</ul>
</div>
{% endif %}

View File

@ -0,0 +1,9 @@
{% if formset.non_form_errors %}
<div class="alert alert-block alert-danger">
{% if formset_error_title %}<h4 class="alert-heading">{{ formset_error_title }}</h4>{% endif %}
<ul>
{{ formset.non_form_errors|unordered_list }}
</ul>
</div>
{% endif %}

View File

@ -0,0 +1,48 @@
{% load crispy_forms_field %}
{% if field.is_hidden %}
{{ field }}
{% else %}
{% if field|is_checkbox %}
<div class="form-group">
{% if label_class %}
<div class="controls col-{{ bootstrap_device_type }}-offset-{{ label_size }} {{ field_class }}">
{% endif %}
{% endif %}
<{% if tag %}{{ tag }}{% else %}div{% endif %} id="div_{{ field.auto_id }}" {% if not field|is_checkbox %}class="form-group{% else %}class="checkbox{% endif %}{% if wrapper_class %} {{ wrapper_class }}{% endif %}{% if form_show_errors%}{% if field.errors %} has-error{% endif %}{% endif %}{% if field.css_classes %} {{ field.css_classes }}{% endif %}">
{% if field.label and not field|is_checkbox and form_show_labels %}
<label for="{{ field.id_for_label }}" class="control-label {{ label_class }}{% if field.field.required %} requiredField{% endif %}">
{{ field.label|safe }}{% if field.field.required %}<span class="asteriskField">*</span>{% endif %}
</label>
{% endif %}
{% if field|is_checkboxselectmultiple %}
{% include 'bootstrap3/layout/checkboxselectmultiple.html' %}
{% endif %}
{% if field|is_radioselect %}
{% include 'bootstrap3/layout/radioselect.html' %}
{% endif %}
{% if not field|is_checkboxselectmultiple and not field|is_radioselect %}
{% if field|is_checkbox and form_show_labels %}
<label for="{{ field.id_for_label }}" class="{% if field.field.required %} requiredField{% endif %}">
{% crispy_field field %}
{{ field.label|safe }}
{% include 'bootstrap3/layout/help_text_and_errors.html' %}
</label>
{% else %}
<div class="controls {{ field_class }}">
{% crispy_field field %}
{% include 'bootstrap3/layout/help_text_and_errors.html' %}
</div>
{% endif %}
{% endif %}
</{% if tag %}{{ tag }}{% else %}div{% endif %}>
{% if field|is_checkbox %}
{% if label_class %}
</div>
{% endif %}
</div>
{% endif %}
{% endif %}

View File

@ -0,0 +1,13 @@
{% if inputs %}
<div class="form-group">
{% if label_class %}
<div class="aab controls {{ label_class }}"></div>
{% endif %}
<div class="controls {{ field_class }}">
{% for input in inputs %}
{% include "bootstrap3/layout/baseinput.html" %}
{% endfor %}
</div>
</div>
{% endif %}

View File

@ -0,0 +1,4 @@
<div{% if alert.css_id %} id="{{ alert.css_id }}"{% endif %}{% if alert.css_class %} class="{{ alert.css_class }}"{% endif %}>
{% if dismiss %}<button type="button" class="close" data-dismiss="alert">&times;</button>{% endif %}
{{ content|safe }}
</div>

View File

@ -0,0 +1,9 @@
<input type="{{ input.input_type }}"
name="{% if input.name|wordcount > 1 %}{{ input.name|slugify }}{% else %}{{ input.name }}{% endif %}"
value="{{ input.value }}"
{% if input.input_type != "hidden" %}
class="{{ input.field_classes }}"
id="{% if input.id %}{{ input.id }}{% else %}{{ input.input_type }}-id-{{ input.name|slugify }}{% endif %}"
{% endif %}
{{ input.flat_attrs|safe }}
/>

View File

@ -0,0 +1 @@
<button {{ button.flat_attrs|safe }}>{{ button.content|safe }}</button>

View File

@ -0,0 +1,4 @@
<div {% if buttonholder.css_id %}id="{{ buttonholder.css_id }}"{% endif %}
class="buttonHolder{% if buttonholder.css_class %} {{ buttonholder.css_class }}{% endif %}">
{{ fields_output|safe }}
</div>

View File

@ -0,0 +1,17 @@
{% load crispy_forms_filters %}
{% load l10n %}
<div class="controls {{ field_class }}"{% if flat_attrs %} {{ flat_attrs|safe }}{% endif %}>
{% include 'bootstrap3/layout/field_errors_block.html' %}
{% for choice in field.field.choices %}
{% if not inline_class %}<div class="checkbox">{% endif %}
<label class="{% if inline_class %}checkbox-{{ inline_class }}{% endif %}">
<input type="checkbox"{% if choice.0 in field.value or choice.0|stringformat:"s" in field.value or choice.0|stringformat:"s" == field.value|stringformat:"s" %} checked="checked"{% endif %} name="{{ field.html_name }}" id="id_{{ field.html_name }}_{{ forloop.counter }}" value="{{ choice.0|unlocalize }}" {{ field.field.widget.attrs|flatatt }}>{{ choice.1|unlocalize }}
</label>
{% if not inline_class %}</div>{% endif %}
{% endfor %}
{% include 'bootstrap3/layout/help_text.html' %}
</div>

View File

@ -0,0 +1,14 @@
{% if field.is_hidden %}
{{ field }}
{% else %}
<div id="div_{{ field.auto_id }}" class="form-group{% if form_show_errors and field.errors %} has-error{% endif %}{% if field.css_classes %} {{ field.css_classes }}{% endif %}">
{% if field.label %}
<label for="{{ field.auto_id }}" class="control-label {{ label_class }}{% if field.field.required %} requiredField{% endif %}">
{{ field.label|safe }}{% if field.field.required %}<span class="asteriskField">*</span>{% endif %}
</label>
{% endif %}
{% include 'bootstrap3/layout/checkboxselectmultiple.html' %}
</div>
{% endif %}

View File

@ -0,0 +1,4 @@
<div {% if div.css_id %}id="{{ div.css_id }}"{% endif %}
{% if div.css_class %}class="{{ div.css_class }}"{% endif %} {{ div.flat_attrs|safe }}>
{{ fields|safe }}
</div>

View File

@ -0,0 +1,5 @@
{% if form_show_errors and field.errors %}
{% for error in field.errors %}
<span id="error_{{ forloop.counter }}_{{ field.auto_id }}" class="help-block"><strong>{{ error }}</strong></span>
{% endfor %}
{% endif %}

View File

@ -0,0 +1,5 @@
{% if form_show_errors and field.errors %}
{% for error in field.errors %}
<p id="error_{{ forloop.counter }}_{{ field.auto_id }}" class="help-block"><strong>{{ error }}</strong></p>
{% endfor %}
{% endif %}

View File

@ -0,0 +1,17 @@
{% load crispy_forms_field %}
<div{% if div.css_id %} id="{{ div.css_id }}"{% endif %} class="form-group{% if form_show_errors and field.errors %} has-error{% endif %}{% if field.css_classes %} {{ field.css_classes }}{% endif %}{% if div.css_class %} {{ div.css_class }}{% endif %}" {{ div.flat_attrs|safe }}>
{% if field.label and form_show_labels %}
<label for="{{ field.id_for_label }}" class="control-label {{ label_class }}{% if field.field.required %} requiredField{% endif %}">
{{ field.label|safe }}{% if field.field.required %}<span class="asteriskField">*</span>{% endif %}
</label>
{% endif %}
<div class="controls {{ field_class }}">
<div class="input-group">
{% crispy_field field %}
<span class="input-group-btn{% if active %} active{% endif %}{% if input_size %} {{ input_size }}{% endif %}">{{ buttons|safe }}</span>
</div>
{% include 'bootstrap3/layout/help_text_and_errors.html' %}
</div>
</div>

View File

@ -0,0 +1,6 @@
<fieldset {% if fieldset.css_id %}id="{{ fieldset.css_id }}"{% endif %}
{% if fieldset.css_class or form_style %}class="{{ fieldset.css_class }} {{ form_style }}"{% endif %}
{{ fieldset.flat_attrs|safe }}>
{% if legend %}<legend>{{ legend|safe }}</legend>{% endif %}
{{ fields|safe }}
</fieldset>

View File

@ -0,0 +1,9 @@
<div{% if formactions.attrs %} {{ formactions.flat_attrs|safe }}{% endif %} class="form-group">
{% if label_class %}
<div class="aab controls {{ label_class }}"></div>
{% endif %}
<div class="controls {{ field_class }}">
{{ fields_output|safe }}
</div>
</div>

View File

@ -0,0 +1,7 @@
{% if field.help_text %}
{% if help_text_inline %}
<span id="hint_{{ field.auto_id }}" class="help-block">{{ field.help_text|safe }}</span>
{% else %}
<p id="hint_{{ field.auto_id }}" class="help-block">{{ field.help_text|safe }}</p>
{% endif %}
{% endif %}

View File

@ -0,0 +1,13 @@
{% if help_text_inline and not error_text_inline %}
{% include 'bootstrap3/layout/help_text.html' %}
{% endif %}
{% if error_text_inline %}
{% include 'bootstrap3/layout/field_errors.html' %}
{% else %}
{% include 'bootstrap3/layout/field_errors_block.html' %}
{% endif %}
{% if not help_text_inline %}
{% include 'bootstrap3/layout/help_text.html' %}
{% endif %}

View File

@ -0,0 +1,21 @@
{% load crispy_forms_field %}
{% if field.is_hidden %}
{{ field }}
{% else %}
{% if field|is_checkbox %}
<div id="div_{{ field.auto_id }}" class="checkbox">
<label for="{{ field.id_for_label }}" class="{% if field.field.required %} requiredField{% endif %}">
{% crispy_field field 'class' 'checkbox' %}
{{ field.label|safe }}
</label>
</div>
{% else %}
<div id="div_{{ field.auto_id }}" class="form-group">
<label for="{{ field.id_for_label }}" class="sr-only{% if field.field.required %} requiredField{% endif %}">
{{ field.label|safe }}
</label>
{% crispy_field field 'placeholder' field.label %}
</div>
{% endif %}
{% endif %}

View File

@ -0,0 +1,27 @@
{% load crispy_forms_field %}
{% if field.is_hidden %}
{{ field }}
{% else %}
{% if field.label %}
<label for="{{ field.id_for_label }}"{% if labelclass %} class="{{ labelclass }}"{% endif %}>
{% endif %}
{% if field|is_checkbox %}
{% crispy_field field %}
{% endif %}
{% if field.label %}
{{ field.label }}
{% endif %}
{% if not field|is_checkbox %}
{% crispy_field field %}
{% endif %}
{% if field.label %}
</label>
{% endif %}
{% endif %}

View File

@ -0,0 +1,30 @@
{% load crispy_forms_field %}
{% if field.is_hidden %}
{{ field }}
{% else %}
<div id="div_{{ field.auto_id }}" class="form-group{% if wrapper_class %} {{ wrapper_class }}{% endif %}{% if form_show_errors and field.errors %} has-error{% endif %}{% if field.css_classes %} {{ field.css_classes }}{% endif %}">
{% if field.label and form_show_labels %}
<label for="{{ field.id_for_label }}" class="control-label {{ label_class }}{% if field.field.required %} requiredField{% endif %}">
{{ field.label|safe }}{% if field.field.required %}<span class="asteriskField">*</span>{% endif %}
</label>
{% endif %}
<div class="controls {{ field_class }}">
{% if field|is_select %}
{% if crispy_prepended_text %}<span class="input-group{% if active %} active{% endif %}{% if input_size %} {{ input_size }}{% endif %}">{{ crispy_prepended_text|safe }}</span>{% endif %}
{% crispy_field field %}
{% if crispy_appended_text %}<span class="input-group{% if active %} active{% endif %}{% if input_size %} {{ input_size }}{% endif %}">{{ crispy_appended_text|safe }}</span>{% endif %}
{% else %}
<div class="input-group">
{% if crispy_prepended_text %}<span class="input-group-addon{% if active %} active{% endif %}{% if input_size %} {{ input_size }}{% endif %}">{{ crispy_prepended_text|safe }}</span>{% endif %}
{% crispy_field field %}
{% if crispy_appended_text %}<span class="input-group-addon{% if active %} active{% endif %}{% if input_size %} {{ input_size }}{% endif %}">{{ crispy_appended_text|safe }}</span>{% endif %}
</div>
{% endif %}
{% include 'bootstrap3/layout/help_text_and_errors.html' %}
</div>
</div>
{% endif %}

View File

@ -0,0 +1,16 @@
{% load crispy_forms_filters %}
{% load l10n %}
<div class="controls {{ field_class }}"{% if flat_attrs %} {{ flat_attrs|safe }}{% endif %}>
{% include 'bootstrap3/layout/field_errors_block.html' %}
{% for choice in field.field.choices %}
{% if not inline_class %}<div class="radio">{% endif %}
<label class="{% if inline_class %}radio-{{ inline_class }}{% endif %}">
<input type="radio"{% if choice.0|stringformat:"s" == field.value|stringformat:"s" %} checked="checked"{% endif %} name="{{ field.html_name }}" id="id_{{ field.html_name }}_{{ forloop.counter }}" value="{{ choice.0|unlocalize }}" {{ field.field.widget.attrs|flatatt }}>{{ choice.1|unlocalize }}
</label>
{% if not inline_class %}</div>{% endif %}
{% endfor %}
{% include 'bootstrap3/layout/help_text.html' %}
</div>

View File

@ -0,0 +1,14 @@
{% if field.is_hidden %}
{{ field }}
{% else %}
<div id="div_{{ field.auto_id }}" class="form-group{% if wrapper_class %} {{ wrapper_class }}{% endif %}{% if form_show_errors and field.errors %} has-error{% endif %}{% if field.css_classes %} {{ field.css_classes }}{% endif %}">
{% if field.label %}
<label for="{{ field.auto_id }}" class="control-label {{ label_class }}{% if field.field.required %} requiredField{% endif %}">
{{ field.label|safe }}{% if field.field.required %}<span class="asteriskField">*</span>{% endif %}
</label>
{% endif %}
{% include 'bootstrap3/layout/radioselect.html' %}
</div>
{% endif %}

View File

@ -0,0 +1 @@
<li class="tab-pane{% if 'active' in link.css_class %} active{% endif %}"><a href="#{{ link.css_id }}" data-toggle="tab">{{ link.name|capfirst }}{% if tab.errors %}!{% endif %}</a></li>

View File

@ -0,0 +1,6 @@
<ul{% if tabs.css_id %} id="{{ tabs.css_id }}"{% endif %} class="nav nav-tabs">
{{ links|safe }}
</ul>
<div class="tab-content panel-body">
{{ content|safe }}
</div>

Some files were not shown because too many files have changed in this diff Show More