Initial commit of DEMOS2 with the upgraded 'Create Event' UI. However, there is no input validation currently
This commit is contained in:
commit
7084bd1b16
155 changed files with 8102 additions and 0 deletions
9
.gitignore
vendored
Executable file
9
.gitignore
vendored
Executable file
|
@ -0,0 +1,9 @@
|
||||||
|
*.pyc
|
||||||
|
*.sqlite
|
||||||
|
*.sqlite3
|
||||||
|
__pycache__
|
||||||
|
migrations/
|
||||||
|
build
|
||||||
|
|
||||||
|
/venv*/
|
||||||
|
/.idea/
|
25
LICENSE
Executable file
25
LICENSE
Executable 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
26
Makefile
Executable 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
231
Node/demos2-booth.js
Executable 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
173
Node/example.html
Executable 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
469
Node/index.js
Executable 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
529
Node/package-lock.json
generated
Executable 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
232
Node/test/demos2-booth.js
Executable 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
288
Node/test/test_webserver.html
Executable 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 += "¶m=";//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
7
README.md
Executable 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
5
allauthdemo/__init__.py
Executable 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
2
allauthdemo/auth/__init__.py
Executable 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
87
allauthdemo/auth/admin.py
Executable 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
8
allauthdemo/auth/apps.py
Executable 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
46
allauthdemo/auth/forms.py
Executable 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
199
allauthdemo/auth/models.py
Executable 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
3
allauthdemo/auth/tests.py
Executable file
|
@ -0,0 +1,3 @@
|
||||||
|
from django.test import TestCase
|
||||||
|
|
||||||
|
# Create your tests here.
|
53
allauthdemo/auth/views.py
Executable file
53
allauthdemo/auth/views.py
Executable 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
22
allauthdemo/celery.py
Executable 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
0
allauthdemo/polls/__init__.py
Executable file
43
allauthdemo/polls/admin.py
Executable file
43
allauthdemo/polls/admin.py
Executable 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
7
allauthdemo/polls/apps.py
Executable 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
61
allauthdemo/polls/cpp_calls.py
Executable 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 += '¶m='+urllib2.quote(str(param))
|
||||||
|
|
||||||
|
testquerystring = '?number='+str(amount)
|
||||||
|
testquerystring += '¶m='+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
383
allauthdemo/polls/forms.py
Executable 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
110
allauthdemo/polls/models.py
Executable 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)
|
0
allauthdemo/polls/polls/__init__.py
Executable file
0
allauthdemo/polls/polls/__init__.py
Executable file
22
allauthdemo/polls/polls/admin.py
Executable file
22
allauthdemo/polls/polls/admin.py
Executable 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)
|
7
allauthdemo/polls/polls/apps.py
Executable file
7
allauthdemo/polls/polls/apps.py
Executable file
|
@ -0,0 +1,7 @@
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
from django.apps import AppConfig
|
||||||
|
|
||||||
|
|
||||||
|
class PollsConfig(AppConfig):
|
||||||
|
name = 'polls'
|
BIN
allauthdemo/polls/polls/demos_encrypt.so.dylib
Executable file
BIN
allauthdemo/polls/polls/demos_encrypt.so.dylib
Executable file
Binary file not shown.
0
allauthdemo/polls/polls/forms.py
Executable file
0
allauthdemo/polls/polls/forms.py
Executable file
32
allauthdemo/polls/polls/models.py
Executable file
32
allauthdemo/polls/polls/models.py
Executable 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
|
3
allauthdemo/polls/polls/static/polls/style.css
Executable file
3
allauthdemo/polls/polls/static/polls/style.css
Executable file
|
@ -0,0 +1,3 @@
|
||||||
|
li a {
|
||||||
|
color: green;
|
||||||
|
}
|
9
allauthdemo/polls/polls/tests.py
Executable file
9
allauthdemo/polls/polls/tests.py
Executable 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
23
allauthdemo/polls/polls/urls.py
Executable 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'),
|
||||||
|
]
|
98
allauthdemo/polls/polls/views.py
Executable file
98
allauthdemo/polls/polls/views.py
Executable 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})
|
3
allauthdemo/polls/static/polls/style.css
Executable file
3
allauthdemo/polls/static/polls/style.css
Executable file
|
@ -0,0 +1,3 @@
|
||||||
|
li a {
|
||||||
|
color: green;
|
||||||
|
}
|
117
allauthdemo/polls/tasks.py
Executable file
117
allauthdemo/polls/tasks.py
Executable 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)
|
0
allauthdemo/polls/templatetags/__init__.py
Executable file
0
allauthdemo/polls/templatetags/__init__.py
Executable file
9
allauthdemo/polls/templatetags/custom_filters_tags.py
Executable file
9
allauthdemo/polls/templatetags/custom_filters_tags.py
Executable 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
12
allauthdemo/polls/tests.py
Executable 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
36
allauthdemo/polls/urls.py
Executable 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'),
|
||||||
|
]
|
200
allauthdemo/polls/utils/CreateNewEventModelAdaptor.py
Normal file
200
allauthdemo/polls/utils/CreateNewEventModelAdaptor.py
Normal 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
|
||||||
|
|
0
allauthdemo/polls/utils/__init__.py
Normal file
0
allauthdemo/polls/utils/__init__.py
Normal file
367
allauthdemo/polls/views.py
Executable file
367
allauthdemo/polls/views.py
Executable 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
204
allauthdemo/settings.py
Executable 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
166
allauthdemo/settings.template.py
Executable 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
15
allauthdemo/setup.py
Executable 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])
|
3
allauthdemo/templates/allauth/README.txt
Executable file
3
allauthdemo/templates/allauth/README.txt
Executable 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.
|
45
allauthdemo/templates/allauth/account/base.html
Executable file
45
allauthdemo/templates/allauth/account/base.html
Executable 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 %}
|
||||||
|
#}
|
38
allauthdemo/templates/allauth/account/base2.html
Executable file
38
allauthdemo/templates/allauth/account/base2.html
Executable 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 %}
|
||||||
|
#}
|
90
allauthdemo/templates/allauth/account/email.html
Executable file
90
allauthdemo/templates/allauth/account/email.html
Executable 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 %}
|
31
allauthdemo/templates/allauth/account/email_confirm.html
Executable file
31
allauthdemo/templates/allauth/account/email_confirm.html
Executable 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 %}
|
41
allauthdemo/templates/allauth/account/login.html
Executable file
41
allauthdemo/templates/allauth/account/login.html
Executable 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 %}
|
||||||
|
|
21
allauthdemo/templates/allauth/account/logout.html
Executable file
21
allauthdemo/templates/allauth/account/logout.html
Executable 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 %}
|
90
allauthdemo/templates/allauth/account/my_events_tab.html
Executable file
90
allauthdemo/templates/allauth/account/my_events_tab.html
Executable 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 %}
|
17
allauthdemo/templates/allauth/account/password_change.html
Executable file
17
allauthdemo/templates/allauth/account/password_change.html
Executable 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 %}
|
33
allauthdemo/templates/allauth/account/password_reset.html
Executable file
33
allauthdemo/templates/allauth/account/password_reset.html
Executable 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 %}
|
29
allauthdemo/templates/allauth/account/password_reset_from_key.html
Executable file
29
allauthdemo/templates/allauth/account/password_reset_from_key.html
Executable 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 %}
|
17
allauthdemo/templates/allauth/account/password_set.html
Executable file
17
allauthdemo/templates/allauth/account/password_set.html
Executable 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 %}
|
22
allauthdemo/templates/allauth/account/provider_panel.html
Executable file
22
allauthdemo/templates/allauth/account/provider_panel.html
Executable 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 %}
|
38
allauthdemo/templates/allauth/account/signup.html
Executable file
38
allauthdemo/templates/allauth/account/signup.html
Executable 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 %}
|
||||||
|
|
81
allauthdemo/templates/allauth/socialaccount/connections.html
Executable file
81
allauthdemo/templates/allauth/socialaccount/connections.html
Executable 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">×</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 %}
|
||||||
|
|
||||||
|
|
29
allauthdemo/templates/allauth/socialaccount/signup.html
Executable file
29
allauthdemo/templates/allauth/socialaccount/signup.html
Executable 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 %}
|
||||||
|
|
||||||
|
|
44
allauthdemo/templates/auth/profile.html
Executable file
44
allauthdemo/templates/auth/profile.html
Executable 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 %}
|
12
allauthdemo/templates/bases/bootstrap-auth.html
Executable file
12
allauthdemo/templates/bases/bootstrap-auth.html
Executable 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 %}
|
267
allauthdemo/templates/bases/bootstrap-jquery.html
Executable file
267
allauthdemo/templates/bases/bootstrap-jquery.html
Executable 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 %}
|
42
allauthdemo/templates/bases/bootstrap-member.html
Executable file
42
allauthdemo/templates/bases/bootstrap-member.html
Executable 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 %}
|
25
allauthdemo/templates/bases/bootstrap-minimal.html
Executable file
25
allauthdemo/templates/bases/bootstrap-minimal.html
Executable 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 %}
|
29
allauthdemo/templates/bases/bootstrap-visitor.html
Executable file
29
allauthdemo/templates/bases/bootstrap-visitor.html
Executable 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 %}
|
48
allauthdemo/templates/bases/bootstrap-with-nav.html
Executable file
48
allauthdemo/templates/bases/bootstrap-with-nav.html
Executable 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 %}
|
52
allauthdemo/templates/bases/bootstrap.html
Executable file
52
allauthdemo/templates/bases/bootstrap.html
Executable 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>
|
12
allauthdemo/templates/bootstrap3/accordion-group.html
Executable file
12
allauthdemo/templates/bootstrap3/accordion-group.html
Executable 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>
|
3
allauthdemo/templates/bootstrap3/accordion.html
Executable file
3
allauthdemo/templates/bootstrap3/accordion.html
Executable file
|
@ -0,0 +1,3 @@
|
||||||
|
<div class="panel-group" id="{{ accordion.css_id }}">
|
||||||
|
{{ content|safe }}
|
||||||
|
</div>
|
22
allauthdemo/templates/bootstrap3/betterform.html
Executable file
22
allauthdemo/templates/bootstrap3/betterform.html
Executable 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 %}
|
||||||
|
|
9
allauthdemo/templates/bootstrap3/display_form.html
Executable file
9
allauthdemo/templates/bootstrap3/display_form.html
Executable 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 %}
|
8
allauthdemo/templates/bootstrap3/errors.html
Executable file
8
allauthdemo/templates/bootstrap3/errors.html
Executable 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 %}
|
9
allauthdemo/templates/bootstrap3/errors_formset.html
Executable file
9
allauthdemo/templates/bootstrap3/errors_formset.html
Executable 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 %}
|
||||||
|
|
48
allauthdemo/templates/bootstrap3/field.html
Executable file
48
allauthdemo/templates/bootstrap3/field.html
Executable 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 %}
|
13
allauthdemo/templates/bootstrap3/inputs.html
Executable file
13
allauthdemo/templates/bootstrap3/inputs.html
Executable 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 %}
|
4
allauthdemo/templates/bootstrap3/layout/alert.html
Executable file
4
allauthdemo/templates/bootstrap3/layout/alert.html
Executable 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">×</button>{% endif %}
|
||||||
|
{{ content|safe }}
|
||||||
|
</div>
|
9
allauthdemo/templates/bootstrap3/layout/baseinput.html
Executable file
9
allauthdemo/templates/bootstrap3/layout/baseinput.html
Executable 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 }}
|
||||||
|
/>
|
1
allauthdemo/templates/bootstrap3/layout/button.html
Executable file
1
allauthdemo/templates/bootstrap3/layout/button.html
Executable file
|
@ -0,0 +1 @@
|
||||||
|
<button {{ button.flat_attrs|safe }}>{{ button.content|safe }}</button>
|
4
allauthdemo/templates/bootstrap3/layout/buttonholder.html
Executable file
4
allauthdemo/templates/bootstrap3/layout/buttonholder.html
Executable 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>
|
17
allauthdemo/templates/bootstrap3/layout/checkboxselectmultiple.html
Executable file
17
allauthdemo/templates/bootstrap3/layout/checkboxselectmultiple.html
Executable 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>
|
14
allauthdemo/templates/bootstrap3/layout/checkboxselectmultiple_inline.html
Executable file
14
allauthdemo/templates/bootstrap3/layout/checkboxselectmultiple_inline.html
Executable 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 %}
|
4
allauthdemo/templates/bootstrap3/layout/div.html
Executable file
4
allauthdemo/templates/bootstrap3/layout/div.html
Executable 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>
|
5
allauthdemo/templates/bootstrap3/layout/field_errors.html
Executable file
5
allauthdemo/templates/bootstrap3/layout/field_errors.html
Executable 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 %}
|
5
allauthdemo/templates/bootstrap3/layout/field_errors_block.html
Executable file
5
allauthdemo/templates/bootstrap3/layout/field_errors_block.html
Executable 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 %}
|
17
allauthdemo/templates/bootstrap3/layout/field_with_buttons.html
Executable file
17
allauthdemo/templates/bootstrap3/layout/field_with_buttons.html
Executable 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>
|
6
allauthdemo/templates/bootstrap3/layout/fieldset.html
Executable file
6
allauthdemo/templates/bootstrap3/layout/fieldset.html
Executable 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>
|
9
allauthdemo/templates/bootstrap3/layout/formactions.html
Executable file
9
allauthdemo/templates/bootstrap3/layout/formactions.html
Executable 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>
|
7
allauthdemo/templates/bootstrap3/layout/help_text.html
Executable file
7
allauthdemo/templates/bootstrap3/layout/help_text.html
Executable 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 %}
|
13
allauthdemo/templates/bootstrap3/layout/help_text_and_errors.html
Executable file
13
allauthdemo/templates/bootstrap3/layout/help_text_and_errors.html
Executable 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 %}
|
21
allauthdemo/templates/bootstrap3/layout/inline_field.html
Executable file
21
allauthdemo/templates/bootstrap3/layout/inline_field.html
Executable 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 %}
|
27
allauthdemo/templates/bootstrap3/layout/multifield.html
Executable file
27
allauthdemo/templates/bootstrap3/layout/multifield.html
Executable 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 %}
|
30
allauthdemo/templates/bootstrap3/layout/prepended_appended_text.html
Executable file
30
allauthdemo/templates/bootstrap3/layout/prepended_appended_text.html
Executable 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 %}
|
16
allauthdemo/templates/bootstrap3/layout/radioselect.html
Executable file
16
allauthdemo/templates/bootstrap3/layout/radioselect.html
Executable 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>
|
14
allauthdemo/templates/bootstrap3/layout/radioselect_inline.html
Executable file
14
allauthdemo/templates/bootstrap3/layout/radioselect_inline.html
Executable 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 %}
|
1
allauthdemo/templates/bootstrap3/layout/tab-link.html
Executable file
1
allauthdemo/templates/bootstrap3/layout/tab-link.html
Executable 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>
|
6
allauthdemo/templates/bootstrap3/layout/tab.html
Executable file
6
allauthdemo/templates/bootstrap3/layout/tab.html
Executable 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
Reference in a new issue