Issues (102)

Security Analysis    no vulnerabilities found

This project does not seem to handle request data directly as such no vulnerable execution paths were found.

  File Inclusion
File Inclusion enables an attacker to inject custom files into PHP's file loading mechanism, either explicitly passed to include, or for example via PHP's auto-loading mechanism.
  Regex Injection
Regex Injection enables an attacker to execute arbitrary code in your PHP process.
  SQL Injection
SQL Injection enables an attacker to execute arbitrary SQL code on your database server gaining access to user data, or manipulating user data.
  Response Splitting
Response Splitting can be used to send arbitrary responses.
  File Manipulation
File Manipulation enables an attacker to write custom data to files. This potentially leads to injection of arbitrary code on the server.
  Object Injection
Object Injection enables an attacker to inject an object into PHP code, and can lead to arbitrary code execution, file exposure, or file manipulation attacks.
  File Exposure
File Exposure allows an attacker to gain access to local files that he should not be able to access. These files can for example include database credentials, or other configuration files.
  XML Injection
XML Injection enables an attacker to read files on your local filesystem including configuration files, or can be abused to freeze your web-server process.
  Code Injection
Code Injection enables an attacker to execute arbitrary code on the server.
  Variable Injection
Variable Injection enables an attacker to overwrite program variables with custom data, and can lead to further vulnerabilities.
  XPath Injection
XPath Injection enables an attacker to modify the parts of XML document that are read. If that XML document is for example used for authentication, this can lead to further vulnerabilities similar to SQL Injection.
  Other Vulnerability
This category comprises other attack vectors such as manipulating the PHP runtime, loading custom extensions, freezing the runtime, or similar.
  Command Injection
Command Injection enables an attacker to inject a shell command that is execute with the privileges of the web-server. This can be used to expose sensitive data, or gain access of your server.
  LDAP Injection
LDAP Injection enables an attacker to inject LDAP statements potentially granting permission to run unauthorized queries, or modify content inside the LDAP tree.
  Cross-Site Scripting
Cross-Site Scripting enables an attacker to inject code into the response of a web-request that is viewed by other users. It can for example be used to bypass access controls, or even to take over other users' accounts.
  Header Injection
Unfortunately, the security analysis is currently not available for your project. If you are a non-commercial open-source project, please contact support to gain access.

plugin/Integrations/Breakdance/Controller.php (10 issues)

