Skip to content
This repository was archived by the owner on Sep 12, 2018. It is now read-only.

Commit 6e7bed6

Browse files
committed
Merge pull request #539 from docker/0.8-backport
0.8 backport
2 parents 3be0e0b + 78dfdbd commit 6e7bed6

File tree

5 files changed

+68
-20
lines changed

5 files changed

+68
-20
lines changed

depends/docker-registry-core/docker_registry/core/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@
3939
__credits__ = []
4040

4141
__license__ = 'Apache 2.0'
42-
__version__ = '2.0.0'
42+
__version__ = '2.0.1'
4343
__maintainer__ = 'Docker'
4444
__email__ = '[email protected]'
4545
__status__ = 'Production'

depends/docker-registry-core/docker_registry/core/driver.py

Lines changed: 48 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,10 @@
2828

2929
__all__ = ["fetch", "available", "Base"]
3030

31+
import functools
3132
import logging
3233
import pkgutil
34+
import urllib
3335

3436
import docker_registry.drivers
3537

@@ -39,6 +41,28 @@
3941
logger = logging.getLogger(__name__)
4042

4143

44+
def check(value):
45+
value = str(value)
46+
if value == '..':
47+
value = '%2E%2E'
48+
if value == '.':
49+
value = '%2E'
50+
return urllib.quote_plus(value)
51+
52+
53+
def filter_args(f):
54+
@functools.wraps(f)
55+
def wrapper(*args, **kwargs):
56+
args = list(args)
57+
ref = args.pop(0)
58+
args = [check(arg) for arg in args]
59+
args.insert(0, ref)
60+
for key, value in kwargs.iteritems():
61+
kwargs[key] = check(value)
62+
return f(*args, **kwargs)
63+
return wrapper
64+
65+
4266
class Base(object):
4367

