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.auth import require_session_login, process_oauth, has_basic_auth, process_auth_or_cookie
|
||||||
from auth.permissions import (AdministerOrganizationPermission, ReadRepositoryPermission,
|
from auth.permissions import (AdministerOrganizationPermission, ReadRepositoryPermission,
|
||||||
SuperUserPermission, AdministerRepositoryPermission,
|
SuperUserPermission, AdministerRepositoryPermission,
|
||||||
ModifyRepositoryPermission)
|
ModifyRepositoryPermission, OrganizationMemberPermission)
|
||||||
from auth.auth_context import get_authenticated_user
|
from auth.auth_context import get_authenticated_user
|
||||||
from buildtrigger.basehandler import BuildTriggerHandler
|
from buildtrigger.basehandler import BuildTriggerHandler
|
||||||
from buildtrigger.bitbuckethandler import BitbucketBuildTrigger
|
from buildtrigger.bitbuckethandler import BitbucketBuildTrigger
|
||||||
|
@ -69,7 +69,7 @@ def internal_error_display():
|
||||||
@web.errorhandler(404)
|
@web.errorhandler(404)
|
||||||
@web.route('/404', methods=['GET'])
|
@web.route('/404', methods=['GET'])
|
||||||
def not_found_error_display(e = None):
|
def not_found_error_display(e = None):
|
||||||
resp = render_page_template_with_routedata('404.html')
|
resp = index('', error_code=404)
|
||||||
resp.status_code = 404
|
resp.status_code = 404
|
||||||
return resp
|
return resp
|
||||||
|
|
||||||
|
@ -670,17 +670,46 @@ def attach_custom_build_trigger(namespace_name, repo_name):
|
||||||
@parse_repository_name(include_tag=True)
|
@parse_repository_name(include_tag=True)
|
||||||
@anon_protect
|
@anon_protect
|
||||||
def redirect_to_repository(namespace_name, repo_name, tag_name):
|
def redirect_to_repository(namespace_name, repo_name, tag_name):
|
||||||
permission = ReadRepositoryPermission(namespace_name, repo_name)
|
# Always return 200 for ac-discovery, to ensure that rkt and other ACI-compliant clients can
|
||||||
is_public = model.repository.repository_is_public(namespace_name, repo_name)
|
# find the metadata they need. Permissions will be checked in the registry API.
|
||||||
|
|
||||||
if request.args.get('ac-discovery', 0) == 1:
|
if request.args.get('ac-discovery', 0) == 1:
|
||||||
return index('')
|
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])
|
repo_path = '/'.join([namespace_name, repo_name])
|
||||||
return redirect(url_for('web.repository', path=repo_path, tab="tags", tag=tag_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>')
|
@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
|
// Public Repo Experiments
|
||||||
.route('/__exp/publicRepo', 'public-repo-exp')
|
.route('/__exp/publicRepo', 'public-repo-exp')
|
||||||
|
|
||||||
// Default: Redirect to the landing page
|
// 404/403
|
||||||
.otherwise({redirectTo: '/'});
|
.route('/:catchall', 'error-view')
|
||||||
|
.route('/:catch/:all', 'error-view');
|
||||||
}]);
|
}]);
|
||||||
|
|
||||||
// Configure compile provider to add additional URL prefixes to the sanitization list. We use
|
// 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) {
|
function NewOrgCtrl($scope, $routeParams, $timeout, $location, UserService, PlanService, ApiService, CookieService, Features) {
|
||||||
$scope.Features = Features;
|
$scope.Features = Features;
|
||||||
$scope.holder = {};
|
$scope.holder = {};
|
||||||
|
$scope.org = {
|
||||||
|
'name': $routeParams['namespace'] || ''
|
||||||
|
};
|
||||||
|
|
||||||
UserService.updateUserIn($scope);
|
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);
|
UserService.updateUserIn($scope);
|
||||||
|
|
||||||
$scope.Features = Features;
|
$scope.Features = Features;
|
||||||
|
@ -19,7 +19,8 @@
|
||||||
$scope.repo = {
|
$scope.repo = {
|
||||||
'is_public': 0,
|
'is_public': 0,
|
||||||
'description': '',
|
'description': '',
|
||||||
'initialize': ''
|
'initialize': '',
|
||||||
|
'name': $routeParams['name']
|
||||||
};
|
};
|
||||||
|
|
||||||
$scope.changeNamespace = function(namespace) {
|
$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.__auth_scopes = {{ scope_set|safe }};
|
||||||
window.__vuln_priority = {{ vuln_priority_set|safe }}
|
window.__vuln_priority = {{ vuln_priority_set|safe }}
|
||||||
window.__token = '{{ csrf_token() }}';
|
window.__token = '{{ csrf_token() }}';
|
||||||
|
|
||||||
|
{% if error_code %}
|
||||||
|
window.__error_code = {{ error_code }};
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if error_info %}
|
||||||
|
window.__error_info = {{ error_info|safe }};
|
||||||
|
{% endif %}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
{% for script_url in external_scripts %}
|
{% for script_url in external_scripts %}
|
||||||
|
|
Reference in a new issue