1
<?php
2
3
namespace GeminiLabs\SiteReviews\Integrations\Breakdance;
4
5
use GeminiLabs\SiteReviews\Controllers\AbstractController;
6
use GeminiLabs\SiteReviews\Database\ShortcodeOptionManager;
7
use GeminiLabs\SiteReviews\Helpers\Arr;
8
use GeminiLabs\SiteReviews\Helpers\Str;
9
use GeminiLabs\SiteReviews\Helpers\Svg;
10
11
class Controller extends AbstractController
12
{
13
    /**
14
     * Breakdance does not provide a way to create a multi-select dropdown
15
     * populated by an AJAX callback on init AND search. To get around this,
16
     * we use the post_chooser control and override the callback with our own.
17
     *
18
     * @action breakdance_ajax_breakdance_get_posts:1
19
     * @action wp_ajax_breakdance_get_posts:1
20
     * @action wp_ajax_nopriv_breakdance_get_posts:1
21
     */
22
    public function interceptGetPostsQuery(): void
23
    {
24
        if (!$this->verifyRequest()) {
25
            return;
26
        }
27
        $option = Str::removePrefix(filter_input(INPUT_POST, 'postType'), glsr()->prefix);
28
        $search = filter_input(INPUT_POST, 'search');
29
        $params = compact('option', 'search');
30
        $results = call_user_func([glsr(ShortcodeOptionManager::class), $option], $params);
31
        $replacements = [ // the post_chooser control requires integer keys
32
            'post_id' => -10,
33
            'parent_id' => -20,
34
            'user_id' => -30,
35
            'author_id' => -40,
36
            'profile_id' => -50,
37
        ];
38
        if (in_array($option, ['assigned_posts'])) {
39
            $thumbnailFn = fn ($id) => get_the_post_thumbnail_url($id, 'thumbnail');
40
        } elseif (in_array($option, ['assigned_users', 'author'])) {
41
            $thumbnailFn = fn ($id) => get_avatar_url($id);
42
        }
43
        $data = $this->prepareResponse($results, $thumbnailFn ?? null, $replacements);
44
        if (in_array($option, ['post_id'])) {
45
            array_walk($data, function (&$item) {
46
                $item['title'] = "{$item['id']}: {$item['title']}";
47
            });
48
        }
49
        wp_send_json_success($data, 200);
50
        exit; // @phpstan-ignore-line
0 ignored issues
show
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
51
    }
52
53
    /**
54
     * @action unofficial_i_am_kevin_geary_master_of_all_things_css_and_html
55
     */
56
    public function printInlineStyles(): void
57
    {
58
        $icon = Svg::encoded('assets/images/icon-static.svg');
59
        echo '<style>'.
60
            '.breakdance-control-wrapper:has(+ .breakdance-control-wrapper [data-test-id$="_description_alert"] .breakdance-alert-box) {'.
61
                'margin-bottom: 7px;'.
62
            '}'.
63
            '[data-test-id$="_description_alert"] .breakdance-alert-box {'.
64
                'padding-inline: 13px;',
65
                '.v-alert__border--left {'.
66
                    'display: none;'.
67
                '}',
68
            '}',
69
            '.breakdance-add-panel__element:has(.glsr-icon) .breakdance-element-badge {'.
70
                'padding: 0;'.
71
                '&::after {'.
72
                    'background-image: url("'.$icon.'");'.
73
                    'content: "";'.
74
                    'height: var(--text-lg);'.
75
                    'width: var(--text-lg);'.
76
                '}'.
77
            '}'.
78
        '</style>';
79
    }
80
81
    /**
82
     * @action init
83
     */
84
    public function registerDesignControls(): void
85
    {
86
        $controls = \EssentialElements\Formdesignoptions::designControls();
0 ignored issues
show
The type EssentialElements\Formdesignoptions was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
87
        $atomV1FormDesign = reset($controls);
88
        if ('other' === Arr::get($atomV1FormDesign, 'children.5.slug')) {
89
            unset($atomV1FormDesign['children'][5]);
90
        }
91
        \Breakdance\Elements\PresetSections\PresetSectionsController::getInstance()->register(
0 ignored issues
show
The type Breakdance\Elements\Pres...resetSectionsController was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
92
            "GLSR\\FormDesign",
93
            $atomV1FormDesign,
94
            true
95
        );
96
    }
97
98
    /**
99
     * Breakdance loads an element by filtering the result of get_declared_classes
100
     * and checking if the class is_subclass_of \Breakdance\Elements\Element.
101
     *
102
     * Controls are added dynamically from the Shortcode class to enforce consistancy
103
     * across builder integrations. As a result, we need to bypass the Element Studio
104
     * and we do this by setting the save location to $onlyForAdvancedUsers and
105
     * $excludeFromElementStudio.
106
     *
107
     * @action breakdance_loaded:5
108
     */
109
    public function registerElements(): void
110
    {
111
        $pluginDir = dirname(plugin_basename(glsr()->file));
112
        \Breakdance\Elements\registerCategory(glsr()->id, glsr()->name);
0 ignored issues
show
The function registerCategory was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

112
        /** @scrutinizer ignore-call */ 
113
        \Breakdance\Elements\registerCategory(glsr()->id, glsr()->name);
Loading history...
113
        \Breakdance\ElementStudio\registerSaveLocation(
0 ignored issues
show
The function registerSaveLocation was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

113
        /** @scrutinizer ignore-call */ 
114
        \Breakdance\ElementStudio\registerSaveLocation(
Loading history...
114
            "{$pluginDir}/assets/breakdance/elements",
115
            'GLSR_Breakdance',
116
            'element',
117
            'Site Reviews Elements',
118
            true, // onlyForAdvancedUsers
119
            true // excludeFromElementStudio
120
        );
121
        \Breakdance\ElementStudio\registerSaveLocation(
122
            "{$pluginDir}/assets/breakdance/macros",
123
            'GLSR_Breakdance',
124
            'macro',
125
            'Site Reviews Macros',
126
            true, // onlyForAdvancedUsers
127
            true // excludeFromElementStudio
128
        );
129
        \Breakdance\ElementStudio\registerSaveLocation(
130
            "{$pluginDir}/assets/breakdance/presets",
131
            'GLSR_Breakdance',
132
            'preset',
133
            'Site Reviews Presets',
134
            true, // onlyForAdvancedUsers
135
            true // excludeFromElementStudio
136
        );
137
    }
138
139
    /**
140
     * Unfortunately we can't use this yet because Breakdance does not support
141
     * AJAX searching in multiselect controls.
142
     *
143
     * @action breakdance_loaded
144
     */
145
    public function registerRoutes(): void
146
    {
147
        return; // We can't use this yet...
148
        $input = filter_input_array(INPUT_POST, [ // @phpstan-ignore-line
0 ignored issues
show
$input = filter_input_ar...ILTER_REQUIRE_ARRAY)))) is not reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

Loading history...
149
            'requestData' => [
150
                'context' => [
151
                    'filter' => fn ($value) => is_numeric($value)
152
                        ? intval($value)
153
                        : strip_tags($value),
154
                    'flags' => FILTER_REQUIRE_ARRAY,
155
                ],
156
            ],
157
        ]);
158
        $include = Arr::consolidate($input['requestData']['context'] ?? []);