4468
"""Storage is a convenience class...
@@ -59,6 +83,10 @@ class Base(object):
5983
repositories = 'repositories'
6084
images = 'images'
6185

86+
def _repository_path(self, namespace, repository):
87+
return '{0}/{1}/{2}'.format(
88+
self.repositories, namespace, repository)
89+
6290
# Set the IO buffer to 128kB
6391
buffer_size = 128 * 1024
6492
# By default no storage plugin supports it
@@ -68,60 +96,74 @@ def __init__(self, path=None, config=None):
6896
pass
6997

7098
# FIXME(samalba): Move all path resolver in each module (out of the base)
99+
@filter_args
71100
def images_list_path(self, namespace, repository):
72-
repository_path = self.repository_path(
101+
repository_path = self._repository_path(
73102
namespace=namespace, repository=repository)
74103
return '{0}/_images_list'.format(repository_path)
75104

105+
@filter_args
76106
def image_json_path(self, image_id):
77107
return '{0}/{1}/json'.format(self.images, image_id)
78108

109+
@filter_args
79110
def image_mark_path(self, image_id):
80111
return '{0}/{1}/_inprogress'.format(self.images, image_id)
81112

113+
@filter_args
82114
def image_checksum_path(self, image_id):
83115
return '{0}/{1}/_checksum'.format(self.images, image_id)
84116

117+
@filter_args
85118
def image_layer_path(self, image_id):
86119
return '{0}/{1}/layer'.format(self.images, image_id)
87120

121+
@filter_args
88122
def image_ancestry_path(self, image_id):
89123
return '{0}/{1}/ancestry'.format(self.images, image_id)
90124

125+
@filter_args
91126
def image_files_path(self, image_id):
92127
return '{0}/{1}/_files'.format(self.images, image_id)
93128

129+
@filter_args
94130
def image_diff_path(self, image_id):
95131
return '{0}/{1}/_diff'.format(self.images, image_id)
96132

133+
@filter_args
97134
def repository_path(self, namespace, repository):
98135
return '{0}/{1}/{2}'.format(
99136
self.repositories, namespace, repository)
100137

138+
@filter_args
101139
def tag_path(self, namespace, repository, tagname=None):
102-
repository_path = self.repository_path(
140+
repository_path = self._repository_path(
103141
namespace=namespace, repository=repository)
104142
if not tagname:
105143
return repository_path
106144
return '{0}/tag_{1}'.format(repository_path, tagname)
107145

146+
@filter_args
108147
def repository_json_path(self, namespace, repository):
109-
repository_path = self.repository_path(
148+
repository_path = self._repository_path(
110149
namespace=namespace, repository=repository)
111150
return '{0}/json'.format(repository_path)
112151

152+
@filter_args
113153
def repository_tag_json_path(self, namespace, repository, tag):
114-
repository_path = self.repository_path(
154+
repository_path = self._repository_path(
115155
namespace=namespace, repository=repository)
116156
return '{0}/tag{1}_json'.format(repository_path, tag)
117157

158+
@filter_args
118159
def index_images_path(self, namespace, repository):
119-
repository_path = self.repository_path(
160+
repository_path = self._repository_path(
120161
namespace=namespace, repository=repository)
121162
return '{0}/_index_images'.format(repository_path)
122163

164+
@filter_args
123165
def private_flag_path(self, namespace, repository):
124-
repository_path = self.repository_path(
166+
repository_path = self._repository_path(
125167
namespace=namespace, repository=repository)
126168
return '{0}/_private'.format(repository_path)
127169

docker_registry/images.py

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -203,7 +203,8 @@ def get_image_layer(image_id, headers):
203203
bytes_range = _parse_bytes_range()
204204
repository = toolkit.get_repository()
205205
if repository and store.is_private(*repository):
206-
return toolkit.api_error('Image not found', 404)
206+
if not toolkit.validate_parent_access(image_id):
207+
return toolkit.api_error('Image not found', 404)
207208
# If no auth token found, either standalone registry or privileged
208209
# access. In both cases, access is always "public".
209210
return _get_image_layer(image_id, headers, bytes_range)
@@ -321,7 +322,8 @@ def get_image_json(image_id, headers):
321322
try:
322323
repository = toolkit.get_repository()
323324
if repository and store.is_private(*repository):
324-
return toolkit.api_error('Image not found', 404)
325+
if not toolkit.validate_parent_access(image_id):
326+
return toolkit.api_error('Image not found', 404)
325327
# If no auth token found, either standalone registry or privileged
326328
# access. In both cases, access is always "public".
327329
return _get_image_json(image_id, headers)
@@ -448,7 +450,8 @@ def get_image_files(image_id, headers):
448450
try:
449451
repository = toolkit.get_repository()
450452
if repository and store.is_private(*repository):
451-
return toolkit.api_error('Image not found', 404)
453+
if not toolkit.validate_parent_access(image_id):
454+
return toolkit.api_error('Image not found', 404)
452455
# If no auth token found, either standalone registry or privileged
453456
# access. In both cases, access is always "public".
454457
data = layers.get_image_files_json(image_id)
@@ -469,7 +472,8 @@ def get_image_diff(image_id, headers):
469472
return toolkit.api_error('Diff queue is disabled', 400)
470473
repository = toolkit.get_repository()
471474
if repository and store.is_private(*repository):
472-
return toolkit.api_error('Image not found', 404)
475+
if not toolkit.validate_parent_access(image_id):
476+
return toolkit.api_error('Image not found', 404)
473477

474478
# first try the cache
475479
diff_json = layers.get_image_diff_cache(image_id)

docker_registry/tags.py

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,9 @@
2626
@app.route('/v1/repositories/<path:repository>/properties', methods=['PUT'])
2727
@toolkit.parse_repository_name
2828
@toolkit.requires_auth
29-
def set_properties(namespace, repo):
29+
def set_properties(namespace, repository):
3030
logger.debug("[set_access] namespace={0}; repository={1}".format(namespace,
31-
repo))
31+
repository))
3232
data = None
3333
try:
3434
# Note(dmp): unicode patch
@@ -37,10 +37,12 @@ def set_properties(namespace, repo):
3737
pass
3838
if not data or not isinstance(data, dict):
3939
return toolkit.api_error('Invalid data')
40-
private_flag_path = store.private_flag_path(namespace, repo)
41-
if data['access'] == 'private' and not store.is_private(namespace, repo):
40+
private_flag_path = store.private_flag_path(namespace, repository)
41+
if (data['access'] == 'private'
42+
and not store.is_private(namespace, repository)):
4243
store.put_content(private_flag_path, '')
43-
elif data['access'] == 'public' and store.is_private(namespace, repo):
44+
elif (data['access'] == 'public'
45+
and store.is_private(namespace, repository)):
4446
# XXX is this necessary? Or do we know for sure the file exists?
4547
try:
4648
store.remove(private_flag_path)
@@ -52,10 +54,10 @@ def set_properties(namespace, repo):
5254
@app.route('/v1/repositories/<path:repository>/properties', methods=['GET'])
5355
@toolkit.parse_repository_name
5456
@toolkit.requires_auth
55-
def get_properties(namespace, repo):
57+
def get_properties(namespace, repository):
5658
logger.debug("[get_access] namespace={0}; repository={1}".format(namespace,
57-
repo))
58-
is_private = store.is_private(namespace, repo)
59+
repository))
60+
is_private = store.is_private(namespace, repository)
5961
return toolkit.response({
6062
'access': 'private' if is_private else 'public'
6163
})

docker_registry/toolkit.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -274,7 +274,7 @@ def wrapper(repository, *args, **kwargs):
274274
else:
275275
(namespace, repository) = parts
276276
repository = urllib.quote_plus(repository)
277-
return f(namespace, repository, *args, **kwargs)
277+
return f(namespace=namespace, repository=repository, *args, **kwargs)
278278
return wrapper
279279

280280

0 commit comments

Comments
 (0)