manager = $manager; $this->enabled = $enabled && $manager !== null; $this->legacySecret = $legacySecret; $this->legacyExpiry = $legacyExpiry; } /** * @return bool True when tokens will actually be issued and checked. */ public function isEnabled() : bool { return $this->enabled; } /** * Issue a token for the current session. * * Symfony returns a freshly randomised encoding of one stored secret on * every call, so successive calls return different strings that all * validate. That is deliberate BREACH mitigation. * * @return string The token, or an empty string when the guard is disabled. */ public function token() : string { if (!$this->enabled || $this->manager === null) { return ''; } return $this->manager->getToken(self::INTENTION_GLOBAL)->getValue(); } /** * @param string $value The submitted token. * * @return bool True only when the token is valid for this session. */ public function validate(string $value) : bool { if (!$this->enabled || $this->manager === null || $value === '') { return false; } if ($this->manager->isTokenValid(new CsrfToken(self::INTENTION_GLOBAL, $value))) { return true; } return $this->validateLegacyHmac($value); } /** * @param string $url URL of the XHR-patching script to inject. */ public function setScriptUrl(string $url) : void { $this->scriptUrl = $url; } /** * Supply a CSP nonce for the scripts this class injects. * * develop currently sends 'unsafe-inline', so this is unused today. 1.2.x * has already moved to nonce-based CSP; when develop follows, the injected * scripts would silently stop running and take every AJAX call with them. * * @param string $nonce The per-request nonce, or an empty string for none. */ public function setNonce(string $nonce) : void { $this->nonce = $nonce; } /** * Inject the CSRF token into POST forms and the XHR shim into the page. * * The form pattern is carried over from csrf-magic unchanged. It is * deliberately not widened: every POST is validated, decorated or not, so * a form this pattern misses already fails visibly rather than silently. * * The handler may be called repeatedly for a chunked response, so the * "have we seen enabled) { return $buffer; } if (!$this->isHtml) { $this->isHtml = (stripos($buffer, 'isHtml) { return $buffer; } $rawToken = $this->token(); $token = htmlspecialchars($rawToken, ENT_QUOTES, 'UTF-8'); $name = self::INPUT_NAME; $input = ""; $buffer = preg_replace('#(