@vituum/vite-plugin-latte 0.1.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (201) hide show
  1. package/README.md +39 -0
  2. package/handler.js +9 -0
  3. package/index.js +138 -0
  4. package/index.php +173 -0
  5. package/latte/AssetFilter.php +11 -0
  6. package/latte/FetchFunction.php +28 -0
  7. package/latte/IconFilter.php +14 -0
  8. package/latte/JsonTag.php +64 -0
  9. package/latte/PlaceholderFunction.php +11 -0
  10. package/latte/RandomColorFunction.php +14 -0
  11. package/latte/TelFilter.php +22 -0
  12. package/package.json +35 -0
  13. package/vendor/autoload.php +7 -0
  14. package/vendor/bin/latte-lint +107 -0
  15. package/vendor/composer/ClassLoader.php +572 -0
  16. package/vendor/composer/InstalledVersions.php +350 -0
  17. package/vendor/composer/LICENSE +21 -0
  18. package/vendor/composer/autoload_classmap.php +183 -0
  19. package/vendor/composer/autoload_namespaces.php +9 -0
  20. package/vendor/composer/autoload_psr4.php +9 -0
  21. package/vendor/composer/autoload_real.php +57 -0
  22. package/vendor/composer/autoload_static.php +193 -0
  23. package/vendor/composer/installed.json +93 -0
  24. package/vendor/composer/installed.php +32 -0
  25. package/vendor/composer/platform_check.php +26 -0
  26. package/vendor/latte/latte/bin/latte-lint +29 -0
  27. package/vendor/latte/latte/composer.json +53 -0
  28. package/vendor/latte/latte/license.md +60 -0
  29. package/vendor/latte/latte/ncs.php +14 -0
  30. package/vendor/latte/latte/ncs.xml +9 -0
  31. package/vendor/latte/latte/readme.md +21 -0
  32. package/vendor/latte/latte/src/Bridges/Tracy/BlueScreenPanel.php +114 -0
  33. package/vendor/latte/latte/src/Bridges/Tracy/LattePanel.php +99 -0
  34. package/vendor/latte/latte/src/Bridges/Tracy/templates/LattePanel.panel.phtml +98 -0
  35. package/vendor/latte/latte/src/Bridges/Tracy/templates/LattePanel.tab.phtml +15 -0
  36. package/vendor/latte/latte/src/Latte/Compiler/Block.php +44 -0
  37. package/vendor/latte/latte/src/Latte/Compiler/Escaper.php +244 -0
  38. package/vendor/latte/latte/src/Latte/Compiler/ExpressionBuilder.php +128 -0
  39. package/vendor/latte/latte/src/Latte/Compiler/Node.php +28 -0
  40. package/vendor/latte/latte/src/Latte/Compiler/NodeHelpers.php +132 -0
  41. package/vendor/latte/latte/src/Latte/Compiler/NodeTraverser.php +77 -0
  42. package/vendor/latte/latte/src/Latte/Compiler/Nodes/AreaNode.php +17 -0
  43. package/vendor/latte/latte/src/Latte/Compiler/Nodes/AuxiliaryNode.php +27 -0
  44. package/vendor/latte/latte/src/Latte/Compiler/Nodes/FragmentNode.php +59 -0
  45. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Html/AttributeNode.php +48 -0
  46. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Html/BogusTagNode.php +46 -0
  47. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Html/CommentNode.php +39 -0
  48. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Html/ElementNode.php +129 -0
  49. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Html/QuotedValue.php +53 -0
  50. package/vendor/latte/latte/src/Latte/Compiler/Nodes/NopNode.php +21 -0
  51. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/ArgumentNode.php +45 -0
  52. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/ComplexTypeNode.php +17 -0
  53. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/Expression/ArrayAccessNode.php +41 -0
  54. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/Expression/ArrayItemNode.php +52 -0
  55. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/Expression/ArrayNode.php +94 -0
  56. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/Expression/AssignNode.php +39 -0
  57. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/Expression/AssignOpNode.php +45 -0
  58. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/Expression/BinaryOpNode.php +65 -0
  59. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/Expression/CastNode.php +43 -0
  60. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/Expression/ClassConstantFetchNode.php +42 -0
  61. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/Expression/CloneNode.php +36 -0
  62. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/Expression/ClosureNode.php +73 -0
  63. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/Expression/ClosureUseNode.php +37 -0
  64. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/Expression/ConstantFetchNode.php +37 -0
  65. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/Expression/EmptyNode.php +36 -0
  66. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/Expression/ErrorSuppressNode.php +36 -0
  67. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/Expression/FilterCallNode.php +39 -0
  68. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/Expression/FunctionCallNode.php +45 -0
  69. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/Expression/FunctionCallableNode.php +39 -0
  70. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/Expression/InRangeNode.php +42 -0
  71. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/Expression/InstanceofNode.php +40 -0
  72. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/Expression/IssetNode.php +40 -0
  73. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/Expression/MatchNode.php +49 -0
  74. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/Expression/MethodCallNode.php +50 -0
  75. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/Expression/MethodCallableNode.php +42 -0
  76. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/Expression/NewNode.php +45 -0
  77. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/Expression/NotNode.php +36 -0
  78. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/Expression/PostOpNode.php +43 -0
  79. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/Expression/PreOpNode.php +43 -0
  80. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/Expression/PropertyFetchNode.php +42 -0
  81. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/Expression/StaticCallNode.php +55 -0
  82. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/Expression/StaticCallableNode.php +47 -0
  83. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/Expression/StaticPropertyFetchNode.php +42 -0
  84. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/Expression/TernaryNode.php +50 -0
  85. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/Expression/UnaryOpNode.php +45 -0
  86. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/Expression/VariableNode.php +40 -0
  87. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/ExpressionNode.php +17 -0
  88. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/FilterNode.php +67 -0
  89. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/IdentifierNode.php +36 -0
  90. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/IntersectionTypeNode.php +39 -0
  91. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/MatchArmNode.php +45 -0
  92. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/ModifierNode.php +107 -0
  93. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/NameNode.php +89 -0
  94. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/NullableTypeNode.php +35 -0
  95. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/ParameterNode.php +54 -0
  96. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/Scalar/BooleanNode.php +30 -0
  97. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/Scalar/EncapsedStringNode.php +80 -0
  98. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/Scalar/EncapsedStringPartNode.php +30 -0
  99. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/Scalar/FloatNode.php +63 -0
  100. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/Scalar/IntegerNode.php +70 -0
  101. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/Scalar/NullNode.php +29 -0
  102. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/Scalar/StringNode.php +40 -0
  103. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/ScalarNode.php +15 -0
  104. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/SuperiorTypeNode.php +29 -0
  105. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/UnionTypeNode.php +39 -0
  106. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/VarLikeIdentifierNode.php +21 -0
  107. package/vendor/latte/latte/src/Latte/Compiler/Nodes/StatementNode.php +15 -0
  108. package/vendor/latte/latte/src/Latte/Compiler/Nodes/TemplateNode.php +34 -0
  109. package/vendor/latte/latte/src/Latte/Compiler/Nodes/TextNode.php +37 -0
  110. package/vendor/latte/latte/src/Latte/Compiler/PhpHelpers.php +227 -0
  111. package/vendor/latte/latte/src/Latte/Compiler/Position.php +43 -0
  112. package/vendor/latte/latte/src/Latte/Compiler/PrintContext.php +334 -0
  113. package/vendor/latte/latte/src/Latte/Compiler/Tag.php +117 -0
  114. package/vendor/latte/latte/src/Latte/Compiler/TagLexer.php +399 -0
  115. package/vendor/latte/latte/src/Latte/Compiler/TagParser.php +388 -0
  116. package/vendor/latte/latte/src/Latte/Compiler/TagParserData.php +580 -0
  117. package/vendor/latte/latte/src/Latte/Compiler/TemplateGenerator.php +206 -0
  118. package/vendor/latte/latte/src/Latte/Compiler/TemplateLexer.php +391 -0
  119. package/vendor/latte/latte/src/Latte/Compiler/TemplateParser.php +448 -0
  120. package/vendor/latte/latte/src/Latte/Compiler/TemplateParserHtml.php +506 -0
  121. package/vendor/latte/latte/src/Latte/Compiler/Token.php +259 -0
  122. package/vendor/latte/latte/src/Latte/Compiler/TokenStream.php +151 -0
  123. package/vendor/latte/latte/src/Latte/ContentType.php +22 -0
  124. package/vendor/latte/latte/src/Latte/Engine.php +591 -0
  125. package/vendor/latte/latte/src/Latte/Essential/Blueprint.php +160 -0
  126. package/vendor/latte/latte/src/Latte/Essential/CachingIterator.php +232 -0
  127. package/vendor/latte/latte/src/Latte/Essential/CoreExtension.php +232 -0
  128. package/vendor/latte/latte/src/Latte/Essential/Filters.php +591 -0
  129. package/vendor/latte/latte/src/Latte/Essential/Nodes/BlockNode.php +161 -0
  130. package/vendor/latte/latte/src/Latte/Essential/Nodes/CaptureNode.php +98 -0
  131. package/vendor/latte/latte/src/Latte/Essential/Nodes/ContentTypeNode.php +74 -0
  132. package/vendor/latte/latte/src/Latte/Essential/Nodes/DebugbreakNode.php +53 -0
  133. package/vendor/latte/latte/src/Latte/Essential/Nodes/DefineNode.php +134 -0
  134. package/vendor/latte/latte/src/Latte/Essential/Nodes/DoNode.php +49 -0
  135. package/vendor/latte/latte/src/Latte/Essential/Nodes/DumpNode.php +58 -0
  136. package/vendor/latte/latte/src/Latte/Essential/Nodes/EmbedNode.php +125 -0
  137. package/vendor/latte/latte/src/Latte/Essential/Nodes/ExtendsNode.php +60 -0
  138. package/vendor/latte/latte/src/Latte/Essential/Nodes/FirstLastSepNode.php +81 -0
  139. package/vendor/latte/latte/src/Latte/Essential/Nodes/ForNode.php +91 -0
  140. package/vendor/latte/latte/src/Latte/Essential/Nodes/ForeachNode.php +155 -0
  141. package/vendor/latte/latte/src/Latte/Essential/Nodes/IfChangedNode.php +141 -0
  142. package/vendor/latte/latte/src/Latte/Essential/Nodes/IfContentNode.php +82 -0
  143. package/vendor/latte/latte/src/Latte/Essential/Nodes/IfNode.php +180 -0
  144. package/vendor/latte/latte/src/Latte/Essential/Nodes/ImportNode.php +49 -0
  145. package/vendor/latte/latte/src/Latte/Essential/Nodes/IncludeBlockNode.php +140 -0
  146. package/vendor/latte/latte/src/Latte/Essential/Nodes/IncludeFileNode.php +81 -0
  147. package/vendor/latte/latte/src/Latte/Essential/Nodes/IterateWhileNode.php +94 -0
  148. package/vendor/latte/latte/src/Latte/Essential/Nodes/NAttrNode.php +105 -0
  149. package/vendor/latte/latte/src/Latte/Essential/Nodes/NClassNode.php +54 -0
  150. package/vendor/latte/latte/src/Latte/Essential/Nodes/NTagNode.php +79 -0
  151. package/vendor/latte/latte/src/Latte/Essential/Nodes/ParametersNode.php +84 -0
  152. package/vendor/latte/latte/src/Latte/Essential/Nodes/PrintNode.php +70 -0
  153. package/vendor/latte/latte/src/Latte/Essential/Nodes/RawPhpNode.php +46 -0
  154. package/vendor/latte/latte/src/Latte/Essential/Nodes/RollbackNode.php +37 -0
  155. package/vendor/latte/latte/src/Latte/Essential/Nodes/SkipNode.php +71 -0
  156. package/vendor/latte/latte/src/Latte/Essential/Nodes/SpacelessNode.php +62 -0
  157. package/vendor/latte/latte/src/Latte/Essential/Nodes/SwitchNode.php +118 -0
  158. package/vendor/latte/latte/src/Latte/Essential/Nodes/TemplatePrintNode.php +39 -0
  159. package/vendor/latte/latte/src/Latte/Essential/Nodes/TemplateTypeNode.php +38 -0
  160. package/vendor/latte/latte/src/Latte/Essential/Nodes/TraceNode.php +35 -0
  161. package/vendor/latte/latte/src/Latte/Essential/Nodes/TranslateNode.php +104 -0
  162. package/vendor/latte/latte/src/Latte/Essential/Nodes/TryNode.php +75 -0
  163. package/vendor/latte/latte/src/Latte/Essential/Nodes/VarNode.php +106 -0
  164. package/vendor/latte/latte/src/Latte/Essential/Nodes/VarPrintNode.php +40 -0
  165. package/vendor/latte/latte/src/Latte/Essential/Nodes/VarTypeNode.php +36 -0
  166. package/vendor/latte/latte/src/Latte/Essential/Nodes/WhileNode.php +81 -0
  167. package/vendor/latte/latte/src/Latte/Essential/Passes.php +115 -0
  168. package/vendor/latte/latte/src/Latte/Essential/RawPhpExtension.php +28 -0
  169. package/vendor/latte/latte/src/Latte/Essential/RollbackException.php +16 -0
  170. package/vendor/latte/latte/src/Latte/Essential/Tracer.php +117 -0
  171. package/vendor/latte/latte/src/Latte/Essential/TranslatorExtension.php +101 -0
  172. package/vendor/latte/latte/src/Latte/Extension.php +97 -0
  173. package/vendor/latte/latte/src/Latte/Helpers.php +96 -0
  174. package/vendor/latte/latte/src/Latte/Loader.php +37 -0
  175. package/vendor/latte/latte/src/Latte/Loaders/FileLoader.php +95 -0
  176. package/vendor/latte/latte/src/Latte/Loaders/StringLoader.php +76 -0
  177. package/vendor/latte/latte/src/Latte/Policy.php +24 -0
  178. package/vendor/latte/latte/src/Latte/PositionAwareException.php +50 -0
  179. package/vendor/latte/latte/src/Latte/Runtime/Block.php +24 -0
  180. package/vendor/latte/latte/src/Latte/Runtime/FilterExecutor.php +151 -0
  181. package/vendor/latte/latte/src/Latte/Runtime/FilterInfo.php +39 -0
  182. package/vendor/latte/latte/src/Latte/Runtime/Filters.php +234 -0
  183. package/vendor/latte/latte/src/Latte/Runtime/Html.php +35 -0
  184. package/vendor/latte/latte/src/Latte/Runtime/HtmlStringable.php +17 -0
  185. package/vendor/latte/latte/src/Latte/Runtime/Template.php +381 -0
  186. package/vendor/latte/latte/src/Latte/Sandbox/Nodes/FunctionCallNode.php +30 -0
  187. package/vendor/latte/latte/src/Latte/Sandbox/Nodes/FunctionCallableNode.php +29 -0
  188. package/vendor/latte/latte/src/Latte/Sandbox/Nodes/MethodCallNode.php +32 -0
  189. package/vendor/latte/latte/src/Latte/Sandbox/Nodes/MethodCallableNode.php +30 -0
  190. package/vendor/latte/latte/src/Latte/Sandbox/Nodes/PropertyFetchNode.php +32 -0
  191. package/vendor/latte/latte/src/Latte/Sandbox/Nodes/SandboxNode.php +73 -0
  192. package/vendor/latte/latte/src/Latte/Sandbox/Nodes/StaticCallNode.php +31 -0
  193. package/vendor/latte/latte/src/Latte/Sandbox/Nodes/StaticCallableNode.php +30 -0
  194. package/vendor/latte/latte/src/Latte/Sandbox/Nodes/StaticPropertyFetchNode.php +32 -0
  195. package/vendor/latte/latte/src/Latte/Sandbox/RuntimeChecker.php +116 -0
  196. package/vendor/latte/latte/src/Latte/Sandbox/SandboxExtension.php +132 -0
  197. package/vendor/latte/latte/src/Latte/Sandbox/SecurityPolicy.php +185 -0
  198. package/vendor/latte/latte/src/Latte/Strict.php +101 -0
  199. package/vendor/latte/latte/src/Latte/attributes.php +24 -0
  200. package/vendor/latte/latte/src/Latte/exceptions.php +69 -0
  201. package/vendor/latte/latte/src/Tools/Linter.php +175 -0
