snappass/snappass/main.py

128 lines
3.2 KiB
Python
Raw Normal View History

2012-10-08 19:51:41 +02:00
import os
import sys
2012-10-08 19:51:41 +02:00
import uuid
import re
2012-10-08 19:51:41 +02:00
import redis
2016-08-22 06:33:12 +02:00
from redis.exceptions import ConnectionError
2012-10-08 19:51:41 +02:00
from flask import abort, Flask, render_template, request
2013-10-05 23:12:31 +02:00
NO_SSL = os.environ.get('NO_SSL', False)
app = Flask(__name__)
app.secret_key = os.environ.get('SECRET_KEY', 'Secret Key')
app.config.update(
dict(STATIC_URL=os.environ.get('STATIC_URL', 'static')))
2012-10-08 19:51:41 +02:00
if os.environ.get('REDIS_URL'):
redis_client = redis.StrictRedis.from_url(os.environ.get('REDIS_URL'))
else:
redis_host = os.environ.get('REDIS_HOST', 'localhost')
redis_port = os.environ.get('REDIS_PORT', 6379)
redis_db = os.environ.get('SNAPPASS_REDIS_DB', 0)
redis_client = redis.StrictRedis(
host=redis_host, port=redis_port, db=redis_db)
2012-10-08 19:51:41 +02:00
time_conversion = {
'week': 604800,
'day': 86400,
'hour': 3600
}
def check_redis_alive(fn):
def inner(*args, **kwargs):
try:
if fn.__name__ == 'main':
redis_client.ping()
return fn(*args, **kwargs)
2016-08-22 06:33:12 +02:00
except ConnectionError as e:
print('Failed to connect to redis! %s' % e.message)
if fn.__name__ == 'main':
sys.exit(0)
else:
return abort(500)
return inner
2013-10-05 23:12:31 +02:00
@check_redis_alive
2012-10-08 19:51:41 +02:00
def set_password(password, ttl):
2016-07-18 22:35:57 +02:00
key = uuid.uuid4().hex
redis_client.setex(key, ttl, password)
2012-10-08 19:51:41 +02:00
return key
2013-10-05 23:12:31 +02:00
@check_redis_alive
2012-10-08 19:51:41 +02:00
def get_password(key):
2013-10-05 23:12:31 +02:00
password = redis_client.get(key)
if password is not None:
password = password.decode('utf-8')
2013-10-05 23:12:31 +02:00
redis_client.delete(key)
2012-10-08 19:51:41 +02:00
return password
2013-10-05 23:12:31 +02:00
2012-10-08 19:51:41 +02:00
def clean_input():
"""
Make sure we're not getting bad data from the front end,
format data to be machine readable
"""
2016-07-18 20:52:37 +02:00
if 'password' not in request.form:
2012-10-08 19:51:41 +02:00
abort(400)
2016-07-18 20:52:37 +02:00
if 'ttl' not in request.form:
2012-10-08 19:51:41 +02:00
abort(400)
time_period = request.form['ttl'].lower()
2016-07-18 20:52:37 +02:00
if time_period not in time_conversion:
2012-10-08 19:51:41 +02:00
abort(400)
return time_conversion[time_period], request.form['password']
2013-10-05 23:12:31 +02:00
def request_is_valid(request):
"""
Ensure the request validates the following:
- not made by some specific User-Agents (to avoid chat's preview feature issue)
"""
known_sneaky_user_agents = ['Slackbot', 'facebookexternalhit', 'Twitterbot', 'Facebot', 'WhatsApp']
user_agents_regexp = "|".join(known_sneaky_user_agents)
return not re.search(user_agents_regexp, request.headers.get('User-Agent', ''))
2013-10-05 23:12:31 +02:00
@app.route('/', methods=['GET'])
2012-10-08 19:51:41 +02:00
def index():
return render_template('set_password.html')
2013-10-05 23:12:31 +02:00
@app.route('/', methods=['POST'])
2012-10-08 19:51:41 +02:00
def handle_password():
ttl, password = clean_input()
key = set_password(password, ttl)
2013-10-05 23:12:31 +02:00
if NO_SSL:
base_url = request.url_root
else:
base_url = request.url_root.replace("http://", "https://")
link = base_url + key
return render_template('confirm.html', password_link=link)
2012-10-08 19:51:41 +02:00
2013-10-05 23:12:31 +02:00
@app.route('/<password_key>', methods=['GET'])
2012-10-08 19:51:41 +02:00
def show_password(password_key):
if not request_is_valid(request):
abort(404)
2012-10-08 19:51:41 +02:00
password = get_password(password_key)
if not password:
abort(404)
return render_template('password.html', password=password)
2013-10-05 23:12:31 +02:00
@check_redis_alive
2013-10-05 23:12:31 +02:00
def main():
app.run(host='0.0.0.0', debug=True)
2012-10-08 19:51:41 +02:00
if __name__ == '__main__':
2013-10-05 23:12:31 +02:00
main()