blob: 0a28cabf10ee5d49b29504b44a88857305bf6a1b [file] [log] [blame]
Matthias Andreas Benkard12a57352021-12-28 18:02:04 +01001<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) Fabien Potencier
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Twig\Extension;
13
14use Twig\NodeVisitor\SandboxNodeVisitor;
15use Twig\Sandbox\SecurityNotAllowedMethodError;
16use Twig\Sandbox\SecurityNotAllowedPropertyError;
17use Twig\Sandbox\SecurityPolicyInterface;
18use Twig\Source;
19use Twig\TokenParser\SandboxTokenParser;
20
21final class SandboxExtension extends AbstractExtension
22{
23 private $sandboxedGlobally;
24 private $sandboxed;
25 private $policy;
26
27 public function __construct(SecurityPolicyInterface $policy, $sandboxed = false)
28 {
29 $this->policy = $policy;
30 $this->sandboxedGlobally = $sandboxed;
31 }
32
33 public function getTokenParsers(): array
34 {
35 return [new SandboxTokenParser()];
36 }
37
38 public function getNodeVisitors(): array
39 {
40 return [new SandboxNodeVisitor()];
41 }
42
43 public function enableSandbox(): void
44 {
45 $this->sandboxed = true;
46 }
47
48 public function disableSandbox(): void
49 {
50 $this->sandboxed = false;
51 }
52
53 public function isSandboxed(): bool
54 {
55 return $this->sandboxedGlobally || $this->sandboxed;
56 }
57
58 public function isSandboxedGlobally(): bool
59 {
60 return $this->sandboxedGlobally;
61 }
62
63 public function setSecurityPolicy(SecurityPolicyInterface $policy)
64 {
65 $this->policy = $policy;
66 }
67
68 public function getSecurityPolicy(): SecurityPolicyInterface
69 {
70 return $this->policy;
71 }
72
73 public function checkSecurity($tags, $filters, $functions): void
74 {
75 if ($this->isSandboxed()) {
76 $this->policy->checkSecurity($tags, $filters, $functions);
77 }
78 }
79
80 public function checkMethodAllowed($obj, $method, int $lineno = -1, Source $source = null): void
81 {
82 if ($this->isSandboxed()) {
83 try {
84 $this->policy->checkMethodAllowed($obj, $method);
85 } catch (SecurityNotAllowedMethodError $e) {
86 $e->setSourceContext($source);
87 $e->setTemplateLine($lineno);
88
89 throw $e;
90 }
91 }
92 }
93
94 public function checkPropertyAllowed($obj, $method, int $lineno = -1, Source $source = null): void
95 {
96 if ($this->isSandboxed()) {
97 try {
98 $this->policy->checkPropertyAllowed($obj, $method);
99 } catch (SecurityNotAllowedPropertyError $e) {
100 $e->setSourceContext($source);
101 $e->setTemplateLine($lineno);
102
103 throw $e;
104 }
105 }
106 }
107
108 public function ensureToStringAllowed($obj, int $lineno = -1, Source $source = null)
109 {
110 if ($this->isSandboxed() && \is_object($obj) && method_exists($obj, '__toString')) {
111 try {
112 $this->policy->checkMethodAllowed($obj, '__toString');
113 } catch (SecurityNotAllowedMethodError $e) {
114 $e->setSourceContext($source);
115 $e->setTemplateLine($lineno);
116
117 throw $e;
118 }
119 }
120
121 return $obj;
122 }
123}