Move each flask module into a Blueprint and have CSRF protection only on the API blueprint

This commit is contained in:
Joseph Schorr 2013-12-30 17:05:27 -05:00
parent b598c7ec85
commit 310c98df50
8 changed files with 174 additions and 162 deletions

View file

@ -4,7 +4,7 @@ import requests
import urlparse
import json
from flask import request, make_response, jsonify, abort, url_for
from flask import request, make_response, jsonify, abort, url_for, Blueprint, session
from flask.ext.login import current_user, logout_user
from flask.ext.principal import identity_changed, AnonymousIdentity
from functools import wraps
@ -30,13 +30,25 @@ from endpoints.common import common_login
from util.cache import cache_control
from datetime import datetime, timedelta
store = app.config['STORAGE']
user_files = app.config['USERFILES']
logger = logging.getLogger(__name__)
route_data = None
api = Blueprint('api', __name__)
@api.before_request
def csrf_protect():
if request.method != "GET" and request.method != "HEAD":
token = session.get('_csrf_token', None)
found_token = request.values.get('_csrf_token', None)
# TODO: add if not token here, once we are sure all sessions have a token.
if token != found_token:
abort(403)
def get_route_data():
global route_data
if route_data:
@ -44,14 +56,14 @@ def get_route_data():
routes = []
for rule in app.url_map.iter_rules():
if rule.rule.startswith('/api/'):
endpoint_method = globals()[rule.endpoint]
if rule.endpoint.startswith('api.'):
endpoint_method = globals()[rule.endpoint[4:]] # Remove api.
is_internal = '__internal_call' in dir(endpoint_method)
is_org_api = '__user_call' in dir(endpoint_method)
methods = list(rule.methods.difference(['HEAD', 'OPTIONS']))
route = {
'name': rule.endpoint,
'name': rule.endpoint[4:],
'methods': methods,
'path': rule.rule,
'parameters': list(rule.arguments)
@ -112,28 +124,19 @@ def org_api_call(user_call_name):
return internal_decorator
@app.errorhandler(model.DataModelException)
def handle_dme(ex):
return make_response(ex.message, 400)
@app.errorhandler(KeyError)
def handle_dme_key_error(ex):
return make_response(ex.message, 400)
@app.route('/api/discovery')
@api.route('/discovery')
def discovery():
return jsonify(get_route_data())
@app.route('/api/')
@api.route('/')
@internal_api_call
def welcome():
return make_response('welcome', 200)
@app.route('/api/plans/')
@api.route('/plans/')
def list_plans():
return jsonify({
'plans': PLANS,
@ -165,7 +168,7 @@ def user_view(user):
}
@app.route('/api/user/', methods=['GET'])
@api.route('/user/', methods=['GET'])
@internal_api_call
def get_logged_in_user():
if current_user.is_anonymous():
@ -178,7 +181,7 @@ def get_logged_in_user():
return jsonify(user_view(user))
@app.route('/api/user/private', methods=['GET'])
@api.route('/user/private', methods=['GET'])
@api_login_required
@internal_api_call
def get_user_private_count():
@ -199,7 +202,7 @@ def get_user_private_count():
})
@app.route('/api/user/convert', methods=['POST'])
@api.route('/user/convert', methods=['POST'])
@api_login_required
@internal_api_call
def convert_user_to_organization():
@ -236,7 +239,7 @@ def convert_user_to_organization():
return conduct_signin(admin_username, admin_password)
@app.route('/api/user/', methods=['PUT'])
@api.route('/user/', methods=['PUT'])
@api_login_required
@internal_api_call
def change_user_details():
@ -264,7 +267,7 @@ def change_user_details():
return jsonify(user_view(user))
@app.route('/api/user/', methods=['POST'])
@api.route('/user/', methods=['POST'])
@internal_api_call
def create_new_user():
user_data = request.get_json()
@ -291,7 +294,7 @@ def create_new_user():
return error_resp
@app.route('/api/signin', methods=['POST'])
@api.route('/signin', methods=['POST'])
@internal_api_call
def signin_user():
signin_data = request.get_json()
@ -325,7 +328,7 @@ def conduct_signin(username, password):
return response
@app.route("/api/signout", methods=['POST'])
@api.route("/signout", methods=['POST'])
@api_login_required
@internal_api_call
def logout():
@ -334,7 +337,7 @@ def logout():
return make_response('Success', 200)
@app.route("/api/recovery", methods=['POST'])
@api.route("/recovery", methods=['POST'])
@internal_api_call
def request_recovery_email():
email = request.get_json()['email']
@ -343,7 +346,7 @@ def request_recovery_email():
return make_response('Created', 201)
@app.route('/api/users/<prefix>', methods=['GET'])
@api.route('/users/<prefix>', methods=['GET'])
@api_login_required
def get_matching_users(prefix):
users = model.get_matching_users(prefix)
@ -353,7 +356,7 @@ def get_matching_users(prefix):
})
@app.route('/api/entities/<prefix>', methods=['GET'])
@api.route('/entities/<prefix>', methods=['GET'])
@api_login_required
def get_matching_entities(prefix):
teams = []
@ -419,7 +422,7 @@ def team_view(orgname, team):
}
@app.route('/api/organization/', methods=['POST'])
@api.route('/organization/', methods=['POST'])
@api_login_required
@internal_api_call
def create_organization():
@ -468,7 +471,7 @@ def org_view(o, teams):
return view
@app.route('/api/organization/<orgname>', methods=['GET'])
@api.route('/organization/<orgname>', methods=['GET'])
@api_login_required
def get_organization(orgname):
permission = OrganizationMemberPermission(orgname)
@ -484,7 +487,7 @@ def get_organization(orgname):
abort(403)
@app.route('/api/organization/<orgname>', methods=['PUT'])
@api.route('/organization/<orgname>', methods=['PUT'])
@api_login_required
@org_api_call('change_user_details')
def change_organization_details(orgname):
@ -506,7 +509,7 @@ def change_organization_details(orgname):
abort(403)
@app.route('/api/organization/<orgname>/members', methods=['GET'])
@api.route('/organization/<orgname>/members', methods=['GET'])
@api_login_required
def get_organization_members(orgname):
permission = AdministerOrganizationPermission(orgname)
@ -534,7 +537,7 @@ def get_organization_members(orgname):
abort(403)
@app.route('/api/organization/<orgname>/members/<membername>', methods=['GET'])
@api.route('/organization/<orgname>/members/<membername>', methods=['GET'])
@api_login_required
def get_organization_member(orgname, membername):
permission = AdministerOrganizationPermission(orgname)
@ -562,7 +565,7 @@ def get_organization_member(orgname, membername):
abort(403)
@app.route('/api/organization/<orgname>/private', methods=['GET'])
@api.route('/organization/<orgname>/private', methods=['GET'])
@api_login_required
@internal_api_call
def get_organization_private_allowed(orgname):
@ -597,7 +600,7 @@ def member_view(member):
}
@app.route('/api/organization/<orgname>/team/<teamname>',
@api.route('/organization/<orgname>/team/<teamname>',
methods=['PUT', 'POST'])
@api_login_required
def update_organization_team(orgname, teamname):
@ -643,7 +646,7 @@ def update_organization_team(orgname, teamname):
abort(403)
@app.route('/api/organization/<orgname>/team/<teamname>',
@api.route('/organization/<orgname>/team/<teamname>',
methods=['DELETE'])
@api_login_required
def delete_organization_team(orgname, teamname):
@ -656,7 +659,7 @@ def delete_organization_team(orgname, teamname):
abort(403)
@app.route('/api/organization/<orgname>/team/<teamname>/members',
@api.route('/organization/<orgname>/team/<teamname>/members',
methods=['GET'])
@api_login_required
def get_organization_team_members(orgname, teamname):
@ -679,7 +682,7 @@ def get_organization_team_members(orgname, teamname):
abort(403)
@app.route('/api/organization/<orgname>/team/<teamname>/members/<membername>',
@api.route('/organization/<orgname>/team/<teamname>/members/<membername>',
methods=['PUT', 'POST'])
@api_login_required
def update_organization_team_member(orgname, teamname, membername):
@ -708,7 +711,7 @@ def update_organization_team_member(orgname, teamname, membername):
abort(403)
@app.route('/api/organization/<orgname>/team/<teamname>/members/<membername>',
@api.route('/organization/<orgname>/team/<teamname>/members/<membername>',
methods=['DELETE'])
@api_login_required
def delete_organization_team_member(orgname, teamname, membername):
@ -724,7 +727,7 @@ def delete_organization_team_member(orgname, teamname, membername):
abort(403)
@app.route('/api/repository', methods=['POST'])
@api.route('/repository', methods=['POST'])
@api_login_required
def create_repo():
owner = current_user.db_user()
@ -758,7 +761,7 @@ def create_repo():
abort(403)
@app.route('/api/find/repository', methods=['GET'])
@api.route('/find/repository', methods=['GET'])
def find_repos():
prefix = request.args.get('query', '')
@ -781,7 +784,7 @@ def find_repos():
return jsonify(response)
@app.route('/api/repository/', methods=['GET'])
@api.route('/repository/', methods=['GET'])
def list_repos():
def repo_view(repo_obj):
return {
@ -822,7 +825,7 @@ def list_repos():
return jsonify(response)
@app.route('/api/repository/<path:repository>', methods=['PUT'])
@api.route('/repository/<path:repository>', methods=['PUT'])
@api_login_required
@parse_repository_name
def update_repo(namespace, repository):
@ -844,7 +847,7 @@ def update_repo(namespace, repository):
abort(403)
@app.route('/api/repository/<path:repository>/changevisibility',
@api.route('/repository/<path:repository>/changevisibility',
methods=['POST'])
@api_login_required
@parse_repository_name
@ -865,7 +868,7 @@ def change_repo_visibility(namespace, repository):
abort(403)
@app.route('/api/repository/<path:repository>', methods=['DELETE'])
@api.route('/repository/<path:repository>', methods=['DELETE'])
@api_login_required
@parse_repository_name
def delete_repository(namespace, repository):
@ -890,7 +893,7 @@ def image_view(image):
}
@app.route('/api/repository/<path:repository>', methods=['GET'])
@api.route('/repository/<path:repository>', methods=['GET'])
@parse_repository_name
def get_repo(namespace, repository):
logger.debug('Get repo: %s/%s' % (namespace, repository))
@ -939,7 +942,7 @@ def get_repo(namespace, repository):
abort(403) # Permission denied
@app.route('/api/repository/<path:repository>/build/', methods=['GET'])
@api.route('/repository/<path:repository>/build/', methods=['GET'])
@api_login_required
@parse_repository_name
def get_repo_builds(namespace, repository):
@ -972,7 +975,7 @@ def get_repo_builds(namespace, repository):
abort(403) # Permissions denied
@app.route('/api/repository/<path:repository>/build/', methods=['POST'])
@api.route('/repository/<path:repository>/build/', methods=['POST'])
@api_login_required
@parse_repository_name
def request_repo_build(namespace, repository):
@ -1010,7 +1013,7 @@ def webhook_view(webhook):
}
@app.route('/api/repository/<path:repository>/webhook/', methods=['POST'])
@api.route('/repository/<path:repository>/webhook/', methods=['POST'])
@api_login_required
@parse_repository_name
def create_webhook(namespace, repository):
@ -1030,7 +1033,7 @@ def create_webhook(namespace, repository):
abort(403) # Permissions denied
@app.route('/api/repository/<path:repository>/webhook/<public_id>',
@api.route('/repository/<path:repository>/webhook/<public_id>',
methods=['GET'])
@api_login_required
@parse_repository_name
@ -1043,7 +1046,7 @@ def get_webhook(namespace, repository, public_id):
abort(403) # Permission denied
@app.route('/api/repository/<path:repository>/webhook/', methods=['GET'])
@api.route('/repository/<path:repository>/webhook/', methods=['GET'])
@api_login_required
@parse_repository_name
def list_webhooks(namespace, repository):
@ -1057,7 +1060,7 @@ def list_webhooks(namespace, repository):
abort(403) # Permission denied
@app.route('/api/repository/<path:repository>/webhook/<public_id>',
@api.route('/repository/<path:repository>/webhook/<public_id>',
methods=['DELETE'])
@api_login_required
@parse_repository_name
@ -1073,7 +1076,7 @@ def delete_webhook(namespace, repository, public_id):
abort(403) # Permission denied
@app.route('/api/filedrop/', methods=['POST'])
@api.route('/filedrop/', methods=['POST'])
@api_login_required
@internal_api_call
def get_filedrop_url():
@ -1101,7 +1104,7 @@ def wrap_role_view_org(role_json, user, org_members):
return role_json
@app.route('/api/repository/<path:repository>/image/', methods=['GET'])
@api.route('/repository/<path:repository>/image/', methods=['GET'])
@parse_repository_name
def list_repository_images(namespace, repository):
permission = ReadRepositoryPermission(namespace, repository)
@ -1126,7 +1129,7 @@ def list_repository_images(namespace, repository):
abort(403)
@app.route('/api/repository/<path:repository>/image/<image_id>',
@api.route('/repository/<path:repository>/image/<image_id>',
methods=['GET'])
@parse_repository_name
def get_image(namespace, repository, image_id):
@ -1140,7 +1143,7 @@ def get_image(namespace, repository, image_id):
abort(403)
@app.route('/api/repository/<path:repository>/image/<image_id>/changes',
@api.route('/repository/<path:repository>/image/<image_id>/changes',
methods=['GET'])
@cache_control(max_age=60*60) # Cache for one hour
@parse_repository_name
@ -1158,7 +1161,7 @@ def get_image_changes(namespace, repository, image_id):
abort(403)
@app.route('/api/repository/<path:repository>/tag/<tag>/images',
@api.route('/repository/<path:repository>/tag/<tag>/images',
methods=['GET'])
@parse_repository_name
def list_tag_images(namespace, repository, tag):
@ -1182,7 +1185,7 @@ def list_tag_images(namespace, repository, tag):
abort(403) # Permission denied
@app.route('/api/repository/<path:repository>/permissions/team/',
@api.route('/repository/<path:repository>/permissions/team/',
methods=['GET'])
@api_login_required
@parse_repository_name
@ -1199,7 +1202,7 @@ def list_repo_team_permissions(namespace, repository):
abort(403) # Permission denied
@app.route('/api/repository/<path:repository>/permissions/user/',
@api.route('/repository/<path:repository>/permissions/user/',
methods=['GET'])
@api_login_required
@parse_repository_name
@ -1240,7 +1243,7 @@ def list_repo_user_permissions(namespace, repository):
abort(403) # Permission denied
@app.route('/api/repository/<path:repository>/permissions/user/<username>',
@api.route('/repository/<path:repository>/permissions/user/<username>',
methods=['GET'])
@api_login_required
@parse_repository_name
@ -1265,7 +1268,7 @@ def get_user_permissions(namespace, repository, username):
abort(403) # Permission denied
@app.route('/api/repository/<path:repository>/permissions/team/<teamname>',
@api.route('/repository/<path:repository>/permissions/team/<teamname>',
methods=['GET'])
@api_login_required
@parse_repository_name
@ -1280,7 +1283,7 @@ def get_team_permissions(namespace, repository, teamname):
abort(403) # Permission denied
@app.route('/api/repository/<path:repository>/permissions/user/<username>',
@api.route('/repository/<path:repository>/permissions/user/<username>',
methods=['PUT', 'POST'])
@api_login_required
@parse_repository_name
@ -1323,7 +1326,7 @@ def change_user_permissions(namespace, repository, username):
abort(403) # Permission denied
@app.route('/api/repository/<path:repository>/permissions/team/<teamname>',
@api.route('/repository/<path:repository>/permissions/team/<teamname>',
methods=['PUT', 'POST'])
@api_login_required
@parse_repository_name
@ -1351,7 +1354,7 @@ def change_team_permissions(namespace, repository, teamname):
abort(403) # Permission denied
@app.route('/api/repository/<path:repository>/permissions/user/<username>',
@api.route('/repository/<path:repository>/permissions/user/<username>',
methods=['DELETE'])
@api_login_required
@parse_repository_name
@ -1376,7 +1379,7 @@ def delete_user_permissions(namespace, repository, username):
abort(403) # Permission denied
@app.route('/api/repository/<path:repository>/permissions/team/<teamname>',
@api.route('/repository/<path:repository>/permissions/team/<teamname>',
methods=['DELETE'])
@api_login_required
@parse_repository_name
@ -1402,7 +1405,7 @@ def token_view(token_obj):
}
@app.route('/api/repository/<path:repository>/tokens/', methods=['GET'])
@api.route('/repository/<path:repository>/tokens/', methods=['GET'])
@api_login_required
@parse_repository_name
def list_repo_tokens(namespace, repository):
@ -1417,7 +1420,7 @@ def list_repo_tokens(namespace, repository):
abort(403) # Permission denied
@app.route('/api/repository/<path:repository>/tokens/<code>', methods=['GET'])
@api.route('/repository/<path:repository>/tokens/<code>', methods=['GET'])
@api_login_required
@parse_repository_name
def get_tokens(namespace, repository, code):
@ -1429,7 +1432,7 @@ def get_tokens(namespace, repository, code):
abort(403) # Permission denied
@app.route('/api/repository/<path:repository>/tokens/', methods=['POST'])
@api.route('/repository/<path:repository>/tokens/', methods=['POST'])
@api_login_required
@parse_repository_name
def create_token(namespace, repository):
@ -1451,7 +1454,7 @@ def create_token(namespace, repository):
abort(403) # Permission denied
@app.route('/api/repository/<path:repository>/tokens/<code>', methods=['PUT'])
@api.route('/repository/<path:repository>/tokens/<code>', methods=['PUT'])
@api_login_required
@parse_repository_name
def change_token(namespace, repository, code):
@ -1476,7 +1479,7 @@ def change_token(namespace, repository, code):
abort(403) # Permission denied
@app.route('/api/repository/<path:repository>/tokens/<code>',
@api.route('/repository/<path:repository>/tokens/<code>',
methods=['DELETE'])
@api_login_required
@parse_repository_name
@ -1504,7 +1507,7 @@ def subscription_view(stripe_subscription, used_repos):
}
@app.route('/api/user/card', methods=['GET'])
@api.route('/user/card', methods=['GET'])
@api_login_required
@internal_api_call
def get_user_card():
@ -1512,7 +1515,7 @@ def get_user_card():
return get_card(user)
@app.route('/api/organization/<orgname>/card', methods=['GET'])
@api.route('/organization/<orgname>/card', methods=['GET'])
@api_login_required
@internal_api_call
@org_api_call('get_user_card')
@ -1525,7 +1528,7 @@ def get_org_card(orgname):
abort(403)
@app.route('/api/user/card', methods=['POST'])
@api.route('/user/card', methods=['POST'])
@api_login_required
@internal_api_call
def set_user_card():
@ -1536,7 +1539,7 @@ def set_user_card():
return response
@app.route('/api/organization/<orgname>/card', methods=['POST'])
@api.route('/organization/<orgname>/card', methods=['POST'])
@api_login_required
@org_api_call('set_user_card')
def set_org_card(orgname):
@ -1588,7 +1591,7 @@ def get_card(user):
return jsonify({'card': card_info})
@app.route('/api/user/plan', methods=['PUT'])
@api.route('/user/plan', methods=['PUT'])
@api_login_required
@internal_api_call
def update_user_subscription():
@ -1681,7 +1684,7 @@ def subscribe(user, plan, token, require_business_plan):
return resp
@app.route('/api/user/invoices', methods=['GET'])
@api.route('/user/invoices', methods=['GET'])
@api_login_required
def list_user_invoices():
user = current_user.db_user()
@ -1691,7 +1694,7 @@ def list_user_invoices():
return get_invoices(user.stripe_id)
@app.route('/api/organization/<orgname>/invoices', methods=['GET'])
@api.route('/organization/<orgname>/invoices', methods=['GET'])
@api_login_required
@org_api_call('list_user_invoices')
def list_org_invoices(orgname):
@ -1728,7 +1731,7 @@ def get_invoices(customer_id):
})
@app.route('/api/organization/<orgname>/plan', methods=['PUT'])
@api.route('/organization/<orgname>/plan', methods=['PUT'])
@api_login_required
@internal_api_call
@org_api_call('update_user_subscription')
@ -1744,7 +1747,7 @@ def update_org_subscription(orgname):
abort(403)
@app.route('/api/user/plan', methods=['GET'])
@api.route('/user/plan', methods=['GET'])
@api_login_required
@internal_api_call
def get_user_subscription():
@ -1763,7 +1766,7 @@ def get_user_subscription():
})
@app.route('/api/organization/<orgname>/plan', methods=['GET'])
@api.route('/organization/<orgname>/plan', methods=['GET'])
@api_login_required
@internal_api_call
@org_api_call('get_user_subscription')
@ -1793,7 +1796,7 @@ def robot_view(name, token):
}
@app.route('/api/user/robots', methods=['GET'])
@api.route('/user/robots', methods=['GET'])
@api_login_required
def get_user_robots():
user = current_user.db_user()
@ -1803,7 +1806,7 @@ def get_user_robots():
})
@app.route('/api/organization/<orgname>/robots', methods=['GET'])
@api.route('/organization/<orgname>/robots', methods=['GET'])
@api_login_required
@org_api_call('get_user_robots')
def get_org_robots(orgname):
@ -1817,7 +1820,7 @@ def get_org_robots(orgname):
abort(403)
@app.route('/api/user/robots/<robot_shortname>', methods=['PUT'])
@api.route('/user/robots/<robot_shortname>', methods=['PUT'])
@api_login_required
def create_user_robot(robot_shortname):
parent = current_user.db_user()
@ -1828,7 +1831,7 @@ def create_user_robot(robot_shortname):
return resp
@app.route('/api/organization/<orgname>/robots/<robot_shortname>',
@api.route('/organization/<orgname>/robots/<robot_shortname>',
methods=['PUT'])
@api_login_required
@org_api_call('create_user_robot')
@ -1845,7 +1848,7 @@ def create_org_robot(orgname, robot_shortname):
abort(403)
@app.route('/api/user/robots/<robot_shortname>', methods=['DELETE'])
@api.route('/user/robots/<robot_shortname>', methods=['DELETE'])
@api_login_required
def delete_user_robot(robot_shortname):
parent = current_user.db_user()
@ -1854,7 +1857,7 @@ def delete_user_robot(robot_shortname):
return make_response('No Content', 204)
@app.route('/api/organization/<orgname>/robots/<robot_shortname>',
@api.route('/organization/<orgname>/robots/<robot_shortname>',
methods=['DELETE'])
@api_login_required
@org_api_call('delete_user_robot')
@ -1886,7 +1889,7 @@ def log_view(log):
@app.route('/api/repository/<path:repository>/logs', methods=['GET'])
@api.route('/repository/<path:repository>/logs', methods=['GET'])
@api_login_required
@parse_repository_name
def list_repo_logs(namespace, repository):
@ -1903,7 +1906,7 @@ def list_repo_logs(namespace, repository):
abort(403)
@app.route('/api/organization/<orgname>/logs', methods=['GET'])
@api.route('/organization/<orgname>/logs', methods=['GET'])
@api_login_required
@org_api_call('list_user_logs')
def list_org_logs(orgname):
@ -1919,7 +1922,7 @@ def list_org_logs(orgname):
abort(403)
@app.route('/api/user/logs', methods=['GET'])
@api.route('/user/logs', methods=['GET'])
@api_login_required
def list_user_logs():
performer_name = request.args.get('performer', None)

View file

@ -51,15 +51,14 @@ def common_login(db_user):
return False
@app.before_request
def csrf_protect():
if request.method != "GET" and request.method != "HEAD":
token = session.get('_csrf_token', None)
found_token = request.values.get('_csrf_token', None)
@app.errorhandler(model.DataModelException)
def handle_dme(ex):
return make_response(ex.message, 400)
# TODO: add if not token here, once we are sure all sessions have a token.
if token != found_token:
abort(403)
@app.errorhandler(KeyError)
def handle_dme_key_error(ex):
return make_response(ex.message, 400)
def generate_csrf_token():

View file

@ -2,7 +2,7 @@ import json
import logging
import urlparse
from flask import request, make_response, jsonify, abort, session
from flask import request, make_response, jsonify, abort, session, Blueprint
from functools import wraps
from data import model
@ -18,6 +18,7 @@ from auth.permissions import (ModifyRepositoryPermission, UserPermission,
logger = logging.getLogger(__name__)
index = Blueprint('index', __name__)
def generate_headers(role='read'):
def decorator_method(f):
@ -51,8 +52,8 @@ def generate_headers(role='read'):
return decorator_method
@app.route('/v1/users', methods=['POST'])
@app.route('/v1/users/', methods=['POST'])
@index.route('/users', methods=['POST'])
@index.route('/users/', methods=['POST'])
def create_user():
user_data = request.get_json()
username = user_data['username']
@ -87,8 +88,8 @@ def create_user():
return make_response('Created', 201)
@app.route('/v1/users', methods=['GET'])
@app.route('/v1/users/', methods=['GET'])
@index.route('/users', methods=['GET'])
@index.route('/users/', methods=['GET'])
@process_auth
def get_user():
if get_authenticated_user():
@ -99,7 +100,7 @@ def get_user():
abort(404)
@app.route('/v1/users/<username>/', methods=['PUT'])
@index.route('/users/<username>/', methods=['PUT'])
@process_auth
def update_user(username):
permission = UserPermission(username)
@ -124,7 +125,7 @@ def update_user(username):
abort(403)
@app.route('/v1/repositories/<path:repository>', methods=['PUT'])
@index.route('/repositories/<path:repository>', methods=['PUT'])
@process_auth
@parse_repository_name
@generate_headers(role='write')
@ -192,7 +193,7 @@ def create_repository(namespace, repository):
return response
@app.route('/v1/repositories/<path:repository>/images', methods=['PUT'])
@index.route('/repositories/<path:repository>/images', methods=['PUT'])
@process_auth
@parse_repository_name
@generate_headers(role='write')
@ -238,7 +239,7 @@ def update_images(namespace, repository):
abort(403)
@app.route('/v1/repositories/<path:repository>/images', methods=['GET'])
@index.route('/repositories/<path:repository>/images', methods=['GET'])
@process_auth
@parse_repository_name
@generate_headers(role='read')
@ -294,7 +295,7 @@ def get_repository_images(namespace, repository):
abort(403)
@app.route('/v1/repositories/<path:repository>/images', methods=['DELETE'])
@index.route('/repositories/<path:repository>/images', methods=['DELETE'])
@process_auth
@parse_repository_name
@generate_headers(role='write')
@ -302,19 +303,19 @@ def delete_repository_images(namespace, repository):
return make_response('Not Implemented', 501)
@app.route('/v1/repositories/<path:repository>/auth', methods=['PUT'])
@index.route('/repositories/<path:repository>/auth', methods=['PUT'])
@parse_repository_name
def put_repository_auth(namespace, repository):
return make_response('Not Implemented', 501)
@app.route('/v1/search', methods=['GET'])
@index.route('/search', methods=['GET'])
def get_search():
return make_response('Not Implemented', 501)
@app.route('/_ping')
@app.route('/v1/_ping')
@index.route('/_ping')
@index.route('/_ping')
def ping():
response = make_response('true', 200)
response.headers['X-Docker-Registry-Version'] = '0.6.0'

View file

@ -1,7 +1,8 @@
import logging
import json
from flask import make_response, request, session, Response, abort, redirect
from flask import (make_response, request, session, Response, abort,
redirect, Blueprint)
from functools import wraps
from datetime import datetime
from time import time
@ -15,6 +16,7 @@ from auth.permissions import (ReadRepositoryPermission,
ModifyRepositoryPermission)
from data import model
registry = Blueprint('registry', __name__)
store = app.config['STORAGE']
logger = logging.getLogger(__name__)
@ -72,7 +74,7 @@ def set_cache_headers(f):
return wrapper
@app.route('/v1/images/<image_id>/layer', methods=['GET'])
@registry.route('/images/<image_id>/layer', methods=['GET'])
@process_auth
@extract_namespace_repo_from_session
@require_completion
@ -92,7 +94,7 @@ def get_image_layer(namespace, repository, image_id, headers):
abort(403)
@app.route('/v1/images/<image_id>/layer', methods=['PUT'])
@registry.route('/images/<image_id>/layer', methods=['PUT'])
@process_auth
@extract_namespace_repo_from_session
def put_image_layer(namespace, repository, image_id):
@ -158,7 +160,7 @@ def put_image_layer(namespace, repository, image_id):
return make_response('true', 200)
@app.route('/v1/images/<image_id>/checksum', methods=['PUT'])
@registry.route('/images/<image_id>/checksum', methods=['PUT'])
@process_auth
@extract_namespace_repo_from_session
def put_image_checksum(namespace, repository, image_id):
@ -199,7 +201,7 @@ def put_image_checksum(namespace, repository, image_id):
return make_response('true', 200)
@app.route('/v1/images/<image_id>/json', methods=['GET'])
@registry.route('/images/<image_id>/json', methods=['GET'])
@process_auth
@extract_namespace_repo_from_session
@require_completion
@ -229,7 +231,7 @@ def get_image_json(namespace, repository, image_id, headers):
return response
@app.route('/v1/images/<image_id>/ancestry', methods=['GET'])
@registry.route('/images/<image_id>/ancestry', methods=['GET'])
@process_auth
@extract_namespace_repo_from_session
@require_completion
@ -274,7 +276,7 @@ def store_checksum(namespace, repository, image_id, checksum):
store.put_content(checksum_path, checksum)
@app.route('/v1/images/<image_id>/json', methods=['PUT'])
@registry.route('/images/<image_id>/json', methods=['PUT'])
@process_auth
@extract_namespace_repo_from_session
def put_image_json(namespace, repository, image_id):

View file

@ -2,7 +2,7 @@
import logging
import json
from flask import abort, request, jsonify, make_response
from flask import abort, request, jsonify, make_response, Blueprint
from app import app
from util.names import parse_repository_name
@ -14,8 +14,10 @@ from data import model
logger = logging.getLogger(__name__)
tags = Blueprint('tags', __name__)
@app.route('/v1/repositories/<path:repository>/tags',
@tags.route('/repositories/<path:repository>/tags',
methods=['GET'])
@process_auth
@parse_repository_name
@ -30,7 +32,7 @@ def get_tags(namespace, repository):
abort(403)
@app.route('/v1/repositories/<path:repository>/tags/<tag>',
@tags.route('/repositories/<path:repository>/tags/<tag>',
methods=['GET'])
@process_auth
@parse_repository_name
@ -46,7 +48,7 @@ def get_tag(namespace, repository, tag):
abort(403)
@app.route('/v1/repositories/<path:repository>/tags/<tag>',
@tags.route('/repositories/<path:repository>/tags/<tag>',
methods=['PUT'])
@process_auth
@parse_repository_name
@ -62,7 +64,7 @@ def put_tag(namespace, repository, tag):
abort(403)
@app.route('/v1/repositories/<path:repository>/tags/<tag>',
@tags.route('/repositories/<path:repository>/tags/<tag>',
methods=['DELETE'])
@process_auth
@parse_repository_name
@ -77,7 +79,7 @@ def delete_tag(namespace, repository, tag):
abort(403)
@app.route('/v1/repositories/<path:repository>/tags',
@tags.route('/repositories/<path:repository>/tags',
methods=['DELETE'])
@process_auth
@parse_repository_name

View file

@ -3,7 +3,7 @@ import requests
import stripe
from flask import (abort, redirect, request, url_for, render_template,
make_response, Response)
make_response, Response, Blueprint)
from flask.ext.login import current_user
from urlparse import urlparse
@ -18,6 +18,8 @@ from endpoints.common import common_login
logger = logging.getLogger(__name__)
web = Blueprint('web', __name__)
def render_page_template(name):
resp = make_response(render_template(name, route_data=get_route_data()))
@ -25,16 +27,16 @@ def render_page_template(name):
return resp
@app.route('/', methods=['GET'], defaults={'path': ''})
@app.route('/repository/<path:path>', methods=['GET'])
@app.route('/organization/<path:path>', methods=['GET'])
@web.route('/', methods=['GET'], defaults={'path': ''})
@web.route('/repository/<path:path>', methods=['GET'])
@web.route('/organization/<path:path>', methods=['GET'])
def index(path):
return render_page_template('index.html')
@app.route('/snapshot', methods=['GET'])
@app.route('/snapshot/', methods=['GET'])
@app.route('/snapshot/<path:path>', methods=['GET'])
@web.route('/snapshot', methods=['GET'])
@web.route('/snapshot/', methods=['GET'])
@web.route('/snapshot/<path:path>', methods=['GET'])
def snapshot(path = ''):
parsed = urlparse(request.url)
final_url = '%s://%s/%s' % (parsed.scheme, 'localhost', path)
@ -45,74 +47,74 @@ def snapshot(path = ''):
abort(404)
@app.route('/plans/')
@web.route('/plans/')
def plans():
return index('')
@app.route('/guide/')
@web.route('/guide/')
def guide():
return index('')
@app.route('/organizations/')
@app.route('/organizations/new/')
@web.route('/organizations/')
@web.route('/organizations/new/')
def organizations():
return index('')
@app.route('/user/')
@web.route('/user/')
def user():
return index('')
@app.route('/signin/')
@web.route('/signin/')
def signin():
return index('')
@app.route('/new/')
@web.route('/new/')
def new():
return index('')
@app.route('/repository/')
@web.route('/repository/')
def repository():
return index('')
@app.route('/security/')
@web.route('/security/')
def security():
return index('')
@app.route('/v1')
@app.route('/v1/')
@web.route('/v1')
@web.route('/v1/')
def v1():
return index('')
@app.route('/status', methods=['GET'])
@web.route('/status', methods=['GET'])
def status():
return make_response('Healthy')
@app.route('/tos', methods=['GET'])
@web.route('/tos', methods=['GET'])
def tos():
return render_page_template('tos.html')
@app.route('/disclaimer', methods=['GET'])
@web.route('/disclaimer', methods=['GET'])
def disclaimer():
return render_page_template('disclaimer.html')
@app.route('/privacy', methods=['GET'])
@web.route('/privacy', methods=['GET'])
def privacy():
return render_page_template('privacy.html')
@app.route('/receipt', methods=['GET'])
@web.route('/receipt', methods=['GET'])
def receipt():
if not current_user.is_authenticated():
abort(401)
@ -142,7 +144,7 @@ def receipt():
abort(404)
@app.route('/oauth2/github/callback', methods=['GET'])
@web.route('/oauth2/github/callback', methods=['GET'])
def github_oauth_callback():
code = request.args.get('code')
payload = {
@ -205,7 +207,7 @@ def github_oauth_callback():
return render_page_template('githuberror.html')
@app.route('/confirm', methods=['GET'])
@web.route('/confirm', methods=['GET'])
def confirm_email():
code = request.values['code']
@ -219,7 +221,7 @@ def confirm_email():
return redirect(url_for('index'))
@app.route('/recovery', methods=['GET'])
@web.route('/recovery', methods=['GET'])
def confirm_recovery():
code = request.values['code']
user = model.validate_reset_code(code)
@ -229,8 +231,3 @@ def confirm_recovery():
return redirect(url_for('user'))
else:
abort(403)
@app.route('/reset', methods=['GET'])
def password_reset():
pass

View file

@ -1,7 +1,7 @@
import logging
import stripe
from flask import request, make_response
from flask import request, make_response, Blueprint
from data import model
from app import app
@ -11,8 +11,9 @@ from util.email import send_invoice_email
logger = logging.getLogger(__name__)
webhooks = Blueprint('webhooks', __name__)
@app.route('/webhooks/stripe', methods=['POST'])
@webhooks.route('/stripe', methods=['POST'])
def stripe_webhook():
request_data = request.get_json()
logger.debug('Stripe webhook call: %s' % request_data)