@@ -0,0 +1,116 @@
1
+ <?php
2
+
3
+ /**
4
+ * This file is part of the Latte (https://latte.nette.org)
5
+ * Copyright (c) 2008 David Grudl (https://davidgrudl.com)
6
+ */
7
+
8
+ declare(strict_types=1);
9
+
10
+ namespace Latte\Sandbox;
11
+
12
+ use Latte;
13
+
14
+
15
+ /** @internal */
16
+ final class RuntimeChecker
17
+ {
18
+ use Latte\Strict;
19
+
20
+ public function __construct(
21
+ public Latte\Policy $policy,
22
+ ) {
23
+ }
24
+
25
+
26
+ public function call(mixed $callable, array $args): mixed
27
+ {
28
+ self::checkCallable($callable);
29
+ self::args(...$args);
30
+ return $callable(...$args);
31
+ }
32
+
33
+
34
+ public function callMethod(mixed $object, mixed $method, array $args, bool $nullsafe = false): mixed
35
+ {
36
+ if ($object === null) {
37
+ if ($nullsafe) {
38
+ throw new \Error("Call to a member function $method() on null");
39
+ }
40
+ return null;
41
+
42
+ } elseif (!is_object($object) || !is_string($method)) {
43
+ throw new Latte\SecurityViolationException('Invalid callable.');
44
+
45
+ } elseif (!$this->policy->isMethodAllowed($class = $object::class, $method)) {
46
+ throw new Latte\SecurityViolationException("Calling $class::$method() is not allowed.");
47
+ }
48
+
49
+ self::args(...$args);
50
+ return [$object, $method](...$args);
51
+ }
52
+
53
+
54
+ public function closure(mixed $callable): \Closure
55
+ {
56
+ self::checkCallable($callable);
57
+ return \Closure::fromCallable($callable);
58
+ }
59
+
60
+
61
+ public function args(...$args): array
62
+ {
63
+ foreach ($args as $arg) {
64
+ if (
65
+ is_array($arg)
66
+ && is_callable($arg, true, $text)
67
+ && !$this->policy->isMethodAllowed(is_object($arg[0]) ? $arg[0]::class : $arg[0], $arg[1])
68
+ ) {
69
+ throw new Latte\SecurityViolationException("Calling $text() is not allowed.");
70
+ }
71
+ }
72
+
73
+ return $args;
74
+ }
75
+
76
+
77
+ public function prop(mixed $object, mixed $property): mixed
78
+ {
79
+ $class = is_object($object) ? $object::class : $object;
80
+ if (is_string($class) && !$this->policy->isPropertyAllowed($class, (string) $property)) {
81
+ throw new Latte\SecurityViolationException("Access to '$property' property on a $class object is not allowed.");
82
+ }
83
+
84
+ return $object;
85
+ }
86
+
87
+
88
+ private function checkCallable(mixed $callable): void
89
+ {
90
+ if (!is_callable($callable)) {
91
+ throw new Latte\SecurityViolationException('Invalid callable.');
92
+
93
+ } elseif (is_string($callable)) {
94
+ $parts = explode('::', $callable);
95
+ $allowed = count($parts) === 1
96
+ ? $this->policy->isFunctionAllowed($parts[0])
97
+ : $this->policy->isMethodAllowed(...$parts);
98
+
99
+ } elseif (is_array($callable)) {
100
+ $allowed = $this->policy->isMethodAllowed(is_object($callable[0]) ? $callable[0]::class : $callable[0], $callable[1]);
101
+
102
+ } elseif (is_object($callable)) {
103
+ $allowed = $callable instanceof \Closure
104
+ ? true
105
+ : $this->policy->isMethodAllowed($callable::class, '__invoke');
106
+
107
+ } else {
108
+ $allowed = false;
109
+ }
110
+
111
+ if (!$allowed) {
112
+ is_callable($callable, false, $text);
113
+ throw new Latte\SecurityViolationException("Calling $text() is not allowed.");
114
+ }
115
+ }
116
+ }
@@ -0,0 +1,132 @@
1
+ <?php
2
+
3
+ /**
4
+ * This file is part of the Latte (https://latte.nette.org)
5
+ * Copyright (c) 2008 David Grudl (https://davidgrudl.com)
6
+ */
7
+
8
+ declare(strict_types=1);
9
+
10
+ namespace Latte\Sandbox;
11
+
12
+ use Latte;
13
+ use Latte\Compiler\ExpressionBuilder;
14
+ use Latte\Compiler\Node;
15
+ use Latte\Compiler\Nodes\Php;
16
+ use Latte\Compiler\Nodes\Php\Expression;
17
+ use Latte\Compiler\Nodes\TemplateNode;
18
+ use Latte\Compiler\NodeTraverser;
19
+ use Latte\Engine;
20
+ use Latte\SecurityViolationException;
21
+
22
+
23
+ /**
24
+ * Security protection for the sandbox.
25
+ */
26
+ final class SandboxExtension extends Latte\Extension
27
+ {
28
+ use Latte\Strict;
29
+
30
+ private ?Latte\Policy $policy;
31
+
32
+
33
+ public function beforeCompile(Engine $engine): void
34
+ {
35
+ $this->policy = $engine->getPolicy(effective: true);
36
+ }
37
+
38
+
39
+ public function getTags(): array
40
+ {
41
+ return [
42
+ 'sandbox' => [Nodes\SandboxNode::class, 'create'],
43
+ ];
44
+ }
45
+
46
+
47
+ public function getPasses(): array
48
+ {
49
+ return $this->policy
50
+ ? ['sandbox' => self::order([$this, 'processPass'], before: '*')]
51
+ : [];
52
+ }
53
+
54
+
55
+ public function beforeRender(Engine $engine): void
56
+ {
57
+ if ($policy = $engine->getPolicy()) {
58
+ $engine->addProvider('sandbox', new RuntimeChecker($policy));
59
+ }
60
+ }
61
+
62
+
63
+ public function getCacheKey(Engine $engine): mixed
64
+ {
65
+ return (bool) $engine->getPolicy(effective: true);
66
+ }
67
+
68
+
69
+ public function processPass(TemplateNode $node): void
70
+ {
71
+ (new NodeTraverser)->traverse($node, leave: \Closure::fromCallable([$this, 'sandboxVisitor']));
72
+ }
73
+
74
+
75
+ private function sandboxVisitor(Node $node): Node
76
+ {
77
+ if ($node instanceof Expression\VariableNode) {
78
+ if ($node->name === 'this') {
79
+ throw new SecurityViolationException("Forbidden variable \${$node->name}.", $node->position);
80
+ } elseif (!is_string($node->name)) {
81
+ throw new SecurityViolationException('Forbidden variable variables.', $node->position);
82
+ }
83
+
84
+ return $node;
85
+
86
+ } elseif ($node instanceof Expression\NewNode) {
87
+ throw new SecurityViolationException("Forbidden keyword 'new'", $node->position);
88
+
89
+ } elseif ($node instanceof Expression\FunctionCallNode
90
+ && $node->name instanceof Php\NameNode
91
+ ) {
92
+ if (!$this->policy->isFunctionAllowed((string) $node->name)) {
93
+ throw new SecurityViolationException("Function $node->name() is not allowed.", $node->position);
94
+
95
+ } elseif ($node->args) {
96
+ $arg = ExpressionBuilder::variable('$this')->property('global')->property('sandbox')->method('args', $node->args)
97
+ ->build();
98
+ $node->args = [new Php\ArgumentNode($arg, unpack: true)];
99
+ }
100
+
101
+ return $node;
102
+
103
+ } elseif ($node instanceof Php\FilterNode) {
104
+ $name = (string) $node->name;
105
+ if (!$this->policy->isFilterAllowed($name)) {
106
+ throw new SecurityViolationException("Filter |$name is not allowed.", $node->position);
107
+
108
+ } elseif ($node->args) {
109
+ $arg = ExpressionBuilder::variable('$this')->property('global')->property('sandbox')->method('args', $node->args)
110
+ ->build();
111
+ $node->args = [new Php\ArgumentNode($arg, unpack: true)];
112
+ }
113
+
114
+ return $node;
115
+
116
+ } elseif ($node instanceof Expression\PropertyFetchNode
117
+ || $node instanceof Expression\StaticPropertyFetchNode
118
+ || $node instanceof Expression\FunctionCallNode
119
+ || $node instanceof Expression\FunctionCallableNode
120
+ || $node instanceof Expression\MethodCallNode
121
+ || $node instanceof Expression\MethodCallableNode
122
+ || $node instanceof Expression\StaticCallNode
123
+ || $node instanceof Expression\StaticCallableNode
124
+ ) {
125
+ $class = namespace\Nodes::class . strrchr($node::class, '\\');
126
+ return new $class($node);
127
+
128
+ } else {
129
+ return $node;
130
+ }
131
+ }
132
+ }
@@ -0,0 +1,185 @@
1
+ <?php
2
+
3
+ /**
4
+ * This file is part of the Latte (https://latte.nette.org)
5
+ * Copyright (c) 2008 David Grudl (https://davidgrudl.com)
6
+ */
7
+
8
+ declare(strict_types=1);
9
+
10
+ namespace Latte\Sandbox;
11
+
12
+ use Latte;
13
+
14
+
15
+ /**
16
+ * Default-deny policy.
17
+ */
18
+ class SecurityPolicy implements Latte\Policy
19
+ {
20
+ use Latte\Strict;
21
+
22
+ public const All = ['*'];
23
+ public const ALL = self::All;
24
+
25
+ /** @var string[] */
26
+ private array $tags = [];
27
+
28
+ /** @var string[] */
29
+ private array $filters = [];
30
+
31
+ /** @var string[] */
32
+ private array $functions = [];
33
+
34
+ /** @var string[][] */
35
+ private array $methods = [];
36
+
37
+ /** @var string[][] */
38
+ private array $properties = [];
39
+
40
+ /** @var array<string, array<string, bool>> */
41
+ private array $methodCache = [];
42
+
43
+ /** @var array<string, array<string, bool>> */
44
+ private array $propertyCache = [];
45
+
46
+
47
+ public static function createSafePolicy(): self
48
+ {
49
+ $policy = new self;
50
+
51
+ // does not include: contentType, debugbreak, dump, extends, import, include, layout,
52
+ // php (but 'do' is allowed), sandbox, snippet, snippetArea, templatePrint, varPrint, embed
53
+ $policy->allowTags([
54
+ '_', '=', 'attr', 'block', 'breakIf', 'capture', 'case', 'class', 'continueIf', 'default',
55
+ 'define', 'do', 'else', 'elseif', 'elseifset', 'first', 'for', 'foreach', 'if', 'ifchanged',
56
+ 'ifcontent', 'iterateWhile', 'ifset', 'l', 'last', 'r', 'rollback', 'sep', 'skipIf', 'spaceless',
57
+ 'switch', 'templateType', 'translate', 'try', 'var', 'varType', 'while',
58
+ ]);
59
+
60
+ // does not include: dataStream, noEscape, noCheck
61
+ $policy->allowFilters([
62
+ 'batch', 'breaklines', 'breakLines', 'bytes', 'capitalize', 'ceil', 'clamp', 'date', 'escapeCss', 'escapeHtml',
63
+ 'escapeHtmlComment', 'escapeICal', 'escapeJs', 'escapeUrl', 'escapeXml', 'explode', 'first',
64
+ 'firstUpper', 'floor', 'checkUrl', 'implode', 'indent', 'join', 'last', 'length', 'lower',
65
+ 'number', 'padLeft', 'padRight', 'query', 'random', 'repeat', 'replace', 'replaceRe', 'reverse',
66
+ 'round', 'slice', 'sort', 'spaceless', 'split', 'strip', 'striphtml', 'stripHtml', 'striptags', 'stripTags', 'substr',
67
+ 'trim', 'truncate', 'upper', 'webalize',
68
+ ]);
69
+
70
+ $policy->allowFunctions(['clamp', 'divisibleBy', 'even', 'first', 'last', 'odd', 'slice']);
71
+
72
+ $policy->allowMethods(Latte\Essential\CachingIterator::class, self::All);
73
+ $policy->allowProperties(Latte\Essential\CachingIterator::class, self::All);
74
+
75
+ return $policy;
76
+ }
77
+
78
+
79
+ /**
80
+ * @param string[] $tags
81
+ */
82
+ public function allowTags(array $tags): self
83
+ {
84
+ $this->tags += array_flip(array_map('strtolower', $tags));
85
+ return $this;
86
+ }
87
+
88
+
89
+ /**
90
+ * @param string[] $filters
91
+ */
92
+ public function allowFilters(array $filters): self
93
+ {
94
+ $this->filters += array_flip(array_map('strtolower', $filters));
95
+ return $this;
96
+ }
97
+
98
+
99
+ /**
100
+ * @param string[] $functions
101
+ */
102
+ public function allowFunctions(array $functions): self
103
+ {
104
+ $this->functions += array_flip(array_map('strtolower', $functions));
105
+ return $this;
106
+ }
107
+
108
+
109
+ /**
110
+ * @param string[] $methods
111
+ */
112
+ public function allowMethods(string $class, array $methods): self
113
+ {
114
+ $this->methodCache = [];
115
+ $this->methods[$class] = array_flip(array_map('strtolower', $methods));
116
+ return $this;
117
+ }
118
+
119
+
120
+ /**
121
+ * @param string[] $properties
122
+ */
123
+ public function allowProperties(string $class, array $properties): self
124
+ {
125
+ $this->propertyCache = [];
126
+ $this->properties[$class] = array_flip(array_map('strtolower', $properties));
127
+ return $this;
128
+ }
129
+
130
+
131
+ public function isTagAllowed(string $tag): bool
132
+ {
133
+ return isset($this->tags[strtolower($tag)]) || isset($this->tags['*']);
134
+ }
135
+
136
+
137
+ public function isFilterAllowed(string $filter): bool
138
+ {
139
+ return isset($this->filters[strtolower($filter)]) || isset($this->filters['*']);
140
+ }
141
+
142
+
143
+ public function isFunctionAllowed(string $function): bool
144
+ {
145
+ return isset($this->functions[strtolower($function)]) || isset($this->functions['*']);
146
+ }
147
+
148
+
149
+ public function isMethodAllowed(string $class, string $method): bool
150
+ {
151
+ $method = strtolower($method);
152
+ /** @var bool|null $res */
153
+ $res = &$this->methodCache[$class][$method];
154
+ if (isset($res)) {
155
+ return $res;
156
+ }
157
+
158
+ foreach ($this->methods as $c => $methods) {
159
+ if (is_a($class, $c, true) && (isset($methods[$method]) || isset($methods['*']))) {
160
+ return $res = true;
161
+ }
162
+ }
163
+
164
+ return $res = false;
165
+ }
166
+
167
+
168
+ public function isPropertyAllowed(string $class, string $property): bool
169
+ {
170
+ $property = strtolower($property);
171
+ /** @var bool|null $res */
172
+ $res = &$this->propertyCache[$class][$property];
173
+ if (isset($res)) {
174
+ return $res;
175
+ }
176
+
177
+ foreach ($this->properties as $c => $properties) {
178
+ if (is_a($class, $c, true) && (isset($properties[$property]) || isset($properties['*']))) {
179
+ return $res = true;
180
+ }
181
+ }
182
+
183
+ return $res = false;
184
+ }
185
+ }
@@ -0,0 +1,101 @@
1
+ <?php
2
+
3
+ /**
4
+ * This file is part of the Latte (https://latte.nette.org)
5
+ * Copyright (c) 2008 David Grudl (https://davidgrudl.com)
6
+ */
7
+
8
+ declare(strict_types=1);
9
+
10
+ namespace Latte;
11
+
12
+ use LogicException;
13
+
14
+
15
+ /**
16
+ * Better OOP experience.
17
+ */
18
+ trait Strict
19
+ {
20
+ /**
21
+ * Call to undefined method.
22
+ * @param mixed[] $args
23
+ * @throws LogicException
24
+ */
25
+ public function __call(string $name, array $args): mixed
26
+ {
27
+ $class = method_exists($this, $name) ? 'parent' : static::class;
28
+ $items = (new \ReflectionClass($this))->getMethods(\ReflectionMethod::IS_PUBLIC);
29
+ $items = array_map(fn($item) => $item->getName(), $items);
30
+ $hint = ($t = Helpers::getSuggestion($items, $name))
31
+ ? ", did you mean $t()?"
32
+ : '.';
33
+ throw new LogicException("Call to undefined method $class::$name()$hint");
34
+ }
35
+
36
+
37
+ /**
38
+ * Call to undefined static method.
39
+ * @param mixed[] $args
40
+ * @throws LogicException
41
+ */
42
+ public static function __callStatic(string $name, array $args): mixed
43
+ {
44
+ $rc = new \ReflectionClass(static::class);
45
+ $items = array_filter($rc->getMethods(\ReflectionMethod::IS_STATIC), fn($m) => $m->isPublic());
46
+ $items = array_map(fn($item) => $item->getName(), $items);
47
+ $hint = ($t = Helpers::getSuggestion($items, $name))
48
+ ? ", did you mean $t()?"
49
+ : '.';
50
+ throw new LogicException("Call to undefined static method $rc->name::$name()$hint");
51
+ }
52
+
53
+
54
+ /**
55
+ * Access to undeclared property.
56
+ * @throws LogicException
57
+ */
58
+ public function &__get(string $name): mixed
59
+ {
60
+ $rc = new \ReflectionClass($this);
61
+ $items = array_filter($rc->getProperties(\ReflectionProperty::IS_PUBLIC), fn($p) => !$p->isStatic());
62
+ $items = array_map(fn($item) => $item->getName(), $items);
63
+ $hint = ($t = Helpers::getSuggestion($items, $name))
64
+ ? ", did you mean $$t?"
65
+ : '.';
66
+ throw new LogicException("Attempt to read undeclared property $rc->name::$$name$hint");
67
+ }
68
+
69
+
70
+ /**
71
+ * Access to undeclared property.
72
+ * @throws LogicException
73
+ */
74
+ public function __set(string $name, mixed $value): void
75
+ {
76
+ $rc = new \ReflectionClass($this);
77
+ $items = array_filter($rc->getProperties(\ReflectionProperty::IS_PUBLIC), fn($p) => !$p->isStatic());
78
+ $items = array_map(fn($item) => $item->getName(), $items);
79
+ $hint = ($t = Helpers::getSuggestion($items, $name))
80
+ ? ", did you mean $$t?"
81
+ : '.';
82
+ throw new LogicException("Attempt to write to undeclared property $rc->name::$$name$hint");
83
+ }
84
+
85
+
86
+ public function __isset(string $name): bool
87
+ {
88
+ return false;
89
+ }
90
+
91
+
92
+ /**
93
+ * Access to undeclared property.
94
+ * @throws LogicException
95
+ */
96
+ public function __unset(string $name): void
97
+ {
98
+ $class = static::class;
99
+ throw new LogicException("Attempt to unset undeclared property $class::$$name.");
100
+ }
101
+ }
@@ -0,0 +1,24 @@
1
+ <?php
2
+
3
+ /**
4
+ * This file is part of the Latte (https://latte.nette.org)
5
+ * Copyright (c) 2008 David Grudl (https://davidgrudl.com)
6
+ */
7
+
8
+ declare(strict_types=1);
9
+
10
+ namespace Latte\Attributes;
11
+
12
+ use Attribute;
13
+
14
+
15
+ #[Attribute(Attribute::TARGET_METHOD)]
16
+ class TemplateFunction
17
+ {
18
+ }
19
+
20
+
21
+ #[Attribute(Attribute::TARGET_METHOD)]
22
+ class TemplateFilter
23
+ {
24
+ }
@@ -0,0 +1,69 @@
1
+ <?php
2
+
3
+ /**
4
+ * This file is part of the Latte (https://latte.nette.org)
5
+ * Copyright (c) 2008 David Grudl (https://davidgrudl.com)
6
+ */
7
+
8
+ declare(strict_types=1);
9
+
10
+ namespace Latte;
11
+
12
+
13
+ interface Exception
14
+ {
15
+ }
16
+
17
+
18
+ /**
19
+ * The exception occurred during Latte compilation.
20
+ */
21
+ class CompileException extends \Exception implements Exception
22
+ {
23
+ use PositionAwareException;
24
+
25
+ /** @deprecated */
26
+ public ?int $sourceLine;
27
+
28
+
29
+ public function __construct(string $message, ?Compiler\Position $position = null, ?\Throwable $previous = null)
30
+ {
31
+ parent::__construct($message, 0, $previous);
32
+ $this->position = $position;
33
+ $this->sourceLine = $position?->line;
34
+ $this->generateMessage();
35
+ }
36
+ }
37
+
38
+
39
+ /**
40
+ * The exception that indicates error of the last Regexp execution.
41
+ */
42
+ class RegexpException extends \Exception implements Exception
43
+ {
44
+ public function __construct()
45
+ {
46
+ parent::__construct(preg_last_error_msg(), preg_last_error());
47
+ }
48
+ }
49
+
50
+
51
+ /**
52
+ * Exception thrown when a not allowed construction is used in a template.
53
+ */
54
+ class SecurityViolationException extends \Exception implements Exception
55
+ {
56
+ use PositionAwareException;
57
+
58
+ public function __construct(string $message, ?Compiler\Position $position = null)
59
+ {
60
+ parent::__construct($message);
61
+ $this->position = $position;
62
+ $this->generateMessage();
63
+ }
64
+ }
65
+
66
+
67
+ class RuntimeException extends \RuntimeException implements Exception
68
+ {
69
+ }