From db67b70b46516bd0f72dba7f939bdefe3884a747 Mon Sep 17 00:00:00 2001 From: "Jens W. Klein" Date: Fri, 6 Dec 2024 15:01:55 +0100 Subject: [PATCH] fetch Googles root signing public keys on settings --- src/edutap/wallet_google/models/callback.py | 18 +++++++++++ src/edutap/wallet_google/settings.py | 34 +++++++++++++++++++++ tests/test_handler_validate.py | 4 +++ 3 files changed, 56 insertions(+) diff --git a/src/edutap/wallet_google/models/callback.py b/src/edutap/wallet_google/models/callback.py index 87f50e5..d1aab7b 100644 --- a/src/edutap/wallet_google/models/callback.py +++ b/src/edutap/wallet_google/models/callback.py @@ -35,3 +35,21 @@ class CallbackData(GoogleWalletModel): signedMessage: ( SignedMessage | str ) # google sends this as a string, but we want to parse it as a SignedMessage + + +class RootSigningPublicKey(GoogleWalletModel): + """ + see https://developers.google.com/pay/api/android/guides/resources/payment-data-cryptography#root-signing-keys + """ + + keyValue: str + protocolVersion: str + keyExpiration: str | None = None + + +class RootSigningPublicKeys(GoogleWalletModel): + """ + see https://developers.google.com/pay/api/android/guides/resources/payment-data-cryptography#root-signing-keys + """ + + keys: list[RootSigningPublicKey] diff --git a/src/edutap/wallet_google/settings.py b/src/edutap/wallet_google/settings.py index c029084..8730650 100644 --- a/src/edutap/wallet_google/settings.py +++ b/src/edutap/wallet_google/settings.py @@ -1,9 +1,13 @@ +from .models.callback import RootSigningPublicKeys from pathlib import Path from pydantic import EmailStr from pydantic import Field from pydantic import HttpUrl from pydantic_settings import BaseSettings from pydantic_settings import SettingsConfigDict +from typing import Literal + +import requests ENV_PREFIX = "EDUTAP_WALLET_GOOGLE_" @@ -11,6 +15,17 @@ BASE_URL = "https://walletobjects.googleapis.com/walletobjects/v1" SAVE_URL = "https://pay.google.com/gp/v/save" SCOPE = "https://www.googleapis.com/auth/wallet_object.issuer" +GOOGLE_ROOT_SIGNING_PUBLIC_KEYS_URL = { + # see https://developers.google.com/pay/api/android/guides/resources/payment-data-cryptography#root-signing-keys + "testing": { + "url": "https://payments.developers.google.com/paymentmethodtoken/test/keys.json", + "value": None, + }, + "production": { + "url": "https://payments.developers.google.com/paymentmethodtoken/keys.json", + "value": None, + }, +} class GoogleWalletSettings(BaseSettings): @@ -41,3 +56,22 @@ class GoogleWalletSettings(BaseSettings): callback_url: HttpUrl | None = None callback_update_url: HttpUrl | None = None + + environment: Literal["production", "testing"] = "testing" + + google_root_signing_public_keys: RootSigningPublicKeys | None = None + + def __init__(self): + super().__init__() + if GOOGLE_ROOT_SIGNING_PUBLIC_KEYS_URL[self.environment]["value"] is None: + resp = requests.get( + GOOGLE_ROOT_SIGNING_PUBLIC_KEYS_URL[self.environment]["url"] + ) + resp.raise_for_status() + self.google_root_signing_public_keys = ( + RootSigningPublicKeys.model_validate_json(resp.text) + ) + else: + self.google_root_signing_public_keys = GOOGLE_ROOT_SIGNING_PUBLIC_KEYS_URL[ + self.environment + ]["value"] diff --git a/tests/test_handler_validate.py b/tests/test_handler_validate.py index 5b41539..7ed55f0 100644 --- a/tests/test_handler_validate.py +++ b/tests/test_handler_validate.py @@ -1 +1,5 @@ from edutap.wallet_google.handlers.validate import verify_signature + + +def test_hndler_validate_valid(): + assert verify_signature("data") == True