turnstile

Drupal paywall plugin
Log | Files | Refs | README | LICENSE

commit cc3ed8cc3c3adaa4164faa6e99192ec2311676d5
parent 1196fd18dc60aac0755f773d4214e8f60587d3b5
Author: Christian Grothoff <christian@grothoff.org>
Date:   Sun,  3 May 2026 09:56:23 +0200

add merchant backend protocol version compatibility check

Diffstat:
MREADME.md | 2+-
Msrc/TalerMerchantApiService.php | 71++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
2 files changed, 71 insertions(+), 2 deletions(-)

diff --git a/README.md b/README.md @@ -179,7 +179,7 @@ taler_turnstile/ - Drupal 9 or 10 - PHP 8.1 or higher (the module uses native enums) -- A GNU Taler merchant backend supporting the v25 (or newer) +- A GNU Taler merchant backend supporting the v29 (or newer) `paivana` template type and the public `/sessions/$SESSION_ID` endpoint - The Drupal `path_alias` module (used by the confirmation endpoint diff --git a/src/TalerMerchantApiService.php b/src/TalerMerchantApiService.php @@ -51,6 +51,15 @@ class TalerMerchantApiService { const CACHE_BACKEND_DATA_SECONDS = 60; /** + * Merchant backend protocol version (libtool "current") required by + * this module. The backend's /config "version" string is libtool-style + * "CURRENT:REVISION:AGE": the backend supports interfaces in the range + * [CURRENT-AGE, CURRENT], so we require this number to fall in that + * range. + */ + const REQUIRED_PROTOCOL_VERSION = 29; + + /** * The HTTP client factory. * * @var \Drupal\Core\Http\ClientFactory @@ -111,6 +120,7 @@ class TalerMerchantApiService { * Backend URL to check, may include '/instances/$ID' path * @return bool * TRUE if this is a valid backend URL for a Taler backend + * that speaks a protocol compatible with this module */ public function checkConfig(string $backend_url) { $base_url = $this->getBaseURL($backend_url); @@ -128,7 +138,14 @@ class TalerMerchantApiService { return FALSE; } $body = json_decode($response->getBody(), TRUE); - return isset($body['name']) && $body['name'] === 'taler-merchant'; + if (!isset($body['name']) || $body['name'] !== 'taler-merchant') { + return FALSE; + } + if (!isset($body['version']) || !is_string($body['version'])) { + $this->logger->error('Taler merchant backend /config response is missing the "version" field; cannot verify protocol compatibility.'); + return FALSE; + } + return $this->checkVersion($body['version']); } catch (\Exception $e) { return FALSE; } @@ -136,6 +153,49 @@ class TalerMerchantApiService { /** + * Verify that a libtool-style "CURRENT:REVISION:AGE" version string + * advertises support for self::REQUIRED_PROTOCOL_VERSION. The backend + * supports interfaces in [CURRENT-AGE, CURRENT]; we require the + * required version to lie within that range. Logs an error when it + * does not. + * + * @param string $version + * The "version" field from the backend's /config response. + * @return bool + * TRUE iff the backend speaks a compatible protocol version. + */ + private function checkVersion(string $version): bool { + $parts = explode(':', $version); + if (count($parts) !== 3 + || !ctype_digit($parts[0]) + || !ctype_digit($parts[1]) + || !ctype_digit($parts[2])) { + $this->logger->error('Taler merchant backend reported malformed version "@version" (expected libtool-style CURRENT:REVISION:AGE).', [ + '@version' => $version, + ]); + return FALSE; + } + $current = (int) $parts[0]; + $age = (int) $parts[2]; + $required = self::REQUIRED_PROTOCOL_VERSION; + if ($current < $required) { + $this->logger->error('Taler merchant backend protocol version "@version is too old; this module requires protocol v@required or newer.', [ + '@version' => $version, + '@required' => $required, + ]); + return FALSE; + } + if ($current - $age > $required) { + $this->logger->warning('Taler merchant backend protocol version "@version" MAY no longer support v@required required by this module. Proceed with caution.', [ + '@version' => $version, + '@required' => $required, + ]); + return TRUE; + } + return TRUE; + } + + /** * Checks if the given backend URL points to a Taler merchant backend. * * @param string $backend_url @@ -326,6 +386,15 @@ class TalerMerchantApiService { return []; } + if (!isset($backend_config['version']) || !is_string($backend_config['version'])) { + $this->logger->error('Taler merchant backend /config response is missing the "version" field; cannot obtain currency list.'); + return []; + } + if (!$this->checkVersion($backend_config['version'])) { + // checkVersion() already logged the specific reason. + return []; + } + if (! isset($backend_config['currencies'])) { $this->logger->error('Backend returned malformed response for /config');