Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
| Total | |
100.00% |
8 / 8 |
|
100.00% |
2 / 2 |
CRAP | n/a |
0 / 0 |
|
| session_pin | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
| session_pin_secret | |
100.00% |
7 / 7 |
|
100.00% |
1 / 1 |
8 | |||
| 1 | <?php |
| 2 | |
| 3 | declare(strict_types=1); |
| 4 | |
| 5 | /** |
| 6 | * @file |
| 7 | * Shared per-session PIN derivation for TicketBAI actions. |
| 8 | * Required by both Derived.php (issues the PIN to the client) and |
| 9 | * Authorize.php (wraps the private key with a key derived from the same |
| 10 | * PIN), so they must always agree on the exact same value for a given |
| 11 | * session. Keeping a single implementation removes the risk of the two |
| 12 | * action files drifting apart. |
| 13 | */ |
| 14 | |
| 15 | /** |
| 16 | * Derive a per-session PIN from a server-only secret and the caller's session token. |
| 17 | * The secret (BUILD_DERIVED_SECRET) never leaves the server; only this derived value |
| 18 | * is sent to the client, and it changes automatically whenever the session changes. |
| 19 | * |
| 20 | * @param string $secret Server-only HMAC secret. |
| 21 | * @param string $session Session token already validated by the caller. |
| 22 | * @return string Hex-encoded HMAC-SHA256 digest used as PBKDF2 input. |
| 23 | */ |
| 24 | function session_pin(string $secret, string $session): string |
| 25 | { |
| 26 | return hash_hmac('sha256', $session, $secret); |
| 27 | } |
| 28 | |
| 29 | /** |
| 30 | * Resolve the server-only HMAC secret (BUILD_DERIVED_SECRET) with a single, fixed |
| 31 | * precedence. Derived.php and Authorize.php must resolve this exact value the same |
| 32 | * way for the same environment: a divergent precedence between the two files (e.g. |
| 33 | * one preferring $_ENV, the other getenv()) can silently split the PIN each derives |
| 34 | * for the same session if the two env sources ever disagree. |
| 35 | * |
| 36 | * If getenv() and $_ENV disagree on a non-empty value, that disagreement itself means |
| 37 | * the deployment is inconsistent (e.g. Apache SetEnv vs. a .env loader populating only |
| 38 | * one of the two sources) and is logged instead of being resolved silently: it is |
| 39 | * exactly the kind of drift this function exists to prevent, just one layer up. |
| 40 | * |
| 41 | * @param \Psr\Log\LoggerInterface $logger Logger used to report source disagreement. |
| 42 | * @return string Configured secret, or '' if unset in both getenv() and $_ENV. |
| 43 | */ |
| 44 | function session_pin_secret(\Psr\Log\LoggerInterface $logger): string |
| 45 | { |
| 46 | $envValue = getenv('BUILD_DERIVED_SECRET'); |
| 47 | $envValue = (is_string($envValue) && $envValue !== '') ? $envValue : null; |
| 48 | |
| 49 | $superglobalValue = $_ENV['BUILD_DERIVED_SECRET'] ?? null; |
| 50 | $superglobalValue = (is_string($superglobalValue) && $superglobalValue !== '') ? $superglobalValue : null; |
| 51 | |
| 52 | if ($envValue !== null && $superglobalValue !== null && $envValue !== $superglobalValue) { |
| 53 | $logger->error('BUILD_DERIVED_SECRET differs between getenv() and $_ENV; using the getenv() value.'); |
| 54 | } |
| 55 | |
| 56 | return $envValue ?? $superglobalValue ?? ''; |
| 57 | } |