diff --git a/eosweb/core/main.py b/eosweb/core/main.py
index 0b1dafd..3445211 100644
--- a/eosweb/core/main.py
+++ b/eosweb/core/main.py
@@ -50,6 +50,28 @@ if 'EOSWEB_SETTINGS' in os.environ:
# Connect to database
db_connect(app.config['DB_NAME'], app.config['MONGO_URI'])
+# Make Flask's serialisation, e.g. for sessions, EosObject aware
+class EosObjectJSONEncoder(flask.json.JSONEncoder):
+ def default(self, obj):
+ if isinstance(obj, EosObject):
+ return EosObject.serialise_and_wrap(obj)
+ return super().default(obj)
+class EosObjectJSONDecoder(flask.json.JSONDecoder):
+ def __init__(self, *args, **kwargs):
+ self.super_object_hook = kwargs.get('object_hook', None)
+ kwargs['object_hook'] = self.my_object_hook
+ super().__init__(*args, **kwargs)
+
+ def my_object_hook(self, val):
+ if 'type' in val:
+ if val['type'] in EosObject.objects:
+ return EosObject.deserialise_and_unwrap(val)
+ if self.super_object_hook:
+ return self.super_object_hook(val)
+ return val
+app.json_encoder = EosObjectJSONEncoder
+app.json_decoder = EosObjectJSONDecoder
+
@app.cli.command('test')
@click.option('--prefix', default=None)
@click.option('--lang', default=None)
@@ -123,6 +145,8 @@ def count_test_election():
def inject_globals():
return {'eos': eos, 'eosweb': eosweb, 'SHA256': eos.core.hashing.SHA256}
+# === Views ===
+
@app.route('/')
def index():
return flask.render_template('index.html')
@@ -197,6 +221,35 @@ def election_api_cast_vote(election):
'vote': EosObject.serialise_and_wrap(vote)
}), mimetype='application/json')
+@app.route('/debug')
+def debug():
+ assert False
+
+@app.route('/auth/login')
+def login():
+ return flask.render_template('auth/login.html')
+
+@app.route('/auth/logout')
+def logout():
+ flask.session['user'] = None
+ #return flask.redirect(flask.request.args['next'] if 'next' in flask.request.args else '/')
+ # I feel like there's some kind of exploit here, so we'll leave this for now
+ return flask.redirect('/')
+
+@app.route('/auth/login_complete')
+def login_complete():
+ return flask.render_template('auth/login_complete.html')
+
+@app.route('/auth/login_cancelled')
+def login_cancelled():
+ return flask.render_template('auth/login_cancelled.html')
+
+# === Apps ===
+
+for app_name in app.config['APPS']:
+ app_main = importlib.import_module(app_name + '.main')
+ app_main.main(app)
+
# === Model-Views ===
model_view_map = {}
diff --git a/eosweb/core/templates/auth/login.html b/eosweb/core/templates/auth/login.html
new file mode 100644
index 0000000..0bece56
--- /dev/null
+++ b/eosweb/core/templates/auth/login.html
@@ -0,0 +1,47 @@
+{% extends 'base.html' %}
+
+{#
+ Eos - Verifiable elections
+ Copyright © 2017 RunasSudo (Yingtong Li)
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program. If not, see .
+#}
+
+{% block title %}Login{% endblock %}
+
+{% block content %}
+ {% if session.user %}
+
You are currently logged in as {{ session.user.username }}. Please select an option from the list below to switch accounts.
+ {% else %}
+ You are not currently logged in. Please select an option from the list below to log in.
+ {% endif %}
+
+ {% for auth_method in eosweb.app.config['AUTH_METHODS'] %}
+ - {{ auth_method[1] }}
+ {% endfor %}
+
+{% endblock %}
+
+{% block basecontent %}
+ {{ super() }}
+
+{% endblock %}
diff --git a/eosweb/core/templates/auth/login_complete.html b/eosweb/core/templates/auth/login_complete.html
new file mode 100644
index 0000000..749ddf5
--- /dev/null
+++ b/eosweb/core/templates/auth/login_complete.html
@@ -0,0 +1,40 @@
+{% extends 'semantic_base.html' %}
+
+{#
+ Eos - Verifiable elections
+ Copyright © 2017 RunasSudo (Yingtong Li)
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program. If not, see .
+#}
+
+{% block title %}Login{% endblock %}
+
+{% block basecontent %}
+
+
+
+
+
You have successfully logged in to your account.
+
You may now close this window and return to your previous page.
+
+
+
+
+
+{% endblock %}
diff --git a/eosweb/core/templates/base.html b/eosweb/core/templates/base.html
index 8c31769..e4ef317 100644
--- a/eosweb/core/templates/base.html
+++ b/eosweb/core/templates/base.html
@@ -26,7 +26,16 @@
diff --git a/eosweb/redditauth/__init__.py b/eosweb/redditauth/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/eosweb/redditauth/main.py b/eosweb/redditauth/main.py
new file mode 100644
index 0000000..d93e836
--- /dev/null
+++ b/eosweb/redditauth/main.py
@@ -0,0 +1,68 @@
+# Eos - Verifiable elections
+# Copyright © 2017 RunasSudo (Yingtong Li)
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see .
+
+from flask_oauthlib.client import OAuth
+
+import flask
+
+from eos.core.objects import *
+
+import base64
+import uuid
+
+class RedditUser(DocumentObject):
+ oauth_token = StringField(is_protected=True)
+ username = StringField()
+
+def main(app):
+ oauth = OAuth()
+ reddit = oauth.remote_app('Reddit',
+ request_token_url=None,
+ authorize_url='https://www.reddit.com/api/v1/authorize.compact',
+ request_token_params={'duration': 'temporary', 'scope': 'identity'},
+ access_token_url='https://www.reddit.com/api/v1/access_token',
+ access_token_method='POST',
+ access_token_headers={
+ 'Authorization': 'Basic ' + base64.b64encode('{}:{}'.format(app.config['REDDIT_OAUTH_CLIENT_ID'], app.config['REDDIT_OAUTH_CLIENT_SECRET']).encode('ascii')).decode('ascii'),
+ 'User-Agent': app.config['REDDIT_USER_AGENT']
+ },
+ consumer_key=app.config['REDDIT_OAUTH_CLIENT_ID'],
+ consumer_secret=app.config['REDDIT_OAUTH_CLIENT_SECRET']
+ )
+
+ @app.route('/auth/reddit/login')
+ def reddit_login():
+ return reddit.authorize(callback=app.config['BASE_URI'] + flask.url_for('reddit_oauth_authorized'), state=uuid.uuid4())
+
+ @reddit.tokengetter
+ def get_reddit_oauth_token():
+ return (flask.session.get('user').oauth_token, '')
+
+ @app.route('/auth/reddit/oauth_callback')
+ def reddit_oauth_authorized():
+ resp = reddit.authorized_response()
+ if resp is None:
+ # Request denied
+ return flask.redirect(flask.url_for('login_cancelled'))
+
+ user = RedditUser()
+ user.oauth_token = resp['access_token']
+ flask.session['user'] = user
+
+ me = reddit.get('https://oauth.reddit.com/api/v1/me')
+ user.username = me.data['name']
+
+ return flask.redirect(flask.url_for('login_complete'))
diff --git a/eosweb/redditauth/settings.py b/eosweb/redditauth/settings.py
new file mode 100644
index 0000000..a7fe7f5
--- /dev/null
+++ b/eosweb/redditauth/settings.py
@@ -0,0 +1,20 @@
+# Eos - Verifiable elections
+# Copyright © 2017 RunasSudo (Yingtong Li)
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see .
+
+REDDIT_OAUTH_CLIENT_ID = 'xxxxxxxxxxxxxx'
+REDDIT_OAUTH_CLIENT_SECRET = 'xxxxxxxxxxxxxxxxxxxxxxxxxxx'
+
+REDDIT_USER_AGENT = 'FIXME'