This project does not seem to handle request data directly as such no vulnerable execution paths were found.
include
, or for example
via PHP's auto-loading mechanism.
1 | <?php |
||||||
2 | |||||||
3 | namespace yrc\rest; |
||||||
4 | |||||||
5 | use yii\rest\Controller as RestController; |
||||||
6 | use yii\filters\Cors; |
||||||
7 | use yii\filters\AccessControl; |
||||||
8 | use yii\filters\RateLimiter; |
||||||
9 | use yii\filters\VerbFilter; |
||||||
10 | use yii\filters\ContentNegotiator; |
||||||
11 | use yii\web\HttpException; |
||||||
12 | use yii\web\ForbiddenHttpException; |
||||||
13 | use yrc\web\Response; |
||||||
14 | |||||||
15 | use Yii; |
||||||
16 | |||||||
17 | use ReflectionClass; |
||||||
18 | use ReflectionMethod; |
||||||
19 | |||||||
20 | /** |
||||||
21 | * Implements Restful API controller interfaces |
||||||
22 | * @class Controller |
||||||
23 | */ |
||||||
24 | class Controller extends RestController |
||||||
25 | { |
||||||
26 | /** |
||||||
27 | * Allowed HTTP verbs |
||||||
28 | * @var array $httpVerbs |
||||||
29 | */ |
||||||
30 | private $httpVerbs = ['post', 'get', 'delete', 'put', 'patch', 'options', 'head']; |
||||||
31 | |||||||
32 | /** |
||||||
33 | * Global access filter |
||||||
34 | */ |
||||||
35 | public function beforeAction($action) |
||||||
36 | { |
||||||
37 | $parent = parent::beforeAction($action); |
||||||
38 | |||||||
39 | // Check the global access control header |
||||||
40 | if (!Yii::$app->yrc->checkAccessHeader(Yii::$app->request)) { |
||||||
0 ignored issues
–
show
|
|||||||
41 | throw new HttpException(401); |
||||||
42 | } |
||||||
43 | |||||||
44 | return $parent; |
||||||
45 | } |
||||||
46 | |||||||
47 | /** |
||||||
48 | * RestController automatically applies HTTP verb filtering and CORS headers |
||||||
49 | * @return array |
||||||
50 | */ |
||||||
51 | public function behaviors() |
||||||
52 | { |
||||||
53 | $behaviors = parent::behaviors(); |
||||||
54 | |||||||
55 | $authenticator = false; |
||||||
56 | |||||||
57 | if (isset($behaviors['authenticator'])) { |
||||||
58 | $authenticator = $behaviors['authenticator']; |
||||||
59 | unset($behaviors['authenticator']); |
||||||
60 | } |
||||||
61 | |||||||
62 | $behaviors['contentNegotiator'] = [ |
||||||
63 | 'class' => ContentNegotiator::class, |
||||||
64 | 'formats' => [ |
||||||
65 | 'application/json' => Response::FORMAT_JSON, |
||||||
66 | 'application/vnd.25519+json' => Response::FORMAT_JSON25519, |
||||||
67 | 'application/vnd.ncryptf+json' => Response::FORMAT_NCRYPTF_JSON, |
||||||
68 | 'application/xml' => Response::FORMAT_XML, |
||||||
69 | ] |
||||||
70 | ]; |
||||||
71 | |||||||
72 | $behaviors['corsFilter'] = [ |
||||||
73 | 'class' => Cors::class, |
||||||
74 | 'cors' => [ |
||||||
75 | 'Origin' => ['*'], |
||||||
76 | 'Access-Control-Request-Method' => $this->getHttpVerbMethodsFromClass($this->actions()[$this->action->id]), |
||||||
77 | 'Access-Control-Request-Headers' => ['*'], |
||||||
78 | 'Access-Control-Expose-Headers' => [ |
||||||
79 | 'Access-Control-Allow-Origin', |
||||||
80 | 'X-Pagination-Per-Page', |
||||||
81 | 'X-Pagination-Total-Count', |
||||||
82 | 'X-Pagination-Current-Page', |
||||||
83 | 'X-Pagination-Page-Count', |
||||||
84 | 'Allow', |
||||||
85 | 'X-Rate-Limit-Limit', |
||||||
86 | 'X-Rate-Limit-Remaining', |
||||||
87 | 'X-Rate-Limit-Reset' |
||||||
88 | ], |
||||||
89 | ] |
||||||
90 | ]; |
||||||
91 | |||||||
92 | $behaviors['verbs'] = [ |
||||||
93 | 'class' => VerbFilter::class, |
||||||
94 | 'actions' => $this->getVerbFilterActionMap() |
||||||
95 | ]; |
||||||
96 | |||||||
97 | // Move authenticator after verbs and cors |
||||||
98 | if ($authenticator != false) { |
||||||
99 | $behaviors['authenticator'] = $authenticator; |
||||||
100 | } |
||||||
101 | |||||||
102 | $behaviors['rateLimiter'] = [ |
||||||
103 | 'class' => RateLimiter::class, |
||||||
104 | 'enableRateLimitHeaders' => true |
||||||
105 | ]; |
||||||
106 | |||||||
107 | $access = $this->getAccessControl(); |
||||||
108 | |||||||
109 | if ($access !== null) { |
||||||
0 ignored issues
–
show
|
|||||||
110 | $behaviors['access'] = $access; |
||||||
111 | } |
||||||
112 | |||||||
113 | // Manually add the ACAO header because Yii2 is terrible at doing it |
||||||
114 | header("Access-Control-Allow-Origin: " . \implode(',', $behaviors['corsFilter']['cors']['Origin'])); |
||||||
115 | return $behaviors; |
||||||
116 | } |
||||||
117 | |||||||
118 | /** |
||||||
119 | * Pulls the ACL list from the action |
||||||
120 | * @return array |
||||||
121 | */ |
||||||
122 | private function getAccessControl() |
||||||
123 | { |
||||||
124 | $access = [ |
||||||
125 | 'class' => AccessControl::class, |
||||||
126 | 'denyCallback' => function ($rule, $action) { |
||||||
0 ignored issues
–
show
The parameter
$rule is not used and could be removed.
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
This check looks for parameters that have been defined for a function or method, but which are not used in the method body. ![]() The parameter
$action is not used and could be removed.
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
This check looks for parameters that have been defined for a function or method, but which are not used in the method body. ![]() |
|||||||
127 | throw new ForbiddenHttpException(Yii::t('yrc', 'You do not have permission to access this resource')); |
||||||
128 | } |
||||||
129 | ]; |
||||||
130 | |||||||
131 | $acl = $this->action->acl; |
||||||
132 | if ($acl === null) { |
||||||
133 | return null; |
||||||
134 | } |
||||||
135 | |||||||
136 | foreach ($acl as $verb => $perms) { |
||||||
137 | $access['rules'][] = [ |
||||||
138 | 'allow' => true, |
||||||
139 | 'verbs' => [$verb], |
||||||
140 | 'roles' => $perms |
||||||
141 | ]; |
||||||
142 | } |
||||||
143 | |||||||
144 | // Allow HTTP Options |
||||||
145 | $access['rules'][] = [ |
||||||
146 | 'allow' => true, |
||||||
147 | 'verbs' => ['OPTIONS'] |
||||||
148 | ]; |
||||||
149 | |||||||
150 | return $access; |
||||||
151 | } |
||||||
152 | |||||||
153 | /** |
||||||
154 | * Retrieves the HTTP verb list |
||||||
155 | * @param string $class |
||||||
156 | * @return array |
||||||
157 | */ |
||||||
158 | private function getHttpVerbMethodsFromClass($class) |
||||||
159 | { |
||||||
160 | $result = []; |
||||||
161 | |||||||
162 | if (is_array($class)) { |
||||||
0 ignored issues
–
show
|
|||||||
163 | $class = $class['class']; |
||||||
164 | } |
||||||
165 | |||||||
166 | // Fetch the public methods for the class then filter them out by the http verbs |
||||||
167 | $reflection = new ReflectionClass($class); |
||||||
168 | $methods = $reflection->getMethods(ReflectionMethod::IS_PUBLIC); |
||||||
169 | foreach ($methods as $method) { |
||||||
170 | if (\in_array($method->name, $this->httpVerbs)) { |
||||||
171 | $result[] = $method->name; |
||||||
172 | } |
||||||
173 | } |
||||||
174 | |||||||
175 | return $result; |
||||||
176 | } |
||||||
177 | |||||||
178 | /** |
||||||
179 | * Convers self::actions() for automatic verb filtering |
||||||
180 | * @return array |
||||||
181 | */ |
||||||
182 | private function getVerbFilterActionMap() |
||||||
183 | { |
||||||
184 | $actions = $this->actions(); |
||||||
185 | |||||||
186 | // Only apply this filtering for ActionMapped Controllers |
||||||
187 | if (empty($actions)) { |
||||||
188 | return []; |
||||||
189 | } |
||||||
190 | |||||||
191 | $actionMap = []; |
||||||
192 | |||||||
193 | // Iterate over all the actions, and automatically determine the methods implemented |
||||||
194 | foreach ($actions as $actionName => $params) { |
||||||
195 | static $class = null; |
||||||
196 | if (is_array($params)) { |
||||||
197 | $class = $params['class']; |
||||||
198 | } else { |
||||||
199 | $class = $params; |
||||||
200 | } |
||||||
201 | |||||||
202 | $actionMap[$actionName] = $this->getHttpVerbMethodsFromClass($class); |
||||||
203 | } |
||||||
204 | |||||||
205 | return $actionMap; |
||||||
206 | } |
||||||
207 | } |
||||||
208 |
This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.
This is most likely a typographical error or the method has been renamed.