From 82084e37d5bed90fbb83c1047bb02071bbd8f25c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 19 Jun 2023 16:32:27 +0000 Subject: [PATCH 01/35] Bump requests from 2.28.1 to 2.31.0 in /requirements Bumps [requests](https://github.com/psf/requests) from 2.28.1 to 2.31.0. - [Release notes](https://github.com/psf/requests/releases) - [Changelog](https://github.com/psf/requests/blob/main/HISTORY.md) - [Commits](https://github.com/psf/requests/compare/v2.28.1...v2.31.0) --- updated-dependencies: - dependency-name: requests dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- requirements/basic.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements/basic.txt b/requirements/basic.txt index a313335..970329b 100644 --- a/requirements/basic.txt +++ b/requirements/basic.txt @@ -1,3 +1,3 @@ peasant==0.6 -requests==2.28.1 +requests==2.31.0 taskio==0.0.5 From 5ab5887baa30abbb5128be3916bc32d9d38f7aaf Mon Sep 17 00:00:00 2001 From: Flavio Garcia Date: Mon, 7 Aug 2023 00:06:53 -0400 Subject: [PATCH 02/35] chore(build): package project using the build module Fixes: #440 --- scripts/build.sh | 7 +++---- setup.py | 1 + 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/scripts/build.sh b/scripts/build.sh index 5e18e3e..22d4469 100755 --- a/scripts/build.sh +++ b/scripts/build.sh @@ -1,6 +1,6 @@ #!/bin/bash ## -## Copyright 2019-2022 Flávio Gonçalves Garcia +## Copyright 2019-2023 Flavio Garcia ## ## Licensed under the Apache License, Version 2.0 (the "License"); ## you may not use this file except in compliance with the License. @@ -16,9 +16,8 @@ ## ## build.sh Build packages to be uploaded to pypi. ## -## Author: Flavio Gonçalves Garcia +## Author: Flavio Garcia -python setup.py bdist_wheel --universal -python setup.py sdist +python -m build rm -rf build rm -rf automatoes.egg-info diff --git a/setup.py b/setup.py index 5a2255f..1136e78 100644 --- a/setup.py +++ b/setup.py @@ -59,6 +59,7 @@ def resolve_requires(requirements_file): url="https://github.com/candango/automatoes", author=automatoes.get_author(), author_email=automatoes.get_author_email(), + python_requires=">= 3.7", classifiers=[ "Development Status :: 5 - Production/Stable", "License :: OSI Approved :: Apache Software License", From 4bb38435fcb5b332fe6270910bae2a6986be0c90 Mon Sep 17 00:00:00 2001 From: Flavio Garcia Date: Mon, 7 Aug 2023 00:09:48 -0400 Subject: [PATCH 03/35] build: release 0.9.11 --- automatoes/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/automatoes/__init__.py b/automatoes/__init__.py index e856551..05abc77 100644 --- a/automatoes/__init__.py +++ b/automatoes/__init__.py @@ -17,7 +17,7 @@ __author__ = "Flavio Garcia " -__version__ = (0, 9, 10) +__version__ = (0, 9, 11) __licence__ = "Apache License V2.0" From c972ba13d2efef4a954f8f2090ffd5bc9239d2a7 Mon Sep 17 00:00:00 2001 From: Stefan Trautvetter Date: Tue, 25 Jul 2023 12:02:00 +0200 Subject: [PATCH 04/35] Added arg output_filename to cli issue command --- automatoes/cli/__init__.py | 4 ++++ automatoes/issue.py | 11 ++++++----- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/automatoes/cli/__init__.py b/automatoes/cli/__init__.py index 74d6d71..179d6b6 100644 --- a/automatoes/cli/__init__.py +++ b/automatoes/cli/__init__.py @@ -87,6 +87,7 @@ def _issue(args): key_file=args.key_file, csr_file=args.csr_file, output_path=args.output, + output_filename=args.output_filename, must_staple=args.ocsp_must_staple, verbose=verbose ) @@ -228,6 +229,9 @@ def manuale_main(): issue_sub.add_argument('--output', '-o', help="The output directory for created objects", default='.') + issue_sub.add_argument('--output-filename', + help="The filename base for created objects", + default=None) issue_sub.add_argument('--ocsp-must-staple', dest='ocsp_must_staple', help="CSR: Request OCSP Must-Staple extension", diff --git a/automatoes/issue.py b/automatoes/issue.py index b09ca34..d8c54da 100644 --- a/automatoes/issue.py +++ b/automatoes/issue.py @@ -50,7 +50,7 @@ def issue(server, paths, account, domains, key_size, key_file=None, - csr_file=None, output_path=None, must_staple=False, verbose=False): + csr_file=None, output_path=None, output_filename=None, must_staple=False, verbose=False): print("Candango Automatoes {}. Manuale replacement.\n\n".format( get_version())) @@ -195,11 +195,12 @@ def issue(server, paths, account, domains, key_size, key_file=None, # Write the key, certificate and full chain os.makedirs(output_path, exist_ok=True) - cert_path = os.path.join(output_path, domains[0] + '.crt') - chain_path = os.path.join(output_path, domains[0] + '.chain.crt') + cert_name = output_filename if output_filename else domains[0] + cert_path = os.path.join(output_path, cert_name + '.crt') + chain_path = os.path.join(output_path, cert_name + '.chain.crt') intermediate_path = os.path.join(output_path, - domains[0] + '.intermediate.crt') - key_path = os.path.join(output_path, domains[0] + '.pem') + cert_name + '.intermediate.crt') + key_path = os.path.join(output_path, cert_name + '.pem') if order.key is not None: with open(key_path, 'wb') as f: From d56bb1ac15292e75b7ef5af9930756fe17b2020d Mon Sep 17 00:00:00 2001 From: Flavio Garcia Date: Mon, 7 Aug 2023 00:17:09 -0400 Subject: [PATCH 05/35] build: release 0.9.12 --- automatoes/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/automatoes/__init__.py b/automatoes/__init__.py index 05abc77..bc4b4d5 100644 --- a/automatoes/__init__.py +++ b/automatoes/__init__.py @@ -17,7 +17,7 @@ __author__ = "Flavio Garcia " -__version__ = (0, 9, 11) +__version__ = (0, 9, 12) __licence__ = "Apache License V2.0" From d126736e4e2a738119eccbcf1d92b766373a034b Mon Sep 17 00:00:00 2001 From: Flavio Garcia Date: Thu, 28 Mar 2024 16:19:00 -0400 Subject: [PATCH 06/35] build(requirements): set peasant or greater or equal 0.6 --- LICENSE | 2 +- requirements/basic.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/LICENSE b/LICENSE index b842d30..437e690 100644 --- a/LICENSE +++ b/LICENSE @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright 2019-2022 Flávio Gonçalves Garcia + Copyright 2019-2024 Flavio Garcia Copyright 2016-2017 Veeti Paananen under MIT License Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/requirements/basic.txt b/requirements/basic.txt index 970329b..ff4bc95 100644 --- a/requirements/basic.txt +++ b/requirements/basic.txt @@ -1,3 +1,3 @@ -peasant==0.6 +peasant>=0.6 requests==2.31.0 taskio==0.0.5 From a9861482ef54cfc793a3b9ccde4eabf39b444d64 Mon Sep 17 00:00:00 2001 From: Flavio Garcia Date: Fri, 29 Mar 2024 14:28:46 -0400 Subject: [PATCH 07/35] docs: remove broken requirements badge --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index cb4f2ff..e450b78 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,6 @@ [![PyPI](https://img.shields.io/pypi/v/automatoes.svg)](https://pypi.org/project/automatoes/) [![Number of PyPI downloads](https://img.shields.io/pypi/dm/automatoes.svg)](https://pypi.org/project/automatoes/#files) [![Build Status](https://img.shields.io/endpoint.svg?url=https%3A%2F%2Factions-badge.atrox.dev%2Fcandango%2Fautomatoes%2Fbadge&style=flat)](https://actions-badge.atrox.dev/candango/automatoes/goto) -[![Requirements Status](https://requires.io/github/candango/automatoes/requirements.svg?branch=develop)](https://requires.io/github/candango/automatoes/requirements/?branch=develop) Automatoes is a [Let's Encrypt](https://letsencrypt.org)/[ACME](https://github.com/ietf-wg-acme/acme/) From 1cf491fc7edf17ccafa33d0d46fb1474a30d7034 Mon Sep 17 00:00:00 2001 From: Flavio Garcia Date: Thu, 20 Jun 2024 23:08:25 -0400 Subject: [PATCH 08/35] build(deps): bump peasant to 0.7.3 --- requirements/basic.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements/basic.txt b/requirements/basic.txt index ff4bc95..5f40c5c 100644 --- a/requirements/basic.txt +++ b/requirements/basic.txt @@ -1,3 +1,3 @@ -peasant>=0.6 +peasant>=0.7.3 requests==2.31.0 taskio==0.0.5 From 9c28ba420b743840f2ab708d9671299c3fea53bc Mon Sep 17 00:00:00 2001 From: Flavio Garcia Date: Fri, 21 Jun 2024 08:24:02 -0400 Subject: [PATCH 09/35] build(deps): bump taskio to 0.0.7 Remove requests and add it to the peasant extras. --- requirements/basic.txt | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/requirements/basic.txt b/requirements/basic.txt index 5f40c5c..45eeddf 100644 --- a/requirements/basic.txt +++ b/requirements/basic.txt @@ -1,3 +1,2 @@ -peasant>=0.7.3 -requests==2.31.0 -taskio==0.0.5 +peasant[requests]>=0.7.3 +taskio>=0.0.7 From cd4b27e05414f70324128e76de537e98b30c5998 Mon Sep 17 00:00:00 2001 From: Flavio Garcia Date: Fri, 21 Jun 2024 11:49:38 -0400 Subject: [PATCH 10/35] build: remove python 3.7 and add 3.12 to the build Fixes: #128 --- .github/workflows/run_tests.yml | 2 +- setup.py | 6 +++--- tests/crypto_test.py | 4 +--- tests/runtests.py | 2 +- 4 files changed, 6 insertions(+), 8 deletions(-) diff --git a/.github/workflows/run_tests.yml b/.github/workflows/run_tests.yml index 5beec09..ca187ff 100644 --- a/.github/workflows/run_tests.yml +++ b/.github/workflows/run_tests.yml @@ -8,7 +8,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - python-version: ["3.7", "3.8", "3.9", "3.10", "3.11"] + python-version: ["3.8", "3.9", "3.10", "3.11", "3.12"] steps: - uses: actions/checkout@v3 - uses: actions/setup-go@v3 diff --git a/setup.py b/setup.py index 1136e78..a82e432 100644 --- a/setup.py +++ b/setup.py @@ -1,6 +1,6 @@ #!/usr/bin/env python # -# Copyright 2019-2021 Flavio Garcia +# Copyright 2019-2024 Flavio Garcia # Copyright 2016-2017 Veeti Paananen under MIT License # # Licensed under the Apache License, Version 2.0 (the "License"); @@ -59,7 +59,7 @@ def resolve_requires(requirements_file): url="https://github.com/candango/automatoes", author=automatoes.get_author(), author_email=automatoes.get_author_email(), - python_requires=">= 3.7", + python_requires=">= 3.8", classifiers=[ "Development Status :: 5 - Production/Stable", "License :: OSI Approved :: Apache Software License", @@ -68,11 +68,11 @@ def resolve_requires(requirements_file): "Intended Audience :: Developers", "Intended Audience :: System Administrators", "Programming Language :: Python :: 3", - "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3 :: Only", ], packages=find_packages(), diff --git a/tests/crypto_test.py b/tests/crypto_test.py index 824ee08..890904d 100644 --- a/tests/crypto_test.py +++ b/tests/crypto_test.py @@ -1,6 +1,4 @@ -#!/usr/bin/env python -# -# Copyright 2019-2022 Flávio Gonçalves Garcia +# Copyright 2019-2024 Flavio Garcia # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/tests/runtests.py b/tests/runtests.py index 621949e..cf289a8 100644 --- a/tests/runtests.py +++ b/tests/runtests.py @@ -1,6 +1,6 @@ #!/usr/bin/env python # -# Copyright 2019-2022 Flávio Gonçalves Garcia +# Copyright 2019-2024 Flavio Garcia # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. From 898cf8fa816adf073adf78a8b436224dabc8e2f6 Mon Sep 17 00:00:00 2001 From: Flavio Garcia Date: Fri, 21 Jun 2024 11:53:24 -0400 Subject: [PATCH 11/35] build(deps): bump actions/checkout to v4 --- .github/workflows/run_tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/run_tests.yml b/.github/workflows/run_tests.yml index ca187ff..c51809b 100644 --- a/.github/workflows/run_tests.yml +++ b/.github/workflows/run_tests.yml @@ -10,7 +10,7 @@ jobs: matrix: python-version: ["3.8", "3.9", "3.10", "3.11", "3.12"] steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - uses: actions/setup-go@v3 with: go-version: '^1.13.1' From 0e6736febccfc03748b9cff0a583d9562ddbc105 Mon Sep 17 00:00:00 2001 From: Flavio Garcia Date: Fri, 21 Jun 2024 11:53:57 -0400 Subject: [PATCH 12/35] build(deps): bump actions/setup-python to v5 --- .github/workflows/run_tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/run_tests.yml b/.github/workflows/run_tests.yml index c51809b..1e6aea6 100644 --- a/.github/workflows/run_tests.yml +++ b/.github/workflows/run_tests.yml @@ -15,7 +15,7 @@ jobs: with: go-version: '^1.13.1' - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: python-version: ${{ matrix.python-version }} - name: Set up peeble From f8df7c668b6a11c7440639e668d5dfc9a42a998e Mon Sep 17 00:00:00 2001 From: Flavio Garcia Date: Fri, 21 Jun 2024 12:10:31 -0400 Subject: [PATCH 13/35] build(deps): add tornado tests requirements --- requirements/tests.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/requirements/tests.txt b/requirements/tests.txt index cda6a36..758d0c7 100644 --- a/requirements/tests.txt +++ b/requirements/tests.txt @@ -1 +1,2 @@ behave==1.2.6 +tornado==6.4.1 From 6a16a7a603dda80f5b55d90983abee18e9cfeb06 Mon Sep 17 00:00:00 2001 From: Flavio Garcia Date: Fri, 21 Jun 2024 12:12:01 -0400 Subject: [PATCH 14/35] refactor(protocol): implement new nonce to acmev2 peasant Refs: #14 #129 --- automatoes/protocol.py | 114 ++++++++++++---------------------- tests/__init__.py | 10 ++- tests/features/environment.py | 8 +-- tests/nonce_test.py | 32 ++++++++++ 4 files changed, 81 insertions(+), 83 deletions(-) create mode 100644 tests/nonce_test.py diff --git a/automatoes/protocol.py b/automatoes/protocol.py index 0abd282..88b58d9 100644 --- a/automatoes/protocol.py +++ b/automatoes/protocol.py @@ -1,6 +1,4 @@ -# -*- coding: UTF-8 -*- -# -# Copyright 2019-2022 Flávio Gonçalves Garcia +# Copyright 2019-2024 Flavio Garcia # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -15,82 +13,15 @@ # limitations under the License. from . import get_version -from peasant import get_version as peasant_get_version -from peasant.client import Peasant, PeasantTransport -import requests -from urllib.parse import urljoin, urlparse - - -class AcmeV2RequestsTransport(PeasantTransport): - - def __init__(self): - super().__init__() - self._directory = None - self._user_agent = ("Automat-o-es %s Peasant %s" % ( - get_version(), peasant_get_version())) - - @property - def DEFAULT_HEADERS(self) -> dict: - return {'User-Agent': self._user_agent} +from peasant.client.protocol import Peasant +from peasant.client.transport_requests import RequestsTransport - def set_directory(self): - response = self.get("/%s" % self.peasant.directory_path) - if response.status_code == 200: - self.peasant.directory_cache = response.json() - else: - raise Exception - def new_nonce(self): - """ Returns a new nonce """ - return self.head(self.peasant.directory['newNonce'], headers={ - 'resource': "new-reg", - 'payload': None, - }).headers.get('Replay-Nonce') - - def get(self, path, **kwargs): - kwargs = self.create_kwargs(**kwargs) - return requests.get(self.sanatize_path(path), **kwargs) - - def head(self, path, **kwargs): - kwargs = self.create_kwargs(**kwargs) - return requests.head(self.path(path), **kwargs) - - def create_kwargs(self, **kwargs): - _headers = self.DEFAULT_HEADERS.copy() - headers = kwargs.get("headers") - if headers: - _headers.update(headers) - kwargs = { - 'headers': _headers - } - if self.peasant.verify: - kwargs['verify'] = self.peasant.verify - return kwargs - - def sanatize_path(self, path): - """ Handle path and make it sure the right path will be used combined - with the url from set to the peasant. - """ - # If https is in we assume that was returned by the directory - if path.startswith("https"): - return path - # Make sure path is relative - if path.startswith("http"): - path = urlparse(path).path - url_parsed = urlparse(self.peasant.url) - if url_parsed.path != "": - url_parsed_path = url_parsed.path - if url_parsed_path.startswith("/"): - url_parsed_path = url_parsed_path[1:] - if path.startswith("/"): - path = path[1:] - path = "%s/%s" % (url_parsed_path, path) - return urljoin(self.peasant.url, path) - - -class AcmeProtocol(Peasant): +class AcmeV2Pesant(Peasant): def __init__(self, transport, **kwargs): + """ + """ super().__init__(transport) self._url = kwargs.get("url") self._account = kwargs.get("account") @@ -121,3 +52,36 @@ def directory_path(self, path): @property def verify(self): return self._verify + + +class AcmeRequestsTransport(RequestsTransport): + + peasant: AcmeV2Pesant + + def __init__(self, bastion_address): + super().__init__(bastion_address) + self._directory = None + self.user_agent = (f"Automatoes/{get_version()} {self.user_agent}") + self.basic_headers = { + 'User-Agent': self.user_agent + } + self.kwargs_updater = self.update_kwargs + + def update_kwargs(self, method, **kwargs): + if self.peasant.verify: + kwargs['verify'] = self.peasant.verify + return kwargs + + def set_directory(self): + response = self.get("/%s" % self.peasant.directory_path) + if response.status_code == 200: + self.peasant.directory_cache = response.json() + else: + raise Exception + + def new_nonce(self): + """ Returns a new nonce """ + return self.head(self.peasant.directory()['newNonce'], headers={ + 'resource': "new-reg", + 'payload': None, + }).headers.get('Replay-Nonce') diff --git a/tests/__init__.py b/tests/__init__.py index 0390a39..32abf81 100644 --- a/tests/__init__.py +++ b/tests/__init__.py @@ -1,6 +1,4 @@ -#!/usr/bin/env python -# -# Copyright 2019-2022 Flávio Gonçalves Garcia +# Copyright 2019-2024 Flavio Garcia # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -20,3 +18,9 @@ TEST_ROOT = os.path.dirname(os.path.abspath(__file__)) FIXTURES_ROOT = os.path.abspath(os.path.join(TEST_ROOT, "fixtures")) PROJECT_ROOT = os.path.abspath(os.path.join(TEST_ROOT, "..")) + + +def get_absolute_path(directory): + return os.path.realpath( + os.path.join(os.path.dirname(__file__), directory) + ) diff --git a/tests/features/environment.py b/tests/features/environment.py index 21a666b..0fc12e2 100644 --- a/tests/features/environment.py +++ b/tests/features/environment.py @@ -1,6 +1,4 @@ -# -*- coding: UTF-8 -*- -# -# Copyright 2019-2022 Flávio Gonçalves Garcia +# Copyright 2019-2024 Flavio Garcia # Copyright 2016-2017 Veeti Paananen under MIT License # # Licensed under the Apache License, Version 2.0 (the "License"); @@ -19,7 +17,7 @@ # https://community.letsencrypt.org/t/staging-endpoint-for-acme-v2/49605 from behave import fixture, use_fixture from automatoes.acme import AcmeV2 -from automatoes.protocol import AcmeProtocol, AcmeV2RequestsTransport +from automatoes.protocol import AcmeV2Pesant, AcmeV2RequestsTransport import os from unittest.case import TestCase @@ -35,7 +33,7 @@ def get_absolute_path(directory): @fixture def acme_protocol(context, timeout=1, **kwargs): transport = AcmeV2RequestsTransport() - context.acme_protocol = AcmeProtocol( + context.acme_protocol = AcmeV2Pesant( transport, url=peeble_url, directory="dir", diff --git a/tests/nonce_test.py b/tests/nonce_test.py new file mode 100644 index 0000000..957fd13 --- /dev/null +++ b/tests/nonce_test.py @@ -0,0 +1,32 @@ +# Copyright 2019-2024 Flavio Garcia +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from . import get_absolute_path +from automatoes.protocol import AcmeV2Pesant, AcmeRequestsTransport +from tornado import testing + + +class NonceTestCase(testing.AsyncTestCase): + """ Test letsencrypt nonce + """ + + @testing.gen_test + async def test_auth(self): + transport = AcmeRequestsTransport("https://localhost:14000") + protocol = AcmeV2Pesant( + transport, + directory="dir", + verify=get_absolute_path("certs/candango.minica.pem") + ) + self.assertIsNotNone(protocol.new_nonce()) From 952f910d2bf0820696e2e3cfd8fb94a90a032a18 Mon Sep 17 00:00:00 2001 From: Flavio Garcia Date: Fri, 21 Jun 2024 12:18:21 -0400 Subject: [PATCH 15/35] fix(tests): fix AcmeRequestsTransport importing Refs: #129 --- tests/features/environment.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/features/environment.py b/tests/features/environment.py index 0fc12e2..caa8066 100644 --- a/tests/features/environment.py +++ b/tests/features/environment.py @@ -17,7 +17,7 @@ # https://community.letsencrypt.org/t/staging-endpoint-for-acme-v2/49605 from behave import fixture, use_fixture from automatoes.acme import AcmeV2 -from automatoes.protocol import AcmeV2Pesant, AcmeV2RequestsTransport +from automatoes.protocol import AcmeV2Pesant, AcmeRequestsTransport import os from unittest.case import TestCase @@ -32,7 +32,7 @@ def get_absolute_path(directory): @fixture def acme_protocol(context, timeout=1, **kwargs): - transport = AcmeV2RequestsTransport() + transport = AcmeRequestsTransport(peeble_url) context.acme_protocol = AcmeV2Pesant( transport, url=peeble_url, From 5876d3d6ce81182f77eaeb1142f14f7eb642783e Mon Sep 17 00:00:00 2001 From: Flavio Garcia Date: Mon, 24 Jun 2024 14:17:36 -0400 Subject: [PATCH 16/35] build(deps): bump minimal pesant to 0.7.4 --- requirements/basic.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements/basic.txt b/requirements/basic.txt index 45eeddf..4ab4b1f 100644 --- a/requirements/basic.txt +++ b/requirements/basic.txt @@ -1,2 +1,2 @@ -peasant[requests]>=0.7.3 +peasant[requests]>=0.7.4 taskio>=0.0.7 From a4f4323ac084c2257d38c9123965e259eef608d6 Mon Sep 17 00:00:00 2001 From: Flavio Garcia Date: Sun, 30 Jun 2024 15:33:08 -0400 Subject: [PATCH 17/35] build(tests): bump actions/setup-go to v5 Also add pip cache to python. --- .github/workflows/run_tests.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/run_tests.yml b/.github/workflows/run_tests.yml index 1e6aea6..93396ff 100644 --- a/.github/workflows/run_tests.yml +++ b/.github/workflows/run_tests.yml @@ -11,13 +11,14 @@ jobs: python-version: ["3.8", "3.9", "3.10", "3.11", "3.12"] steps: - uses: actions/checkout@v4 - - uses: actions/setup-go@v3 + - uses: actions/setup-go@v5 with: go-version: '^1.13.1' - name: Set up Python ${{ matrix.python-version }} uses: actions/setup-python@v5 with: python-version: ${{ matrix.python-version }} + cache: "pip" - name: Set up peeble run: | export GOPATH=~/go From fe8a389d7d76bf1fa397f0b4d1ab1c186d309f23 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 19 Jan 2025 03:03:46 +0000 Subject: [PATCH 18/35] Bump tornado from 6.4.1 to 6.4.2 in /requirements Bumps [tornado](https://github.com/tornadoweb/tornado) from 6.4.1 to 6.4.2. - [Changelog](https://github.com/tornadoweb/tornado/blob/v6.4.2/docs/releases.rst) - [Commits](https://github.com/tornadoweb/tornado/compare/v6.4.1...v6.4.2) --- updated-dependencies: - dependency-name: tornado dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- requirements/tests.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements/tests.txt b/requirements/tests.txt index 758d0c7..fee8d2a 100644 --- a/requirements/tests.txt +++ b/requirements/tests.txt @@ -1,2 +1,2 @@ behave==1.2.6 -tornado==6.4.1 +tornado==6.4.2 From 966d181d7fa72af84929d1695aa02a4a1b43d057 Mon Sep 17 00:00:00 2001 From: Flavio Garcia Date: Tue, 11 Feb 2025 21:43:22 -0500 Subject: [PATCH 19/35] build: run build script after tests Refs: #131 --- .github/workflows/run_tests.yml | 4 +++- LICENSE | 2 +- README.md | 2 +- scripts/build.sh | 4 ++-- 4 files changed, 7 insertions(+), 5 deletions(-) diff --git a/.github/workflows/run_tests.yml b/.github/workflows/run_tests.yml index 93396ff..fff2dbb 100644 --- a/.github/workflows/run_tests.yml +++ b/.github/workflows/run_tests.yml @@ -34,4 +34,6 @@ jobs: export GOPATH=~/go ./scripts/pebble_service.sh start tests/conf/pebble-config.json behave tests/features - ./scripts/pebble_service.sh stop tests/conf/pebble-config.json + - name: Build packages + run: | + ./scripst/build.sh diff --git a/LICENSE b/LICENSE index 437e690..adce694 100644 --- a/LICENSE +++ b/LICENSE @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright 2019-2024 Flavio Garcia + Copyright 2019-2025 Flavio Garcia Copyright 2016-2017 Veeti Paananen under MIT License Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/README.md b/README.md index e450b78..998b931 100644 --- a/README.md +++ b/README.md @@ -290,5 +290,5 @@ initiatives. Available under the This website and all documentation are licensed under [Creative Commons 3.0](http://creativecommons.org/licenses/by/3.0/). -Copyright © 2019-2022 Flávio Gonçalves Garcia +Copyright © 2019-2025 Flavio Garcia Copyright © 2016-2017 Veeti Paananen under MIT License diff --git a/scripts/build.sh b/scripts/build.sh index 22d4469..010dba5 100755 --- a/scripts/build.sh +++ b/scripts/build.sh @@ -1,6 +1,6 @@ #!/bin/bash ## -## Copyright 2019-2023 Flavio Garcia +## Copyright 2019-2025 Flavio Garcia ## ## Licensed under the Apache License, Version 2.0 (the "License"); ## you may not use this file except in compliance with the License. @@ -18,6 +18,6 @@ ## ## Author: Flavio Garcia -python -m build +python -m build -n rm -rf build rm -rf automatoes.egg-info From f40c3c44fc15aa546c901b30c3619b72c5c6685b Mon Sep 17 00:00:00 2001 From: Flavio Garcia Date: Tue, 11 Feb 2025 21:58:22 -0500 Subject: [PATCH 20/35] build(tests): remove python 3.8 and add 3.13 to the build Refs: #134 --- .github/workflows/run_tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/run_tests.yml b/.github/workflows/run_tests.yml index fff2dbb..67aa2d9 100644 --- a/.github/workflows/run_tests.yml +++ b/.github/workflows/run_tests.yml @@ -8,7 +8,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - python-version: ["3.8", "3.9", "3.10", "3.11", "3.12"] + python-version: ["3.9", "3.10", "3.11", "3.12", "3.13"] steps: - uses: actions/checkout@v4 - uses: actions/setup-go@v5 From cd3bf82eb5d931062b35586d05616d4ecf68a20f Mon Sep 17 00:00:00 2001 From: Flavio Garcia Date: Tue, 11 Feb 2025 22:07:49 -0500 Subject: [PATCH 21/35] build(tests): add cache-save as false option to setup-python Refs: #134 --- .github/workflows/run_tests.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/run_tests.yml b/.github/workflows/run_tests.yml index 67aa2d9..9959aa0 100644 --- a/.github/workflows/run_tests.yml +++ b/.github/workflows/run_tests.yml @@ -19,6 +19,7 @@ jobs: with: python-version: ${{ matrix.python-version }} cache: "pip" + cache-save: false - name: Set up peeble run: | export GOPATH=~/go From f79bbd85876cf56e9a6fdcebff1a64b74e19d882 Mon Sep 17 00:00:00 2001 From: Flavio Garcia Date: Tue, 11 Feb 2025 22:10:39 -0500 Subject: [PATCH 22/35] build(tests): remove cache from setup-python Refs: #134 --- .github/workflows/run_tests.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/run_tests.yml b/.github/workflows/run_tests.yml index 9959aa0..6ab38bf 100644 --- a/.github/workflows/run_tests.yml +++ b/.github/workflows/run_tests.yml @@ -18,7 +18,6 @@ jobs: uses: actions/setup-python@v5 with: python-version: ${{ matrix.python-version }} - cache: "pip" cache-save: false - name: Set up peeble run: | From dd143d47e33d800c88471a98800179d3076511c2 Mon Sep 17 00:00:00 2001 From: Flavio Garcia Date: Tue, 11 Feb 2025 22:53:56 -0500 Subject: [PATCH 23/35] refactor: implement resolve_requires without any pip dependency Fixes: #135 --- setup.py | 38 ++++++++++++++++---------------------- 1 file changed, 16 insertions(+), 22 deletions(-) diff --git a/setup.py b/setup.py index a82e432..ab980cd 100644 --- a/setup.py +++ b/setup.py @@ -16,18 +16,8 @@ # limitations under the License. import automatoes -from codecs import open from setuptools import find_packages, setup -import sys - -try: - # for pip >= 10 - from pip._internal.req import parse_requirements -except ImportError: - # for pip <= 9.0.3 - print("error: Upgrade to a pip version newer than 10. Run \"pip install " - "--upgrade pip\".") - sys.exit(1) +import os with open("README.md", "r") as fh: long_description = fh.read() @@ -35,17 +25,21 @@ # Solution from http://bit.ly/29Yl8VN def resolve_requires(requirements_file): - try: - requirements = parse_requirements("./%s" % requirements_file, - session=False) - return [str(ir.req) for ir in requirements] - except AttributeError: - # for pip >= 20.1.x - # Need to run again as the first run was ruined by the exception - requirements = parse_requirements("./%s" % requirements_file, - session=False) - # pr stands for parsed_requirement - return [str(pr.requirement) for pr in requirements] + requires = [] + if os.path.isfile(f"./{requirements_file}"): + file_dir = os.path.dirname(f"./{requirements_file}") + with open(f"./{requirements_file}") as f: + for raw_line in f.readlines(): + line = raw_line.strip().replace("\n", "") + if len(line) > 0: + if line.startswith("-r "): + partial_file = os.path.join(file_dir, line.replace( + "-r ", "")) + partial_requires = resolve_requires(partial_file) + requires = requires + partial_requires + continue + requires.append(line) + return requires setup( From fac72526b641b832ace7c1bcb5084d02e18e07e2 Mon Sep 17 00:00:00 2001 From: Flavio Garcia Date: Tue, 11 Feb 2025 22:54:49 -0500 Subject: [PATCH 24/35] build: Set python_requires to 3.9 and newer Fixes: #134 --- setup.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/setup.py b/setup.py index ab980cd..1cb69e1 100644 --- a/setup.py +++ b/setup.py @@ -1,6 +1,6 @@ #!/usr/bin/env python # -# Copyright 2019-2024 Flavio Garcia +# Copyright 2019-2025 Flavio Garcia # Copyright 2016-2017 Veeti Paananen under MIT License # # Licensed under the Apache License, Version 2.0 (the "License"); @@ -53,7 +53,7 @@ def resolve_requires(requirements_file): url="https://github.com/candango/automatoes", author=automatoes.get_author(), author_email=automatoes.get_author_email(), - python_requires=">= 3.8", + python_requires=">= 3.9", classifiers=[ "Development Status :: 5 - Production/Stable", "License :: OSI Approved :: Apache Software License", @@ -62,11 +62,11 @@ def resolve_requires(requirements_file): "Intended Audience :: Developers", "Intended Audience :: System Administrators", "Programming Language :: Python :: 3", - "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: 3.13", "Programming Language :: Python :: 3 :: Only", ], packages=find_packages(), From b73e1a77d09ece2a03c211079e3ec9bd4f8e3ce8 Mon Sep 17 00:00:00 2001 From: Flavio Garcia Date: Tue, 11 Feb 2025 23:19:50 -0500 Subject: [PATCH 25/35] build(deps): bump peasant to 0.7.5 --- requirements/basic.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements/basic.txt b/requirements/basic.txt index 4ab4b1f..3fd3a96 100644 --- a/requirements/basic.txt +++ b/requirements/basic.txt @@ -1,2 +1,2 @@ -peasant[requests]>=0.7.4 +peasant[requests]>=0.7.5 taskio>=0.0.7 From 054c49e8b27acfd1a86cf0867915678e2d82cde5 Mon Sep 17 00:00:00 2001 From: Flavio Garcia Date: Tue, 11 Feb 2025 23:22:35 -0500 Subject: [PATCH 26/35] build(tests): remove cache-save from actions/setup-python Refs: #131 --- .github/workflows/run_tests.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/run_tests.yml b/.github/workflows/run_tests.yml index 6ab38bf..4983110 100644 --- a/.github/workflows/run_tests.yml +++ b/.github/workflows/run_tests.yml @@ -18,7 +18,6 @@ jobs: uses: actions/setup-python@v5 with: python-version: ${{ matrix.python-version }} - cache-save: false - name: Set up peeble run: | export GOPATH=~/go From cfba4c8f19b9c1d975742ce567a06bc37a9f9fdb Mon Sep 17 00:00:00 2001 From: Flavio Garcia Date: Wed, 12 Feb 2025 00:24:48 -0500 Subject: [PATCH 27/35] build(tests): fix tests Refs: #131 --- automatoes/crypto.py | 9 ++++++++- tests/features/steps/acme_v2_steps.py | 5 +++-- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/automatoes/crypto.py b/automatoes/crypto.py index c8d7e0d..19dac66 100644 --- a/automatoes/crypto.py +++ b/automatoes/crypto.py @@ -228,8 +228,15 @@ def load_pem_certificate(data): return x509.load_pem_x509_certificate(data, default_backend()) +def get_issuer_certificate_domain_name(cert): + for cn in cert.subject: + return cn.value + + def get_certificate_domain_name(cert): - return cert.subject.get_attributes_for_oid(NameOID.COMMON_NAME)[0].value + for ext in cert.extensions: + if isinstance(ext.value, SubjectAlternativeName): + return ext.value.get_values_for_type(DNSName)[0] def get_certificate_domains(cert): diff --git a/tests/features/steps/acme_v2_steps.py b/tests/features/steps/acme_v2_steps.py index 97dc70f..e5bd740 100644 --- a/tests/features/steps/acme_v2_steps.py +++ b/tests/features/steps/acme_v2_steps.py @@ -18,7 +18,8 @@ from behave import given, when, then from automatoes.crypto import (create_csr, generate_rsa_key, strip_certificates, load_pem_certificate, - get_certificate_domain_name) + get_certificate_domain_name, + get_issuer_certificate_domain_name) from automatoes.model import Account from cartola import security @@ -169,7 +170,7 @@ def step_order_has_a_certificate_with_domain(context, what_domain): ) issuer_certificate = load_pem_certificate(certificates[1]) context.tester.assertTrue( - get_certificate_domain_name( + get_issuer_certificate_domain_name( issuer_certificate ).startswith("Pebble Intermediate CA") ) From b8215d8fd5c3c1da032f3a982af3a6a3c9f5efab Mon Sep 17 00:00:00 2001 From: Flavio Garcia Date: Wed, 12 Feb 2025 00:34:29 -0500 Subject: [PATCH 28/35] build(tests): Use x509.SubjectAlternativeName as instance Refs: #131 --- automatoes/acme.py | 6 ++---- automatoes/crypto.py | 9 +++++---- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/automatoes/acme.py b/automatoes/acme.py index d47c77f..c3fca66 100644 --- a/automatoes/acme.py +++ b/automatoes/acme.py @@ -413,8 +413,6 @@ def get_order_challenges(self, order: Order): :param order: order to be challenged :return: Order """ - domains = [identifier['value'] for identifier in - order.contents['identifiers']] order_challenges = [] for auth in order.contents['authorizations']: auth_response = _json(self.post_as_get(auth, self.account.uri)) @@ -522,7 +520,7 @@ def post(self, path, body, headers=None, kid=None): protected = self.get_headers(url=self.path(path)) if kid: protected['kid'] = kid - protected.pop('jwk') + protected.pop("jwk") body = sign_request_v2(self.account.key, protected, body) kwargs = { 'headers': _headers @@ -539,7 +537,7 @@ def post_as_get(self, path, kid, headers=None): protected = self.get_headers(url=self.path(path)) protected['kid'] = kid - protected.pop('jwk') + protected.pop("jwk") body = sign_request_v2(self.account.key, protected, None) kwargs = { 'headers': _headers diff --git a/automatoes/crypto.py b/automatoes/crypto.py index 19dac66..3e9f8ed 100644 --- a/automatoes/crypto.py +++ b/automatoes/crypto.py @@ -28,7 +28,7 @@ with warnings.catch_warnings(): warnings.simplefilter("ignore") from cryptography import x509 -from cryptography.x509 import NameOID +from cryptography.x509 import NameOID, DNSName, SubjectAlternativeName from cryptography.hazmat.backends import default_backend from cryptography.hazmat.primitives.asymmetric import padding from cryptography.hazmat.primitives.asymmetric.rsa import ( @@ -97,7 +97,7 @@ def generate_header(account_key): numbers = account_key.public_key().public_numbers() e = numbers.e.to_bytes((numbers.e.bit_length() // 8 + 1), byteorder='big') n = numbers.n.to_bytes((numbers.n.bit_length() // 8 + 1), byteorder='big') - if n[0] == 0: # for strict JWK + if n[0] == 0: # for strict JWK n = n[1:] return { 'alg': 'RS256', @@ -178,7 +178,8 @@ def export_private_key(key): """ Exports a private key in OpenSSL PEM format. """ - return key.private_bytes(Encoding.PEM, PrivateFormat.TraditionalOpenSSL, NoEncryption()) + return key.private_bytes(Encoding.PEM, PrivateFormat.TraditionalOpenSSL, + NoEncryption()) def create_csr(key, domains, must_staple=False): @@ -235,7 +236,7 @@ def get_issuer_certificate_domain_name(cert): def get_certificate_domain_name(cert): for ext in cert.extensions: - if isinstance(ext.value, SubjectAlternativeName): + if isinstance(ext.value, x509.SubjectAlternativeName): return ext.value.get_values_for_type(DNSName)[0] From 645cce9785d6bc93aaad126b1b9518fe349c3ffd Mon Sep 17 00:00:00 2001 From: Flavio Garcia Date: Wed, 12 Feb 2025 00:36:52 -0500 Subject: [PATCH 29/35] build(tests): fix type at the script path Refs: #131 --- .github/workflows/run_tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/run_tests.yml b/.github/workflows/run_tests.yml index 4983110..88a6fb6 100644 --- a/.github/workflows/run_tests.yml +++ b/.github/workflows/run_tests.yml @@ -35,4 +35,4 @@ jobs: behave tests/features - name: Build packages run: | - ./scripst/build.sh + ./scripts/build.sh From e4cd08a63c0dce7a4b64d77d5e2bad7a55d7b2e6 Mon Sep 17 00:00:00 2001 From: Flavio Garcia Date: Wed, 12 Feb 2025 00:43:44 -0500 Subject: [PATCH 30/35] build: revert build script with no isolation Refs: #131 --- scripts/build.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/build.sh b/scripts/build.sh index 010dba5..7c51c26 100755 --- a/scripts/build.sh +++ b/scripts/build.sh @@ -18,6 +18,6 @@ ## ## Author: Flavio Garcia -python -m build -n +python -m build rm -rf build rm -rf automatoes.egg-info From c3674809e0fb75504c5bc762f62ad2bafde2a3d6 Mon Sep 17 00:00:00 2001 From: Flavio Garcia Date: Wed, 12 Feb 2025 23:21:28 -0500 Subject: [PATCH 31/35] feat(crypto): add functions necessary to generate the ari data Add generate_ari_data, get_certificate_aki and get_certificate_serial functions to the project. Refs: #121 --- automatoes/crypto.py | 25 +++++++++++++++++---- tests/ari_test.py | 53 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 74 insertions(+), 4 deletions(-) create mode 100644 tests/ari_test.py diff --git a/automatoes/crypto.py b/automatoes/crypto.py index 3e9f8ed..27a2f64 100644 --- a/automatoes/crypto.py +++ b/automatoes/crypto.py @@ -1,6 +1,4 @@ -# -*- coding: UTF-8 -*- -# -# Copyright 2019-2023 Flávio Gonçalves Garcia +# Copyright 2019-2025 Flavio Garcia # Copyright 2016-2017 Veeti Paananen under MIT License # # Licensed under the Apache License, Version 2.0 (the "License"); @@ -28,7 +26,7 @@ with warnings.catch_warnings(): warnings.simplefilter("ignore") from cryptography import x509 -from cryptography.x509 import NameOID, DNSName, SubjectAlternativeName +from cryptography.x509 import NameOID, DNSName from cryptography.hazmat.backends import default_backend from cryptography.hazmat.primitives.asymmetric import padding from cryptography.hazmat.primitives.asymmetric.rsa import ( @@ -90,6 +88,13 @@ def certbot_key_data_to_int(key_data: dict) -> dict: return key_data_int +def generate_ari_data(cert): + aki_b64 = base64.urlsafe_b64encode(get_certificate_aki(cert).encode()) + serial_b64 = base64.urlsafe_b64encode( + get_certificate_serial(cert).encode()) + return f"{aki_b64}.{serial_b64}" + + def generate_header(account_key): """ Creates a new request header for the specified account key. @@ -234,6 +239,18 @@ def get_issuer_certificate_domain_name(cert): return cn.value +def get_certificate_aki(cert): + for ext in cert.extensions: + if isinstance(ext.value, x509.AuthorityKeyIdentifier): + hex = ext.value.key_identifier.hex() + return ":".join(hex[i:i+2] for i in range(0, len(hex), 2)) + + +def get_certificate_serial(cert): + hex = format(cert.serial_number, "x") + return ":".join(hex[i:i+2] for i in range(0, len(hex), 2)) + + def get_certificate_domain_name(cert): for ext in cert.extensions: if isinstance(ext.value, x509.SubjectAlternativeName): diff --git a/tests/ari_test.py b/tests/ari_test.py new file mode 100644 index 0000000..d9968ad --- /dev/null +++ b/tests/ari_test.py @@ -0,0 +1,53 @@ +# Copyright 2019-2025 Flavio Garcia +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from . import FIXTURES_ROOT +from automatoes.crypto import (generate_ari_data, + get_certificate_aki, + get_certificate_serial, + load_pem_certificate) +import base64 +from cartola import fs +import unittest +import os + + +class ARITestCase(unittest.TestCase): + """ Tests the crypto module from automatoes + """ + + def test_aki(self): + """ Test the strip_certificate function """ + key_directory = os.path.join(FIXTURES_ROOT, "keys", "candango.org", + "another") + + key_crt = fs.read( + os.path.join(key_directory, "another.candango.org.crt"), + True + ) + + pem_crt = load_pem_certificate(key_crt) + + aki = get_certificate_aki(pem_crt) + serial = get_certificate_serial(pem_crt) + expected_aki = ("c0:cc:03:46:b9:58:20:cc:5c:72:70:f3:e1:2e:cb:20:a6:" + "f5:68:3a") + expected_serial = ("fa:f3:97:73:26:ea:e8:44:e7:14:00:20:ae:90:60:af:" + "ba:44") + aki_b64 = base64.urlsafe_b64encode(expected_aki.encode()) + serial_b64 = base64.urlsafe_b64encode(expected_serial.encode()) + + self.assertEqual(expected_aki, aki) + self.assertEqual(expected_serial, serial) + self.assertEqual(f"{aki_b64}.{serial_b64}", generate_ari_data(pem_crt)) From 43893e17656e33e23c2ff5be53e49f3c5e52764b Mon Sep 17 00:00:00 2001 From: Flavio Garcia Date: Thu, 13 Feb 2025 00:33:34 -0500 Subject: [PATCH 32/35] refactor(model): move all namedtupples to model Refs: #131 --- automatoes/acme.py | 23 ++++++++--------------- automatoes/model.py | 11 ++++++++--- 2 files changed, 16 insertions(+), 18 deletions(-) diff --git a/automatoes/acme.py b/automatoes/acme.py index c3fca66..4ef90a2 100644 --- a/automatoes/acme.py +++ b/automatoes/acme.py @@ -1,6 +1,4 @@ -#!/usr/bin/env python -# -# Copyright 2019-2020 Flavio Garcia +# Copyright 2019-2025 Flavio Garcia # Copyright 2016-2017 Veeti Paananen under MIT License # # Licensed under the Apache License, Version 2.0 (the "License"); @@ -19,12 +17,13 @@ ACME API client. """ -from . import get_version -from .crypto import (export_certificate_for_acme, generate_header, jose_b64, - sign_request, sign_request_v2) -from .errors import AccountAlreadyExistsError, AcmeError -from .model import Order, Challenge -from collections import namedtuple +from automatoes import get_version +from automatoes.crypto import (export_certificate_for_acme, generate_header, + jose_b64, sign_request, sign_request_v2) +from automatoes.errors import AccountAlreadyExistsError, AcmeError +from automatoes.model import (Challenge, IssuanceResult, + NewAuthorizationResult, Order, + RegistrationResult) import copy import datetime import hashlib @@ -241,12 +240,6 @@ def path(self, path): return urljoin(self.url, path) -RegistrationResult = namedtuple("RegistrationResult", "contents uri terms") -NewAuthorizationResult = namedtuple("NewAuthorizationResult", "contents uri") -IssuanceResult = namedtuple("IssuanceResult", - "certificate location intermediate") - - class AcmeV2(Acme): def __init__(self, url, account, directory="directory", verify=None, diff --git a/automatoes/model.py b/automatoes/model.py index 1999623..34bd141 100644 --- a/automatoes/model.py +++ b/automatoes/model.py @@ -1,6 +1,4 @@ -#!/usr/bin/env python -# -# Copyright 2019-2022 Flávio Gonçalves Garcia +# Copyright 2019-2025 Flavio Garcia # Copyright 2016-2017 Veeti Paananen under MIT License # # Licensed under the Apache License, Version 2.0 (the "License"); @@ -20,6 +18,7 @@ from .crypto import (generate_jwk_thumbprint, load_private_key, export_private_key) +from collections import namedtuple from datetime import datetime @@ -141,3 +140,9 @@ def deserialize(data): return order except (TypeError, ValueError, AttributeError) as e: raise IOError("Invalid account structure: {}".format(e)) + + +RegistrationResult = namedtuple("RegistrationResult", "contents uri terms") +NewAuthorizationResult = namedtuple("NewAuthorizationResult", "contents uri") +IssuanceResult = namedtuple("IssuanceResult", + "certificate location intermediate") From 1638dad2057d882b70a5865938e72cae376a62a1 Mon Sep 17 00:00:00 2001 From: Flavio Garcia Date: Thu, 13 Feb 2025 00:40:45 -0500 Subject: [PATCH 33/35] build(release): deliver 0.9.13 --- automatoes/__init__.py | 4 ++-- automatoes/crypto.py | 6 +----- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/automatoes/__init__.py b/automatoes/__init__.py index bc4b4d5..abe432d 100644 --- a/automatoes/__init__.py +++ b/automatoes/__init__.py @@ -1,6 +1,6 @@ # -*- coding: UTF-8 -*- # -# Copyright 2019-2022 Flávio Gonçalves Garcia +# Copyright 2019-2025 Flavio Garcia # Copyright 2016-2017 Veeti Paananen under MIT License # # Licensed under the Apache License, Version 2.0 (the "License"); @@ -17,7 +17,7 @@ __author__ = "Flavio Garcia " -__version__ = (0, 9, 12) +__version__ = (0, 9, 13) __licence__ = "Apache License V2.0" diff --git a/automatoes/crypto.py b/automatoes/crypto.py index 27a2f64..2d8db51 100644 --- a/automatoes/crypto.py +++ b/automatoes/crypto.py @@ -21,11 +21,7 @@ import binascii import json import logging -# TODO: Remove that after python 3.5 depreciation -import warnings -with warnings.catch_warnings(): - warnings.simplefilter("ignore") - from cryptography import x509 +from cryptography import x509 from cryptography.x509 import NameOID, DNSName from cryptography.hazmat.backends import default_backend from cryptography.hazmat.primitives.asymmetric import padding From d1dca5e7073cb8990f397ea059203bb77368c546 Mon Sep 17 00:00:00 2001 From: Flavio Garcia Date: Thu, 13 Feb 2025 00:44:37 -0500 Subject: [PATCH 34/35] docs: update python version to 3.9 and newer Refs: #131 --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 998b931..ac02751 100644 --- a/README.md +++ b/README.md @@ -44,7 +44,7 @@ still bring your own keys and/or CSR's. Everybody wins. ## Installation -Python 3.6 or above is required. +Python 3.9 or above is required. ### Using your package manager From d80ae4c83e8ce70812878c613227a7c036ce591a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Viktor=20Sz=C3=A9pe?= Date: Thu, 13 Feb 2025 08:17:57 +0000 Subject: [PATCH 35/35] Fix typos MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Viktor Szépe --- README.md | 4 ++-- automatoes/cli/commands/account.py | 2 +- automatoes/cli/commands/order.py | 2 +- docs/index.rst | 2 +- .../{01_user_managment.feature => 01_user_management.feature} | 0 tests/features/steps/migrate_steps.py | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) rename tests/features/{01_user_managment.feature => 01_user_management.feature} (100%) diff --git a/README.md b/README.md index ac02751..0c58351 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ original project and to be a direct replacement from ## Why? -Bacause Let's Encrypt's point is to be automatic and seamless and ManuaLE was +Because Let's Encrypt's point is to be automatic and seamless and ManuaLE was designed to be manual. Automatoes will add automatic workflows and new features to evolve ManuaLe's @@ -199,7 +199,7 @@ this one will be deleted, and a new order will be created. > 1. /acme/cert/ is called, and we place keys like we use to do before > 1. we're done! -* If you try to issue certificates for a domain sequence and an oder is pending +* If you try to issue certificates for a domain sequence and an order is pending or invalid, automatoes will ask you to run authorize before. After authorizing a domain sequence you need run issue with the same domain diff --git a/automatoes/cli/commands/account.py b/automatoes/cli/commands/account.py index 7bbd22f..7bb5352 100644 --- a/automatoes/cli/commands/account.py +++ b/automatoes/cli/commands/account.py @@ -21,7 +21,7 @@ @taskio.group(name="account", short_help="Group with commands related to " - "account managment") + "account management") @pass_context def account(ctx): pass diff --git a/automatoes/cli/commands/order.py b/automatoes/cli/commands/order.py index 3a58ed8..add6f36 100644 --- a/automatoes/cli/commands/order.py +++ b/automatoes/cli/commands/order.py @@ -19,7 +19,7 @@ @taskio.group(name="order", short_help="Group with commands related to order " - "managment") + "management") @pass_context def order(ctx): pass diff --git a/docs/index.rst b/docs/index.rst index 20ff1b9..348c6e1 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -20,7 +20,7 @@ original project and to be a direct replacement from Why? ==== -Bacause Let's Encrypt's point is to be automatic and seamless and ManuaLE was +Because Let's Encrypt's point is to be automatic and seamless and ManuaLE was designed to be manual. Automatoes will add automatic workflows and new features to evolve ManuaLe's diff --git a/tests/features/01_user_managment.feature b/tests/features/01_user_management.feature similarity index 100% rename from tests/features/01_user_managment.feature rename to tests/features/01_user_management.feature diff --git a/tests/features/steps/migrate_steps.py b/tests/features/steps/migrate_steps.py index 537763b..1eb06f9 100644 --- a/tests/features/steps/migrate_steps.py +++ b/tests/features/steps/migrate_steps.py @@ -28,7 +28,7 @@ def key_int_to_data(value: int) -> str: - """ This is the invertion of what happens inside + """ This is the inversion of what happens inside automatoes.crypto.certbot_key_data_to_int """ hex_value = hex(value).replace("0x", "")