2015-07-16 19:49:06 +00:00
|
|
|
# XXX This code is not yet ready to be run in production, and should remain disabled until such
|
|
|
|
# XXX time as this notice is removed.
|
|
|
|
|
2015-06-22 21:37:13 +00:00
|
|
|
import logging
|
|
|
|
import re
|
2015-07-06 19:00:07 +00:00
|
|
|
import jwt.utils
|
|
|
|
import yaml
|
2015-06-22 21:37:13 +00:00
|
|
|
|
|
|
|
from flask import make_response, request
|
|
|
|
|
|
|
|
from app import storage
|
|
|
|
from auth.jwt_auth import process_jwt_auth
|
|
|
|
from endpoints.decorators import anon_protect
|
2015-07-06 19:00:07 +00:00
|
|
|
from endpoints.v2 import v2_bp, require_repo_read, require_repo_write, get_input_stream
|
|
|
|
from digest import digest_tools
|
2015-06-22 21:37:13 +00:00
|
|
|
|
|
|
|
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
|
|
|
|
|
|
VALID_TAG_PATTERN = r'[\w][\w.-]{0,127}'
|
|
|
|
VALID_TAG_REGEX = re.compile(VALID_TAG_PATTERN)
|
|
|
|
|
|
|
|
|
2015-07-06 19:00:07 +00:00
|
|
|
class SignedManifest(object):
|
|
|
|
SIGNATURES_KEY = 'signatures'
|
|
|
|
PROTECTED_KEY = 'protected'
|
|
|
|
FORMAT_LENGTH_KEY = 'formatLength'
|
|
|
|
FORMAT_TAIL_KEY = 'formatTail'
|
|
|
|
REPO_NAME_KEY = 'name'
|
|
|
|
REPO_TAG_KEY = 'tag'
|
|
|
|
|
|
|
|
def __init__(self, manifest_bytes):
|
|
|
|
self._bytes = manifest_bytes
|
|
|
|
parsed = yaml.safe_load(manifest_bytes)
|
|
|
|
|
|
|
|
self._signatures = parsed[self.SIGNATURES_KEY]
|
|
|
|
self._namespace, self._repo_name = parsed[self.REPO_NAME_KEY].split('/')
|
|
|
|
self._tag = parsed[self.REPO_TAG_KEY]
|
|
|
|
|
|
|
|
self._validate()
|
|
|
|
|
|
|
|
def _validate(self):
|
|
|
|
pass
|
|
|
|
|
|
|
|
@property
|
|
|
|
def signatures(self):
|
|
|
|
return self._signatures
|
|
|
|
|
|
|
|
@property
|
|
|
|
def namespace(self):
|
|
|
|
return self._namespace
|
|
|
|
|
|
|
|
@property
|
|
|
|
def repo_name(self):
|
|
|
|
return self._repo_name
|
|
|
|
|
|
|
|
@property
|
|
|
|
def tag(self):
|
|
|
|
return self._tag
|
|
|
|
|
|
|
|
@property
|
|
|
|
def payload(self):
|
|
|
|
protected = self._signatures[0][self.PROTECTED_KEY]
|
|
|
|
parsed_protected = yaml.safe_load(jwt.utils.base64url_decode(protected))
|
|
|
|
logger.debug('parsed_protected: %s', parsed_protected)
|
|
|
|
signed_content_head = self._bytes[:parsed_protected[self.FORMAT_LENGTH_KEY]]
|
|
|
|
logger.debug('signed content head: %s', signed_content_head)
|
|
|
|
signed_content_tail = jwt.utils.base64url_decode(parsed_protected[self.FORMAT_TAIL_KEY])
|
|
|
|
logger.debug('signed content tail: %s', signed_content_tail)
|
|
|
|
return signed_content_head + signed_content_tail
|
2015-06-22 21:37:13 +00:00
|
|
|
|
|
|
|
|
|
|
|
@v2_bp.route('/<namespace>/<repo_name>/manifests/<regex("' + VALID_TAG_PATTERN + '"):tag_name>',
|
|
|
|
methods=['GET'])
|
|
|
|
@process_jwt_auth
|
|
|
|
@require_repo_read
|
|
|
|
@anon_protect
|
|
|
|
def fetch_manifest_by_tagname(namespace, repo_name, tag_name):
|
|
|
|
logger.debug('Fetching tag manifest with name: %s', tag_name)
|
|
|
|
return make_response('Manifest {0}'.format(tag_name))
|
|
|
|
|
|
|
|
|
|
|
|
@v2_bp.route('/<namespace>/<repo_name>/manifests/<regex("' + VALID_TAG_PATTERN + '"):tag_name>',
|
|
|
|
methods=['PUT'])
|
|
|
|
@process_jwt_auth
|
|
|
|
@require_repo_write
|
|
|
|
@anon_protect
|
|
|
|
def write_manifest_by_tagname(namespace, repo_name, tag_name):
|
2015-07-06 19:00:07 +00:00
|
|
|
manifest = SignedManifest(request.data)
|
|
|
|
manifest_digest = digest_tools.sha256_digest(manifest.payload)
|
|
|
|
|
2015-06-22 21:37:13 +00:00
|
|
|
response = make_response('OK', 202)
|
2015-07-06 19:00:07 +00:00
|
|
|
response.headers['Docker-Content-Digest'] = manifest_digest
|
2015-06-22 21:37:13 +00:00
|
|
|
response.headers['Location'] = 'https://fun.com'
|
|
|
|
return response
|
|
|
|
|
|
|
|
|
2015-07-06 19:00:07 +00:00
|
|
|
# @v2_bp.route('/<namespace>/<repo_name>/manifests/<regex("' + digest_tools.DIGEST_PATTERN + '"):tag_digest>',
|
|
|
|
# methods=['PUT'])
|
|
|
|
# @process_jwt_auth
|
|
|
|
# @require_repo_write
|
|
|
|
# @anon_protect
|
|
|
|
# def write_manifest(namespace, repo_name, tag_digest):
|
|
|
|
# logger.debug('Writing tag manifest with name: %s', tag_digest)
|
2015-06-22 21:37:13 +00:00
|
|
|
|
2015-07-06 19:00:07 +00:00
|
|
|
# manifest_path = digest_tools.content_path(tag_digest)
|
|
|
|
# storage.stream_write('local_us', manifest_path, get_input_stream(request))
|
2015-06-22 21:37:13 +00:00
|
|
|
|
2015-07-06 19:00:07 +00:00
|
|
|
# return make_response('Manifest {0}'.format(tag_digest))
|