159
        \Breakdance\AJAX\register_handler(
0 ignored issues
show
The function register_handler was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

159
        /** @scrutinizer ignore-call */ 
160
        \Breakdance\AJAX\register_handler(
Loading history...
160
            glsr()->prefix.'breakdance_assigned_posts',
161
            fn () => $this->fetchAssignedPosts($include),
162
            'edit'
163
        );
164
        \Breakdance\AJAX\register_handler(
165
            glsr()->prefix.'breakdance_assigned_terms',
166
            fn () => $this->fetchAssignedTerms($include),
167
            'edit'
168
        );
169
        \Breakdance\AJAX\register_handler(
170
            glsr()->prefix.'breakdance_assigned_users',
171
            fn () => $this->fetchAssignedUsers($include),
172
            'edit'
173
        );
174
        \Breakdance\AJAX\register_handler(
175
            glsr()->prefix.'breakdance_author',
176
            fn () => $this->fetchAuthor($include),
177
            'edit'
178
        );
179
        \Breakdance\AJAX\register_handler(
180
            glsr()->prefix.'breakdance_post_id',
181
            fn () => $this->fetchPostId($include),
182
            'edit'
183
        );
184
    }
185
186
    /**
187
     * Unfortunately we can't use this yet because Breakdance does not support
188
     * AJAX searching in multiselect controls.
189
     */
190
    protected function fetchAssignedPosts(array $include): array
191
    {
192
        // $include = array_filter($include, fn ($id) => is_numeric($id) || in_array($id, [
193
        //     'parent_id',
194
        //     'post_id',
195
        // ]));
196
        return [];
197
    }
198
199
    /**
200
     * Unfortunately we can't use this yet because Breakdance does not support
201
     * AJAX searching in multiselect controls.
202
     */
203
    protected function fetchAssignedTerms(array $include): array
204
    {
205
        return [];
206
    }
207
208
    /**
209
     * Unfortunately we can't use this yet because Breakdance does not support
210
     * AJAX searching in multiselect controls.
211
     */
212
    protected function fetchAssignedUsers(array $include): array
213
    {
214
        // $include = array_filter($include, fn ($id) => is_numeric($id) || in_array($id, [
215
        //     'author_id',
216
        //     'profile_id',
217
        //     'user_id',
218
        // ]));
219
        return [];
220
    }
221
222
    /**
223
     * Unfortunately we can't use this yet because Breakdance does not support
224
     * AJAX searching in multiselect controls.
225
     */
226
    protected function fetchAuthor(array $include): array
227
    {
228
        // $include = array_filter($include, fn ($id) => is_numeric($id) || in_array($id, [
229
        //     'user_id',
230
        // ]));
231
        return [];
232
    }
233
234
    /**
235
     * Unfortunately we can't use this yet because Breakdance does not support
236
     * AJAX searching in multiselect controls.
237
     */
238
    protected function fetchPostId(array $include): array
239
    {
240
        return [];
241
    }
242
243
    protected function prepareResponse(array $results, ?callable $thumbnailFn = null, array $replacements = []): array
244
    {
245
        if (!$thumbnailFn) {
246
            $thumbnailFn = fn () => false;
247
        }
248
        $callback = fn ($id, $title) => [
249
            'id' => $replacements[$id] ?? $id,
250
            'title' => $title,
251
            'thumbnail' => $thumbnailFn($id),
252
        ];
253
        return array_map($callback, array_keys($results), $results);
254
    }
255
256
    protected function verifyRequest(): bool
257
    {
258
        if (!str_starts_with((string) filter_input(INPUT_POST, 'postType'), glsr()->prefix)) {
259
            return false;
260
        }
261
        if (!\Breakdance\Permissions\hasMinimumPermission('edit')) {
0 ignored issues
show
The function hasMinimumPermission was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

261
        if (!/** @scrutinizer ignore-call */ \Breakdance\Permissions\hasMinimumPermission('edit')) {
Loading history...
262
            return false;
263
        }
264
        $nonceTick = check_ajax_referer(\Breakdance\AJAX\get_nonce_key_for_ajax_requests(), false, false);
0 ignored issues
show
The function get_nonce_key_for_ajax_requests was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

264
        $nonceTick = check_ajax_referer(/** @scrutinizer ignore-call */ \Breakdance\AJAX\get_nonce_key_for_ajax_requests(), false, false);
Loading history...
265
        if (!$nonceTick) {
266
            return false;
267
        }
268
        if (2 === $nonceTick) {
269
            $refreshNonce = \Breakdance\AJAX\get_nonce_for_ajax_requests();
0 ignored issues
show
The function get_nonce_for_ajax_requests was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

269
            $refreshNonce = /** @scrutinizer ignore-call */ \Breakdance\AJAX\get_nonce_for_ajax_requests();
Loading history...
270
            header('Breakdance-Refresh-Nonce:'.$refreshNonce);
271
        }
272
        return true;
273
    }
274
}
275