parent
502fa23d31
commit
4d5c65e6d4
12 changed files with 131 additions and 24 deletions
|
@ -17,7 +17,7 @@ from auth import scopes
|
|||
from auth.auth import require_session_login, process_oauth, has_basic_auth, process_auth_or_cookie
|
||||
from auth.permissions import (AdministerOrganizationPermission, ReadRepositoryPermission,
|
||||
SuperUserPermission, AdministerRepositoryPermission,
|
||||
ModifyRepositoryPermission)
|
||||
ModifyRepositoryPermission, OrganizationMemberPermission)
|
||||
from auth.auth_context import get_authenticated_user
|
||||
from buildtrigger.basehandler import BuildTriggerHandler
|
||||
from buildtrigger.bitbuckethandler import BitbucketBuildTrigger
|
||||
|
@ -69,7 +69,7 @@ def internal_error_display():
|
|||
@web.errorhandler(404)
|
||||
@web.route('/404', methods=['GET'])
|
||||
def not_found_error_display(e = None):
|
||||
resp = render_page_template_with_routedata('404.html')
|
||||
resp = index('', error_code=404)
|
||||
resp.status_code = 404
|
||||
return resp
|
||||
|
||||
|
@ -670,17 +670,46 @@ def attach_custom_build_trigger(namespace_name, repo_name):
|
|||
@parse_repository_name(include_tag=True)
|
||||
@anon_protect
|
||||
def redirect_to_repository(namespace_name, repo_name, tag_name):
|
||||
permission = ReadRepositoryPermission(namespace_name, repo_name)
|
||||
is_public = model.repository.repository_is_public(namespace_name, repo_name)
|
||||
|
||||
# Always return 200 for ac-discovery, to ensure that rkt and other ACI-compliant clients can
|
||||
# find the metadata they need. Permissions will be checked in the registry API.
|
||||
if request.args.get('ac-discovery', 0) == 1:
|
||||
return index('')
|
||||
|
||||
if permission.can() or is_public:
|
||||
# Redirect to the repository page if the user can see the repository.
|
||||
is_public = model.repository.repository_is_public(namespace_name, repo_name)
|
||||
permission = ReadRepositoryPermission(namespace_name, repo_name)
|
||||
repo_exists = bool(model.repository.get_repository(namespace_name, repo_name))
|
||||
|
||||
if repo_exists and (permission.can() or is_public):
|
||||
repo_path = '/'.join([namespace_name, repo_name])
|
||||
return redirect(url_for('web.repository', path=repo_path, tab="tags", tag=tag_name))
|
||||
|
||||
abort(404)
|
||||
namespace_exists = bool(model.user.get_user_or_org(namespace_name))
|
||||
namespace_permission = OrganizationMemberPermission(namespace_name).can()
|
||||
if get_authenticated_user() and get_authenticated_user().username == namespace_name:
|
||||
namespace_permission = True
|
||||
|
||||
# Otherwise, we display an error for the user. Which error we display depends on permissions:
|
||||
# > If the namespace doesn't exist, 404.
|
||||
# > If the user is a member of the namespace:
|
||||
# - If the repository doesn't exist, 404
|
||||
# - If the repository does exist (no access), 403
|
||||
# > If the user is not a member of the namespace: 403
|
||||
error_info = {
|
||||
'for_repo': True,
|
||||
'namespace_exists': namespace_exists,
|
||||
'namespace': namespace_name,
|
||||
'repo_name': repo_name,
|
||||
}
|
||||
|
||||
if not namespace_exists or (namespace_permission and not repo_exists):
|
||||
resp = index('', error_code=404, error_info=json.dumps(error_info))
|
||||
resp.status_code = 404
|
||||
return resp
|
||||
else:
|
||||
resp = index('', error_code=403, error_info=json.dumps(error_info))
|
||||
resp.status_code = 403
|
||||
return resp
|
||||
|
||||
|
||||
@web.route('/<namespace>')
|
||||
|
|
25
static/css/pages/error-view.css
Normal file
25
static/css/pages/error-view.css
Normal file
|
@ -0,0 +1,25 @@
|
|||
.error-view-element {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.error-view-element h2 {
|
||||
font-size: 42px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.error-view-element h3 {
|
||||
font-size: 24px;
|
||||
}
|
||||
|
||||
.error-view-element img {
|
||||
margin-top: 20px;
|
||||
width: 255px;
|
||||
height: 235px;
|
||||
margin-bottom: 40px;
|
||||
}
|
||||
|
||||
.error-view-element .err403 img {
|
||||
margin-top: 30px;
|
||||
width: 225px;
|
||||
height: 205px;
|
||||
}
|
1
static/img/40x/QE-logomark.svg
Normal file
1
static/img/40x/QE-logomark.svg
Normal file
|
@ -0,0 +1 @@
|
|||
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 203.92 187.45"><defs><style>.cls-1{fill:#05ce7c;}.cls-2{fill:#003764;}</style></defs><title>Artboard 1</title><polygon class="cls-1" points="159.61 0 203.92 93.72 159.61 187.45 121.89 187.45 166.2 93.72 121.89 0 159.61 0"/><polygon class="cls-2" points="121.9 187.45 77.59 93.72 121.9 0 159.62 0 115.31 93.72 159.62 187.45 121.9 187.45"/><polygon class="cls-1" points="101.96 42.17 82.02 0 44.3 0 83.1 82.06 101.96 42.17"/><polygon class="cls-1" points="83.1 105.38 44.3 187.45 82.02 187.45 101.96 145.27 83.1 105.38"/><polygon class="cls-2" points="44.31 187.45 0 93.72 44.31 0 82.03 0 37.72 93.72 82.03 187.45 44.31 187.45"/></svg>
|
After Width: | Height: | Size: 719 B |
1
static/img/40x/Quay-logomark.svg
Normal file
1
static/img/40x/Quay-logomark.svg
Normal file
|
@ -0,0 +1 @@
|
|||
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 204 187.48"><defs><style>.cls-1{fill:#40b4e5;}.cls-2{fill:#003764;}</style></defs><title>Artboard 1</title><polygon class="cls-1" points="159.68 -0.04 204 93.72 159.68 187.48 121.94 187.48 166.27 93.72 121.94 -0.04 159.68 -0.04"/><polygon class="cls-2" points="121.94 187.48 77.62 93.72 121.94 -0.04 159.68 -0.04 115.35 93.72 159.68 187.48 121.94 187.48"/><polygon class="cls-1" points="102 42.15 82.06 -0.04 44.32 -0.04 83.13 82.06 102 42.15"/><polygon class="cls-1" points="83.13 105.39 44.32 187.48 82.06 187.48 102 145.29 83.13 105.39"/><polygon class="cls-2" points="44.33 187.48 0 93.72 44.33 -0.04 82.06 -0.04 37.73 93.72 82.06 187.48 44.33 187.48"/></svg>
|
After Width: | Height: | Size: 749 B |
1
static/img/40x/quay-logo-404.svg
Normal file
1
static/img/40x/quay-logo-404.svg
Normal file
File diff suppressed because one or more lines are too long
After Width: | Height: | Size: 8.7 KiB |
|
@ -207,8 +207,9 @@ quayApp.config(['$routeProvider', '$locationProvider', 'pages', function($routeP
|
|||
// Public Repo Experiments
|
||||
.route('/__exp/publicRepo', 'public-repo-exp')
|
||||
|
||||
// Default: Redirect to the landing page
|
||||
.otherwise({redirectTo: '/'});
|
||||
// 404/403
|
||||
.route('/:catchall', 'error-view')
|
||||
.route('/:catch/:all', 'error-view');
|
||||
}]);
|
||||
|
||||
// Configure compile provider to add additional URL prefixes to the sanitization list. We use
|
||||
|
|
17
static/js/pages/error-view.js
Normal file
17
static/js/pages/error-view.js
Normal file
|
@ -0,0 +1,17 @@
|
|||
(function() {
|
||||
/**
|
||||
* Error view page.
|
||||
*/
|
||||
angular.module('quayPages').config(['pages', function(pages) {
|
||||
pages.create('error-view', 'error-view.html', ErrorViewCtrl, {
|
||||
'title': '{{code}}',
|
||||
'description': 'Error',
|
||||
'newLayout': false
|
||||
});
|
||||
}]);
|
||||
|
||||
function ErrorViewCtrl($scope, ApiService, $routeParams, UserService) {
|
||||
$scope.info = window.__error_info;
|
||||
$scope.code = window.__error_code;
|
||||
}
|
||||
}());
|
|
@ -13,6 +13,9 @@
|
|||
function NewOrgCtrl($scope, $routeParams, $timeout, $location, UserService, PlanService, ApiService, CookieService, Features) {
|
||||
$scope.Features = Features;
|
||||
$scope.holder = {};
|
||||
$scope.org = {
|
||||
'name': $routeParams['namespace'] || ''
|
||||
};
|
||||
|
||||
UserService.updateUserIn($scope);
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
})
|
||||
}]);
|
||||
|
||||
function NewRepoCtrl($scope, $location, $http, $timeout, UserService, ApiService, PlanService, TriggerService, Features) {
|
||||
function NewRepoCtrl($scope, $location, $http, $timeout, $routeParams, UserService, ApiService, PlanService, TriggerService, Features) {
|
||||
UserService.updateUserIn($scope);
|
||||
|
||||
$scope.Features = Features;
|
||||
|
@ -19,7 +19,8 @@
|
|||
$scope.repo = {
|
||||
'is_public': 0,
|
||||
'description': '',
|
||||
'initialize': ''
|
||||
'initialize': '',
|
||||
'name': $routeParams['name']
|
||||
};
|
||||
|
||||
$scope.changeNamespace = function(namespace) {
|
||||
|
|
33
static/partials/error-view.html
Normal file
33
static/partials/error-view.html
Normal file
|
@ -0,0 +1,33 @@
|
|||
<div class="error-view-element">
|
||||
<!-- 404 -->
|
||||
<div class="err404" ng-if="code == 404">
|
||||
<h2>404: Not Found</h2>
|
||||
<h3 ng-if="!info.for_repo && !info.namespace_exists">The resource you're looking for doesn't exists</h3>
|
||||
<h3 ng-if="info && !info.namespace_exists">Namespace <strong>{{ info.namespace }}</strong> doesn't exists</h3>
|
||||
<h3 ng-if="info && info.for_repo && info.namespace_exists">The repository you're looking for doesn't exists</h3>
|
||||
|
||||
<img src="/static/img/40x/quay-logo-404.svg">
|
||||
|
||||
<h4 ng-if="!info.for_repo && !info.namespace_exists">
|
||||
Return to the <a href="/">main page</a>
|
||||
</h4>
|
||||
<h4 ng-if="info && !info.namespace_exists">
|
||||
<a href="/organizations/new?namespace={{ info.namespace }}">Create this namespace</a> or return to the <a href="/">main page</a>
|
||||
</h4>
|
||||
<h4 ng-if="info && info.for_repo && info.namespace_exists">
|
||||
<a href="/new?namespace={{ info.namespace }}&name={{ info.repo_name }}">Create this repository</a> or return to the <a href="/">main page</a>
|
||||
</h4>
|
||||
</div>
|
||||
|
||||
<!-- 403 -->
|
||||
<div class="err403" ng-if="code == 403">
|
||||
<h2>403: Unauthorized</h2>
|
||||
<h3 ng-if="!info.for_repo">You are not authorized to view this resource</h3>
|
||||
<h3 ng-if="info.for_repo">You are not authorized to view this repository</h3>
|
||||
<img src="/static/img/40x/QE-logomark.svg" quay-show="!Features.BILLING">
|
||||
<img src="/static/img/40x/Quay-logomark.svg" quay-show="Features.BILLING">
|
||||
|
||||
<h4 ng-if="info.for_repo">Contact the admin of the <strong>{{ info.namespace }}</strong> namespace for access to the repository or you can return to the <a href="/">main page</a></h4>
|
||||
<h4 ng-if="!info.for_repo">Return to the <a href="/">main page</a></h4>
|
||||
</div>
|
||||
</div>
|
|
@ -1,13 +0,0 @@
|
|||
{% extends "error.html" %}
|
||||
|
||||
{% block title %}
|
||||
<title>Page Not Found · Quay</title>
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<h3>The page you're looking for doesn't exist!</h3>
|
||||
<h4>
|
||||
<p>This is somewhat embarrassing, isn’t it? It looks like there's nothing here.</p>
|
||||
<p>You probably want to return to the <a href="/">main page</a>.</p>
|
||||
</h4>
|
||||
{% endblock %}
|
|
@ -40,6 +40,14 @@
|
|||
window.__auth_scopes = {{ scope_set|safe }};
|
||||
window.__vuln_priority = {{ vuln_priority_set|safe }}
|
||||
window.__token = '{{ csrf_token() }}';
|
||||
|
||||
{% if error_code %}
|
||||
window.__error_code = {{ error_code }};
|
||||
{% endif %}
|
||||
|
||||
{% if error_info %}
|
||||
window.__error_info = {{ error_info|safe }};
|
||||
{% endif %}
|
||||
</script>
|
||||
|
||||
{% for script_url in external_scripts %}
|
||||
|
|
Reference in a new issue