Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
8 / 8
100.00% covered (success)
100.00%
2 / 2
CRAP
n/a
0 / 0
session_pin
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
session_pin_secret
100.00% covered (success)
100.00%
7 / 7
100.00% covered (success)
100.00%
1 / 1
8
1<?php
2
3declare(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 */
24function 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 */
44function 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}