diff --git a/README.md b/README.md index 9b13f3b..1192beb 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ Python module and command-line tool for storing and retrieving data in a Docker - Store arbitrary data (blob-store) - Content addressable - Set up named aliases to blobs -- Supports Docker registry schemas v1 and v2 +- Supports Docker registry schema v2 - Works on Python 3.7+ Please note that `dxf` does _not_ generate Docker container configuration, diff --git a/README.rst b/README.rst index 75c317b..448c4a7 100644 --- a/README.rst +++ b/README.rst @@ -6,7 +6,7 @@ Docker registry. - Store arbitrary data (blob-store) - Content addressable - Set up named aliases to blobs -- Supports Docker registry schemas v1 and v2 +- Supports Docker registry schema v2 - Works on Python 3.7+ Please note that ``dxf`` does *not* generate Docker container diff --git a/docs/_build/doctrees/environment.pickle b/docs/_build/doctrees/environment.pickle index b60b2a0..1de1c2e 100644 Binary files a/docs/_build/doctrees/environment.pickle and b/docs/_build/doctrees/environment.pickle differ diff --git a/docs/_build/html/.buildinfo b/docs/_build/html/.buildinfo index 6ae7971..5ac0930 100644 --- a/docs/_build/html/.buildinfo +++ b/docs/_build/html/.buildinfo @@ -1,4 +1,4 @@ # Sphinx build info version 1 # This file hashes the configuration used when building these files. When it is not found, a full rebuild will be done. -config: 6c8c4c6f0d5de4f2cf55fc05c2d0537c +config: 8732eab962e5b670c69842664f2c425a tags: 645f666f9bcd5a90fca523b33c5a78b7 diff --git a/docs/_build/html/_static/documentation_options.js b/docs/_build/html/_static/documentation_options.js index 77da6b4..6e70c6a 100644 --- a/docs/_build/html/_static/documentation_options.js +++ b/docs/_build/html/_static/documentation_options.js @@ -1,5 +1,5 @@ const DOCUMENTATION_OPTIONS = { - VERSION: '11.5.0', + VERSION: '12.0.0', LANGUAGE: 'en', COLLAPSE_INDEX: false, BUILDER: 'html', diff --git a/docs/_build/html/genindex.html b/docs/_build/html/genindex.html index ef24540..2844518 100644 --- a/docs/_build/html/genindex.html +++ b/docs/_build/html/genindex.html @@ -4,10 +4,10 @@ - Index — python-dxf 11.5.0 documentation + Index — python-dxf 12.0.0 documentation - + @@ -22,7 +22,7 @@

