Issues (196)

Security Analysis    6 potential vulnerabilities

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 (4)
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 (1)
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.
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.

src/Model/AutoEdits.php (10 issues)

1
<?php
2
3
declare(strict_types = 1);
4
5
namespace App\Model;
6
7
use App\Repository\AutoEditsRepository;
8
use App\Repository\EditRepository;
9
use App\Repository\PageRepository;
10
use App\Repository\UserRepository;
11
12
/**
13
 * AutoEdits returns statistics about automated edits made by a user.
14
 */
15
class AutoEdits extends Model
16
{
17
    protected EditRepository $editRepo;
18
    protected PageRepository $pageRepo;
19
    protected UserRepository $userRepo;
20
21
    /** @var null|string The tool we're searching for when fetching (semi-)automated edits. */
22
    protected ?string $tool;
23
24
    /** @var Edit[] The list of non-automated contributions. */
25
    protected array $nonAutomatedEdits;
26
27
    /** @var Edit[] The list of automated contributions. */
28
    protected array $automatedEdits;
29
30
    /** @var int Total number of edits. */
31
    protected int $editCount;
32
33
    /** @var int Total number of non-automated edits. */
34
    protected int $automatedCount;
35
36
    /** @var array Counts of known automated tools used by the given user. */
37
    protected array $toolCounts;
38
39
    /** @var int Total number of edits made with the tools. */
40
    protected int $toolsTotal;
41
42
    /** @var int Default number of results to show per page when fetching (non-)automated edits. */
43
    public const RESULTS_PER_PAGE = 50;
44
45
    /**
46
     * Constructor for the AutoEdits class.
47
     * @param AutoEditsRepository $repository
48
     * @param EditRepository $editRepo
49
     * @param PageRepository $pageRepo
50
     * @param UserRepository $userRepo
51
     * @param Project $project
52
     * @param User $user
53
     * @param int|string $namespace Namespace ID or 'all'
54
     * @param false|int $start Start date as Unix timestamp.
55
     * @param false|int $end End date as Unix timestamp.
56
     * @param null $tool The tool we're searching for when fetching (semi-)automated edits.
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $tool is correct as it would always require null to be passed?
Loading history...
57
     * @param false|int $offset Unix timestamp. Used for pagination.
58
     * @param int|null $limit Number of results to return.
59
     */
60
    public function __construct(
61
        AutoEditsRepository $repository,
62
        EditRepository $editRepo,
63
        PageRepository $pageRepo,
64
        UserRepository $userRepo,
65
        Project $project,
66
        User $user,
67
        $namespace = 0,
68
        $start = false,
69
        $end = false,
70
        $tool = null,
71
        $offset = false,
72
        ?int $limit = self::RESULTS_PER_PAGE
73
    ) {
74
        $this->repository = $repository;
75
        $this->editRepo = $editRepo;
76
        $this->pageRepo = $pageRepo;
77
        $this->userRepo = $userRepo;
78
        $this->project = $project;
79
        $this->user = $user;
80
        $this->namespace = $namespace;
81
        $this->start = $start;
82
        $this->end = $end;
83
        $this->tool = $tool;
84
        $this->offset = $offset;
85
        $this->limit = $limit ?? self::RESULTS_PER_PAGE;
86
    }
87
88
    /**
89
     * The tool we're limiting the results to when fetching
90
     * (semi-)automated contributions.
91
     * @return null|string
92
     */
93
    public function getTool(): ?string
94
    {
95
        return $this->tool;
96
    }
97
98
    /**
99
     * Get the raw edit count of the user.
100
     * @return int
101
     */
102
    public function getEditCount(): int
103
    {
104
        if (!isset($this->editCount)) {
105
            $this->editCount = $this->user->countEdits(
0 ignored issues
show
The method countEdits() does not exist on null. ( Ignorable by Annotation )

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

105
            /** @scrutinizer ignore-call */ 
106
            $this->editCount = $this->user->countEdits(

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.

Loading history...
106
                $this->project,
107
                $this->namespace,
108
                $this->start,
109
                $this->end
110
            );
111
        }
112
113
        return $this->editCount;
114
    }
115
116
    /**
117
     * Get the number of edits this user made using semi-automated tools.
118
     * This is not the same as self::getToolCounts because the regex can overlap.
119
     * @return int Result of query, see below.
120
     */
121
    public function getAutomatedCount(): int
122
    {
123
        if (isset($this->automatedCount)) {
124
            return $this->automatedCount;
125
        }
126
127
        $this->automatedCount = $this->repository->countAutomatedEdits(
0 ignored issues
show
The method countAutomatedEdits() does not exist on App\Repository\Repository. It seems like you code against a sub-type of App\Repository\Repository such as App\Repository\EditCounterRepository or App\Repository\AutoEditsRepository. ( Ignorable by Annotation )

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

127
        /** @scrutinizer ignore-call */ 
128
        $this->automatedCount = $this->repository->countAutomatedEdits(
Loading history...
128
            $this->project,
129
            $this->user,
130
            $this->namespace,
131
            $this->start,
132
            $this->end
133
        );
134
135
        return $this->automatedCount;
136
    }
137
138
    /**
139
     * Get the percentage of all edits made using automated tools.
140
     * @return float
141
     */
142
    public function getAutomatedPercentage(): float
143
    {
144
        return $this->getEditCount() > 0
145
            ? ($this->getAutomatedCount() / $this->getEditCount()) * 100
146
            : 0;
147
    }
148
149
    /**
150
     * Get non-automated contributions for this user.
151
     * @param bool $forJson
152
     * @return string[]|Edit[]
153
     */
154
    public function getNonAutomatedEdits(bool $forJson = false): array
155
    {
156
        if (isset($this->nonAutomatedEdits)) {
157
            return $this->nonAutomatedEdits;
158
        }
159
160
        $revs = $this->repository->getNonAutomatedEdits(
0 ignored issues
show
The method getNonAutomatedEdits() does not exist on App\Repository\Repository. It seems like you code against a sub-type of App\Repository\Repository such as App\Repository\AutoEditsRepository. ( Ignorable by Annotation )

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

160
        /** @scrutinizer ignore-call */ 
161
        $revs = $this->repository->getNonAutomatedEdits(
Loading history...
161
            $this->project,
162
            $this->user,
163
            $this->namespace,
164
            $this->start,
165
            $this->end,
166
            $this->offset,
167
            $this->limit
168
        );
169
170
        $this->nonAutomatedEdits = Edit::getEditsFromRevs(
171
            $this->pageRepo,
172
            $this->editRepo,
173
            $this->userRepo,
174
            $this->project,
175
            $this->user,
0 ignored issues
show
It seems like $this->user can also be of type null; however, parameter $user of App\Model\Edit::getEditsFromRevs() does only seem to accept App\Model\User, maybe add an additional type check? ( Ignorable by Annotation )

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

175
            /** @scrutinizer ignore-type */ $this->user,
Loading history...
176
            $revs
177
        );
178
179
        if ($forJson) {
180
            return array_map(function (Edit $edit) {
181
                return $edit->getForJson();
182
            }, $this->nonAutomatedEdits);
183
        }
184
185
        return $this->nonAutomatedEdits;
186
    }
187
188
    /**
189
     * Get automated contributions for this user.
190
     * @param bool $forJson
191
     * @return Edit[]
192
     */
193
    public function getAutomatedEdits(bool $forJson = false): array
194
    {
195
        if (isset($this->automatedEdits)) {
196
            return $this->automatedEdits;
197
        }
198
199
        $revs = $this->repository->getAutomatedEdits(
0 ignored issues
show
The method getAutomatedEdits() does not exist on App\Repository\Repository. It seems like you code against a sub-type of App\Repository\Repository such as App\Repository\AutoEditsRepository. ( Ignorable by Annotation )

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

199
        /** @scrutinizer ignore-call */ 
200
        $revs = $this->repository->getAutomatedEdits(
Loading history...
200
            $this->project,
201
            $this->user,
202
            $this->namespace,
203
            $this->start,
204
            $this->end,
205
            $this->tool,
206
            $this->offset,
207
            $this->limit
208
        );
209
210
        $this->automatedEdits = Edit::getEditsFromRevs(
211
            $this->pageRepo,
212
            $this->editRepo,
213
            $this->userRepo,
214
            $this->project,
215
            $this->user,
0 ignored issues
show
It seems like $this->user can also be of type null; however, parameter $user of App\Model\Edit::getEditsFromRevs() does only seem to accept App\Model\User, maybe add an additional type check? ( Ignorable by Annotation )

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

215
            /** @scrutinizer ignore-type */ $this->user,
Loading history...
216
            $revs
217
        );
218
219
        if ($forJson) {
220
            return array_map(function (Edit $edit) {
221
                return $edit->getForJson();
222
            }, $this->automatedEdits);
223
        }
224
225
        return $this->automatedEdits;
226
    }
227
228
    /**
229
     * Get counts of known automated tools used by the given user.
230
     * @return array Each tool that they used along with the count and link:
231
     *                  [
232
     *                      'Twinkle' => [
233
     *                          'count' => 50,
234
     *                          'link' => 'Wikipedia:Twinkle',
235
     *                      ],
236
     *                  ]
237
     */
238
    public function getToolCounts(): array
239
    {
240
        if (isset($this->toolCounts)) {
241
            return $this->toolCounts;
242
        }
243
244
        $this->toolCounts = $this->repository->getToolCounts(
0 ignored issues
show
The method getToolCounts() does not exist on App\Repository\Repository. It seems like you code against a sub-type of App\Repository\Repository such as App\Repository\AutoEditsRepository. ( Ignorable by Annotation )

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

244
        /** @scrutinizer ignore-call */ 
245
        $this->toolCounts = $this->repository->getToolCounts(
Loading history...
245
            $this->project,
246
            $this->user,
247
            $this->namespace,
248
            $this->start,
249
            $this->end
250
        );
251
252
        return $this->toolCounts;
253
    }
254
255
    /**
256
     * Get a list of all available tools for the Project.
257
     * @return array
258
     */
259
    public function getAllTools(): array
260
    {
261
        return $this->repository->getTools($this->project);
0 ignored issues
show
The method getTools() does not exist on App\Repository\Repository. Did you maybe mean getToolsConnection()? ( Ignorable by Annotation )

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

261
        return $this->repository->/** @scrutinizer ignore-call */ getTools($this->project);

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.

Loading history...
262
    }
263
264
    /**
265
     * Get the combined number of edits made with each tool. This is calculated separately from
266
     * self::getAutomatedCount() because the regex can sometimes overlap, and the counts are actually different.
267
     * @return int
268
     */
269
    public function getToolsTotal(): int
270
    {
271
        if (!isset($this->toolsTotal)) {
272
            $this->toolsTotal = array_reduce($this->getToolCounts(), function ($a, $b) {
273
                return $a + $b['count'];
274
            });
275
        }
276
277
        return $this->toolsTotal;
278
    }
279
280
    /**
281
     * @return bool
282
     */
283
    public function getUseSandbox(): bool
284
    {
285
        return $this->repository->getUseSandbox();
0 ignored issues
show
The method getUseSandbox() does not exist on App\Repository\Repository. It seems like you code against a sub-type of App\Repository\Repository such as App\Repository\AutoEditsRepository. ( Ignorable by Annotation )

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

285
        return $this->repository->/** @scrutinizer ignore-call */ getUseSandbox();
Loading history...
286
    }
287
}
288