· 7 years ago · Dec 09, 2018, 06:10 AM
1#!/usr/bin/env python
2#
3# Welcome to the Secret Safe!
4#
5# - users/users.db stores authentication info with the schema:
6#
7# CREATE TABLE users (
8# id VARCHAR(255) PRIMARY KEY AUTOINCREMENT,
9# username VARCHAR(255),
10# password_hash VARCHAR(255),
11# salt VARCHAR(255)
12# );
13#
14# - For extra security, the dictionary of secrets lives
15# data/secrets.json (so a compromise of the database won't
16# compromise the secrets themselves)
17
18import flask
19import hashlib
20import json
21import logging
22import os
23import sqlite3
24import subprocess
25import sys
26from werkzeug import debug
27
28# Generate test data when running locally
29data_dir = os.path.join(os.path.dirname(__file__), 'data')
30if not os.path.exists(data_dir):
31 import generate_data
32 os.mkdir(data_dir)
33 generate_data.main(data_dir, 'dummy-password', 'dummy-proof', 'dummy-plans')
34
35secrets = json.load(open(os.path.join(data_dir, 'secrets.json')))
36index_html = open('index.html').read()
37app = flask.Flask(__name__)
38
39# Turn on backtraces, but turn off code execution (that'd be an easy level!)
40app.config['PROPAGATE_EXCEPTIONS'] = True
41app.wsgi_app = debug.DebuggedApplication(app.wsgi_app, evalex=False)
42
43app.logger.addHandler(logging.StreamHandler(sys.stderr))
44# use persistent entropy file for secret_key
45app.secret_key = open(os.path.join(data_dir, 'entropy.dat')).read()
46
47# Allow setting url_root if needed
48try:
49 from local_settings import url_root
50except ImportError:
51 pass
52
53def absolute_url(path):
54 return url_root + path
55
56@app.route('/')
57def index():
58 try:
59 user_id = flask.session['user_id']
60 except KeyError:
61 return index_html
62 else:
63 secret = secrets[str(user_id)]
64 return (u'Welcome back! Your secret is: "{0}"'.format(secret) +
65 u' (<a href="./logout">Log out</a>)\n')
66
67@app.route('/logout')
68def logout():
69 flask.session.pop('user_id', None)
70 return flask.redirect(absolute_url('/'))
71
72@app.route('/login', methods=['POST'])
73def login():
74 username = flask.request.form.get('username')
75 password = flask.request.form.get('password')
76
77 if not username:
78 return "Must provide username\n"
79
80 if not password:
81 return "Must provide password\n"
82
83 conn = sqlite3.connect(os.path.join(data_dir, 'users.db'))
84 cursor = conn.cursor()
85
86 query = """SELECT id, password_hash, salt FROM users
87 WHERE username = '{0}' LIMIT 1""".format(username)
88 cursor.execute(query)
89
90 res = cursor.fetchone()
91 if not res:
92 return "There's no such user {0}!\n".format(username)
93 user_id, password_hash, salt = res
94
95 calculated_hash = hashlib.sha256(password + salt)
96 if calculated_hash.hexdigest() != password_hash:
97 return "That's not the password for {0}!\n".format(username)
98
99 flask.session['user_id'] = user_id
100 return flask.redirect(absolute_url('/'))
101
102if __name__ == '__main__':
103 # In development: app.run(debug=True)
104 app.run()