Navigation

  • modules |
  • - + @@ -259,7 +259,7 @@

    Navigation

  • modules |
  • - + diff --git a/docs/_build/html/index.html b/docs/_build/html/index.html index 012f5fc..c272384 100644 --- a/docs/_build/html/index.html +++ b/docs/_build/html/index.html @@ -5,10 +5,10 @@ - dxf module — python-dxf 11.5.0 documentation + dxf module — python-dxf 12.0.0 documentation - + @@ -23,7 +23,7 @@

    Navigation

  • modules |
  • - + @@ -695,7 +695,7 @@

    Navigation

  • modules |
  • - + diff --git a/docs/_build/html/objects.inv b/docs/_build/html/objects.inv index 7a8628d..e4211ae 100644 Binary files a/docs/_build/html/objects.inv and b/docs/_build/html/objects.inv differ diff --git a/docs/_build/html/py-modindex.html b/docs/_build/html/py-modindex.html index 402ce2d..6df726a 100644 --- a/docs/_build/html/py-modindex.html +++ b/docs/_build/html/py-modindex.html @@ -4,10 +4,10 @@ - Python Module Index — python-dxf 11.5.0 documentation + Python Module Index — python-dxf 12.0.0 documentation - + @@ -25,7 +25,7 @@

    Navigation

  • modules |
  • - + @@ -89,7 +89,7 @@

    Navigation

  • modules |
  • - + diff --git a/docs/_build/html/search.html b/docs/_build/html/search.html index 2285fd7..68c05e8 100644 --- a/docs/_build/html/search.html +++ b/docs/_build/html/search.html @@ -4,11 +4,11 @@ - Search — python-dxf 11.5.0 documentation + Search — python-dxf 12.0.0 documentation - + @@ -29,7 +29,7 @@

    Navigation

  • modules |
  • - + @@ -86,7 +86,7 @@

    Navigation

  • modules |
  • - + diff --git a/docs/conf.py b/docs/conf.py index 6332b40..198884c 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -58,9 +58,9 @@ # built documents. # # The short X.Y version. -version = '11.5' +version = '12.0' # The full version, including alpha/beta/rc tags. -release = '11.5.0' +release = '12.0.0' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff --git a/dxf/__init__.py b/dxf/__init__.py index 98521a2..ab5afbb 100644 --- a/dxf/__init__.py +++ b/dxf/__init__.py @@ -566,19 +566,9 @@ def set_alias(self, alias: str, *digests: str) -> str: :returns: The registry manifest used to define the alias. You almost definitely won't need this. """ - try: - manifest_json = self.make_manifest(*digests) - self.set_manifest(alias, manifest_json) - return manifest_json - except requests.exceptions.HTTPError as ex: - # pylint: disable=no-member - if ex.response is None or \ - ex.response.status_code != requests.codes.bad_request: - raise - manifest_json = self.make_unsigned_manifest(alias, *digests) - signed_json = _sign_manifest(manifest_json) - self._request('put', 'manifests/' + alias, data=signed_json) - return signed_json + manifest_json = self.make_manifest(*digests) + self.set_manifest(alias, manifest_json) + return manifest_json def get_manifest_and_response(self, alias: str) -> Tuple[str, requests.Response]: """ @@ -630,26 +620,6 @@ def _get_alias(self, alias, manifest, verify, sizes, get_digest, get_dcd, get_ma parsed_manifest = json.loads(manifest) - if parsed_manifest['schemaVersion'] == 1: - # https://github.com/docker/distribution/issues/1662#issuecomment-213101772 - # "A schema1 manifest should always produce the same image id but - # defining the steps to produce directly from the manifest is not - # straight forward." - if get_digest: - raise exceptions.DXFDigestNotAvailableForSchema1() - r = _verify_manifest(manifest, - parsed_manifest, - dcd, - verify, - get_dcd) - if get_dcd: - r, dcd = r - if get_manifest: - r = manifest - else: - r = [(dgst, self.blob_size(dgst)) for dgst in r] if sizes else r - return (r, dcd) if get_dcd else r - if content is not None: if dcd is not None: method, expected_dgst = split_digest(dcd) @@ -822,120 +792,3 @@ def from_base(cls: Type[TD], base: 'DXFBase', repo: str) -> TD: r._headers = base._headers r._sessions = [base._sessions[0]] return r - -# v1 schema support functions below - - def make_unsigned_manifest(self, alias, *digests): - return json.dumps({ - 'schemaVersion': 1, - 'name': self._repo, - 'tag': alias, - 'fsLayers': [{'blobSum': dgst} for dgst in digests], - 'history': [{'v1Compatibility': '{}'} for dgst in digests] - }, sort_keys=True) - -def _urlsafe_b64encode(s): - return base64.urlsafe_b64encode(_to_bytes_2and3(s)).rstrip(b'=').decode('utf-8') - -def _pad64(s): - return s + b'=' * (-len(s) % 4) - -def _urlsafe_b64decode(s): - return base64.urlsafe_b64decode(_pad64(_to_bytes_2and3(s))) - -def _import_key(expkey): - if expkey['kty'] != 'EC': - raise exceptions.DXFUnexpectedKeyTypeError(expkey['kty'], 'EC') - if expkey['crv'] != 'P-256': - raise exceptions.DXFUnexpectedKeyTypeError(expkey['crv'], 'P-256') - return jwk.JWK(kty='EC', crv='P-256', x=expkey['x'], y=expkey['y']) - -def _sign_manifest(manifest_json): - format_length = manifest_json.rfind('}') - format_tail = manifest_json[format_length:] - key = jwk.JWK.generate(kty='EC', crv='P-256') - jwstoken = jws.JWS(manifest_json.encode('utf-8')) - jkey = json.loads(key.export_public()) - # Docker expects 32 bytes for x and y - jkey['x'] = _urlsafe_b64encode(_urlsafe_b64decode(jkey['x']).rjust(32, b'\0')) - jkey['y'] = _urlsafe_b64encode(_urlsafe_b64decode(jkey['y']).rjust(32, b'\0')) - jwstoken.add_signature(key, None, { - 'formatLength': format_length, - 'formatTail': _urlsafe_b64encode(format_tail) - }, { - 'jwk': jkey, - 'alg': 'ES256' - }) - return manifest_json[:format_length] + \ - ', "signatures": [' + jwstoken.serialize() + ']' + \ - format_tail - -def _verify_manifest(content, - manifest, - content_digest, - verify, - get_content_digest): - # pylint: disable=too-many-locals,too-many-branches - - # Adapted from https://github.com/joyent/node-docker-registry-client - - if verify or ('signatures' in manifest): - signatures = [] - for sig in manifest['signatures']: - protected64 = sig['protected'] - protected = _urlsafe_b64decode(protected64).decode('utf-8') - protected_header = json.loads(protected) - - format_length = protected_header['formatLength'] - format_tail64 = protected_header['formatTail'] - format_tail = _urlsafe_b64decode(format_tail64).decode('utf-8') - - alg = sig['header']['alg'] - if alg.lower() == 'none': - raise exceptions.DXFDisallowedSignatureAlgorithmError('none') - if sig['header'].get('chain'): - raise exceptions.DXFSignatureChainNotImplementedError() - - signatures.append({ - 'alg': alg, - 'signature': sig['signature'], - 'protected64': protected64, - 'key': _import_key(sig['header']['jwk']), - 'format_length': format_length, - 'format_tail': format_tail - }) - - payload = content[:signatures[0]['format_length']] + \ - signatures[0]['format_tail'] - payload64 = _urlsafe_b64encode(payload) - else: - payload = content - - if content_digest: - method, expected_dgst = split_digest(content_digest) - hasher = hashlib.new(method) - hasher.update(payload.encode('utf-8')) - dgst = hasher.hexdigest() - if dgst != expected_dgst: - raise exceptions.DXFDigestMismatchError( - method + ':' + dgst, - method + ':' + expected_dgst) - elif get_content_digest: - content_digest = hash_bytes(payload.encode('utf-8')) - - if verify: - for sig in signatures: - jwstoken = jws.JWS() - jwstoken.deserialize(json.dumps({ - 'payload': payload64, # pylint: disable=possibly-used-before-assignment - 'protected': sig['protected64'], - 'signature': sig['signature'] - }), sig['key'], sig['alg']) - - dgsts = [] - for layer in manifest['fsLayers']: - dgst = layer['blobSum'] - split_digest(dgst) - dgsts.append(dgst) - - return (dgsts, content_digest) if get_content_digest else dgsts diff --git a/htmlcov/index.html b/htmlcov/index.html index 9433960..4c80a09 100644 --- a/htmlcov/index.html +++ b/htmlcov/index.html @@ -11,7 +11,7 @@

    Coverage report: - 94% + 95%

    @@ -76,12 +76,12 @@

    dxf/__init__.py - 432 - 23 + 352 + 15 0 - 159 - 21 - 92% + 125 + 13 + 93% dxf/main.py @@ -96,12 +96,12 @@

    Total - 606 - 26 + 526 + 18 0 - 285 - 24 - 94% + 251 + 16 + 95% @@ -113,7 +113,7 @@

    coverage.py v7.5.3, - created at 2024-06-15 07:28 +0100 + created at 2024-06-15 17:52 +0100