-
Notifications
You must be signed in to change notification settings - Fork 245
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
First working API implementation #51
Changes from 1 commit
524feac
bf93da4
7fc18ec
b8ce29e
331d421
2e0a296
f59fd33
5a0beb1
9e7ca47
13f294c
75b6a69
68b4cec
173f33f
e45feb1
6fe4733
699293b
548c998
e6eca0d
80f77a6
d407c26
5ddecd4
a2d4245
a42815d
339dc0c
23c3c81
7be6307
380af3c
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -6,7 +6,7 @@ | |
import redis | ||
from redis.exceptions import ConnectionError | ||
|
||
from flask import abort, Flask, render_template, request | ||
from flask import abort, Flask, render_template, request, jsonify | ||
|
||
|
||
SNEAKY_USER_AGENTS = ('Slackbot', 'facebookexternalhit', 'Twitterbot', 'Facebot', 'WhatsApp') | ||
|
@@ -90,12 +90,53 @@ def request_is_valid(request): | |
""" | ||
return not SNEAKY_USER_AGENTS_RE.search(request.headers.get('User-Agent', '')) | ||
|
||
def not_found_api(error=None): | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The |
||
message = { | ||
'status': 404, | ||
'message': 'Not Found: ' + request.url, | ||
} | ||
resp = jsonify(message) | ||
resp.status_code = 404 | ||
|
||
return resp | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Flask has a nice shortcut for this pattern: return make_response(jsonify(message), 404) |
||
|
||
def unsupported_media_type_api(error=None): | ||
message = { | ||
'status': 415, | ||
'message': 'Unsupported Media Type', | ||
} | ||
resp = jsonify(message) | ||
resp.status_code = 415 | ||
|
||
return resp | ||
|
||
def bad_request_api(error=None): | ||
message = { | ||
'status': 400, | ||
'message': 'Bad Request', | ||
} | ||
resp = jsonify(message) | ||
resp.status_code = 400 | ||
|
||
return resp | ||
|
||
|
||
@app.route('/', methods=['GET']) | ||
def index(): | ||
return render_template('set_password.html') | ||
|
||
|
||
@app.route('/api', methods=['GET']) | ||
def index_api(): | ||
if NO_SSL: | ||
base_url = request.url_root | ||
else: | ||
base_url = request.url_root.replace("http://", "https://") | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. These four lines are repeated in multiple endpoint functions. Can we factor them into a common Alternatively, we could just require flask-sslify, which would move this concern out of snappass. |
||
|
||
return "Generate a password share link with the following command: \n\n" \ | ||
"curl -X POST -d \'{\"password\":\"password-here\",\"ttl\":\"week | day | hour\"}\' -H \"Content-Type:application/json\" " + base_url + "api\n" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Minor: using single quotes to quote the string would allow to put unescaped double quotes in it. Makes it easier to read. |
||
|
||
|
||
@app.route('/', methods=['POST']) | ||
def handle_password(): | ||
ttl, password = clean_input() | ||
|
@@ -109,6 +150,52 @@ def handle_password(): | |
return render_template('confirm.html', password_link=link) | ||
|
||
|
||
@app.route('/api', methods=['POST']) | ||
def handle_password_api(): | ||
if not request.headers['Content-Type'] == 'application/json': | ||
return unsupported_media_type_api() | ||
|
||
payload = request.get_json() | ||
|
||
if 'password' in payload: | ||
password = payload['password'] | ||
|
||
if not len(password) > 0: | ||
return bad_request_api() | ||
else: | ||
return bad_request_api() | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Pretty complex logic here. How about something like :
|
||
|
||
if 'ttl' in payload: | ||
time_period = payload['ttl'].lower() | ||
if not time_period in time_conversion: | ||
return bad_request_api() | ||
|
||
ttl = time_conversion[time_period] | ||
else: | ||
# Set ttl to one week if not specified in the JSON | ||
ttl = 604800 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. same here, could do |
||
|
||
key = set_password(password, ttl) | ||
|
||
if NO_SSL: | ||
base_url = request.url_root | ||
else: | ||
base_url = request.url_root.replace("http://", "https://") | ||
|
||
link_web = base_url + key | ||
link_api = base_url + "api/" + key | ||
|
||
data = { | ||
'web' : link_web, | ||
'api' : link_api, | ||
} | ||
|
||
resp = jsonify(data) | ||
resp.status_code = 200 | ||
|
||
return resp | ||
|
||
|
||
@app.route('/<password_key>', methods=['GET']) | ||
def show_password(password_key): | ||
if not request_is_valid(request): | ||
|
@@ -120,6 +207,27 @@ def show_password(password_key): | |
return render_template('password.html', password=password) | ||
|
||
|
||
@app.route('/api/<password_key>', methods=['GET']) | ||
def get_password_api(password_key): | ||
password = get_password(password_key) | ||
if not password: | ||
return not_found_api() | ||
|
||
if NO_SSL: | ||
base_url = request.url_root | ||
else: | ||
base_url = request.url_root.replace("http://", "https://") | ||
|
||
data = { | ||
'password' : password | ||
} | ||
|
||
resp = jsonify(data) | ||
resp.status_code = 200 | ||
|
||
return resp | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You can just do: return jsonify(data) ... because the response defaults to 200. |
||
|
||
|
||
@check_redis_alive | ||
def main(): | ||
app.run(host='0.0.0.0') | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we retain the alphabetized order?