From 6d6935549997ea39cf5fa534c75456409c175482 Mon Sep 17 00:00:00 2001 From: Matt Leon Date: Sat, 28 Oct 2023 23:15:36 -0400 Subject: [PATCH] python-matter-server: link PAA certificates locally python-matter-server redownloads these certs on every startup and device commissioning. The development certificates used by default do not seem to change frequently (see https://github.com/project-chip/connectedhomeip/commits/v1.2.0.1/credentials/development/paa-root-certs), so we should be able to make the derivation pure by simply linking to the git repo directly. --- .../python-matter-server/default.nix | 32 +++++ .../link-paa-root-certs.patch | 126 ++++++++++++++++++ 2 files changed, 158 insertions(+) create mode 100644 pkgs/development/python-modules/python-matter-server/link-paa-root-certs.patch diff --git a/pkgs/development/python-modules/python-matter-server/default.nix b/pkgs/development/python-modules/python-matter-server/default.nix index 570ee23fcbf4..751880e45546 100644 --- a/pkgs/development/python-modules/python-matter-server/default.nix +++ b/pkgs/development/python-modules/python-matter-server/default.nix @@ -2,6 +2,8 @@ , buildPythonPackage , fetchFromGitHub , pythonOlder +, stdenvNoCC +, substituteAll # build , setuptools @@ -27,6 +29,29 @@ , pytestCheckHook }: +let + paaCerts = stdenvNoCC.mkDerivation rec { + pname = "matter-server-paa-certificates"; + version = "1.2.0.1"; + + src = fetchFromGitHub { + owner = "project-chip"; + repo = "connectedhomeip"; + rev = "refs/tags/v${version}"; + hash = "sha256-p3P0n5oKRasYz386K2bhN3QVfN6oFndFIUWLEUWB0ss="; + }; + + installPhase = '' + runHook preInstall + + mkdir -p $out + cp $src/credentials/development/paa-root-certs/* $out/ + + runHook postInstall + ''; + }; +in + buildPythonPackage rec { pname = "python-matter-server"; version = "5.5.3"; @@ -41,6 +66,13 @@ buildPythonPackage rec { hash = "sha256-8daAABR5l8ZEX+PR4XrxRHlLllgnOVE4Q9yY/7UQXHw="; }; + patches = [ + (substituteAll { + src = ./link-paa-root-certs.patch; + paacerts = paaCerts; + }) + ]; + postPatch = '' substituteInPlace pyproject.toml \ --replace 'version = "0.0.0"' 'version = "${version}"' diff --git a/pkgs/development/python-modules/python-matter-server/link-paa-root-certs.patch b/pkgs/development/python-modules/python-matter-server/link-paa-root-certs.patch new file mode 100644 index 000000000000..a788f69144b8 --- /dev/null +++ b/pkgs/development/python-modules/python-matter-server/link-paa-root-certs.patch @@ -0,0 +1,126 @@ +diff --git a/matter_server/server/const.py b/matter_server/server/const.py +index b6cd839..f9f798f 100644 +--- a/matter_server/server/const.py ++++ b/matter_server/server/const.py +@@ -5,14 +5,4 @@ from typing import Final + # The minimum schema version (of a client) the server can support + MIN_SCHEMA_VERSION = 5 + +-# the paa-root-certs path is hardcoded in the sdk at this time +-# and always uses the development subfolder +-# regardless of anything you pass into instantiating the controller +-# revisit this once matter 1.1 is released +-PAA_ROOT_CERTS_DIR: Final[pathlib.Path] = ( +- pathlib.Path(__file__) +- .parent.resolve() +- .parent.resolve() +- .parent.resolve() +- .joinpath("credentials/development/paa-root-certs") +-) ++PAA_ROOT_CERTS_DIR: Final[pathlib.Path] = pathlib.Path("@paacerts@") +diff --git a/matter_server/server/helpers/paa_certificates.py b/matter_server/server/helpers/paa_certificates.py +index 9ac5a10..25230c1 100644 +--- a/matter_server/server/helpers/paa_certificates.py ++++ b/matter_server/server/helpers/paa_certificates.py +@@ -58,84 +58,14 @@ async def fetch_dcl_certificates( + fetch_production_certificates: bool = True, + ) -> int: + """Fetch DCL PAA Certificates.""" +- LOGGER.info("Fetching the latest PAA root certificates from DCL.") +- if not PAA_ROOT_CERTS_DIR.is_dir(): +- loop = asyncio.get_running_loop() +- await loop.run_in_executor(None, makedirs, PAA_ROOT_CERTS_DIR) +- fetch_count: int = 0 +- base_urls = set() +- # determine which url's need to be queried. +- # if we're going to fetch both prod and test, do test first +- # so any duplicates will be overwritten/preferred by the production version +- # NOTE: While Matter is in BETA we fetch the test certificates by default +- if fetch_test_certificates: +- base_urls.add(TEST_URL) +- if fetch_production_certificates: +- base_urls.add(PRODUCTION_URL) + +- try: +- async with ClientSession(raise_for_status=True) as http_session: +- for url_base in base_urls: +- # fetch the paa certificates list +- async with http_session.get( +- f"{url_base}/dcl/pki/root-certificates" +- ) as response: +- result = await response.json() +- paa_list = result["approvedRootCertificates"]["certs"] +- # grab each certificate +- for paa in paa_list: +- # do not fetch a certificate if we already fetched it +- if paa["subjectKeyId"] in LAST_CERT_IDS: +- continue +- async with http_session.get( +- f"{url_base}/dcl/pki/certificates/{paa['subject']}/{paa['subjectKeyId']}" +- ) as response: +- result = await response.json() +- +- certificate_data: dict = result["approvedCertificates"]["certs"][0] +- certificate: str = certificate_data["pemCert"] +- subject = certificate_data["subjectAsText"] +- certificate = certificate.rstrip("\n") +- +- await write_paa_root_cert( +- certificate, +- subject, +- ) +- LAST_CERT_IDS.add(paa["subjectKeyId"]) +- fetch_count += 1 +- except ClientError as err: +- LOGGER.warning( +- "Fetching latest certificates failed: error %s", err, exc_info=err +- ) +- else: +- LOGGER.info("Fetched %s PAA root certificates from DCL.", fetch_count) +- +- return fetch_count ++ return 0 + + + async def fetch_git_certificates() -> int: + """Fetch Git PAA Certificates.""" +- fetch_count = 0 +- LOGGER.info("Fetching the latest PAA root certificates from Git.") +- try: +- async with ClientSession(raise_for_status=True) as http_session: +- for cert in GIT_CERTS: +- if cert in LAST_CERT_IDS: +- continue + +- async with http_session.get(f"{GIT_URL}/{cert}.pem") as response: +- certificate = await response.text() +- await write_paa_root_cert(certificate, cert) +- LAST_CERT_IDS.add(cert) +- fetch_count += 1 +- except ClientError as err: +- LOGGER.warning( +- "Fetching latest certificates failed: error %s", err, exc_info=err +- ) +- +- LOGGER.info("Fetched %s PAA root certificates from Git.", fetch_count) +- +- return fetch_count ++ return 0 + + + async def fetch_certificates( +@@ -144,12 +74,4 @@ async def fetch_certificates( + ) -> int: + """Fetch PAA Certificates.""" + +- fetch_count = await fetch_dcl_certificates( +- fetch_test_certificates=fetch_test_certificates, +- fetch_production_certificates=fetch_production_certificates, +- ) +- +- if fetch_test_certificates: +- fetch_count += await fetch_git_certificates() +- +- return fetch_count ++ return 0 +