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/EditSummary.php (1 issue)

Labels
Severity
1
<?php
2
3
declare(strict_types = 1);
4
5
namespace App\Model;
6
7
use App\Repository\EditSummaryRepository;
8
use DateTime;
9
10
/**
11
 * An EditSummary provides statistics about a user's edit summary usage over time.
12
 */
13
class EditSummary extends Model
14
{
15
    /** @var int Number of edits from present to consider as 'recent'. */
16
    protected int $numEditsRecent;
17
18
    /**
19
     * Counts of summaries, raw edits, and per-month breakdown.
20
     * Keys are underscored because this also is served in the API.
21
     * @var array
22
     */
23
    protected array $data = [
24
        'recent_edits_minor' => 0,
25
        'recent_edits_major' => 0,
26
        'total_edits_minor' => 0,
27
        'total_edits_major' => 0,
28
        'total_edits' => 0,
29
        'recent_summaries_minor' => 0,
30
        'recent_summaries_major' => 0,
31
        'total_summaries_minor' => 0,
32
        'total_summaries_major' => 0,
33
        'total_summaries' => 0,
34
        'month_counts' => [],
35
    ];
36
37
    /**
38
     * EditSummary constructor.
39
     *
40
     * @param EditSummaryRepository $repository
41
     * @param Project $project The project we're working with.
42
     * @param User $user The user to process.
43
     * @param int|string $namespace Namespace ID or 'all' for all namespaces.
44
     * @param int|false $start Start date as Unix timestamp.
45
     * @param int|false $end End date as Unix timestamp.
46
     * @param int $numEditsRecent Number of edits from present to consider as 'recent'.
47
     */
48
    public function __construct(
49
        EditSummaryRepository $repository,
50
        Project $project,
51
        User $user,
52
        $namespace,
53
        $start = false,
54
        $end = false,
55
        int $numEditsRecent = 150
56
    ) {
57
        $this->repository = $repository;
58
        $this->project = $project;
59
        $this->user = $user;
60
        $this->namespace = $namespace;
61
        $this->start = $start;
62
        $this->end = $end;
63
        $this->numEditsRecent = $numEditsRecent;
64
    }
65
66
    /**
67
     * Get the total number of edits.
68
     * @return int
69
     */
70
    public function getTotalEdits(): int
71
    {
72
        return $this->data['total_edits'];
73
    }
74
75
    /**
76
     * Get the total number of minor edits.
77
     * @return int
78
     */
79
    public function getTotalEditsMinor(): int
80
    {
81
        return $this->data['total_edits_minor'];
82
    }
83
84
    /**
85
     * Get the total number of major (non-minor) edits.
86
     * @return int
87
     */
88
    public function getTotalEditsMajor(): int
89
    {
90
        return $this->data['total_edits_major'];
91
    }
92
93
    /**
94
     * Get the total number of recent minor edits.
95
     * @return int
96
     */
97
    public function getRecentEditsMinor(): int
98
    {
99
        return $this->data['recent_edits_minor'];
100
    }
101
102
    /**
103
     * Get the total number of recent major (non-minor) edits.
104
     * @return int
105
     */
106
    public function getRecentEditsMajor(): int
107
    {
108
        return $this->data['recent_edits_major'];
109
    }
110
111
    /**
112
     * Get the total number of edits with summaries.
113
     * @return int
114
     */
115
    public function getTotalSummaries(): int
116
    {
117
        return $this->data['total_summaries'];
118
    }
119
120
    /**
121
     * Get the total number of minor edits with summaries.
122
     * @return int
123
     */
124
    public function getTotalSummariesMinor(): int
125
    {
126
        return $this->data['total_summaries_minor'];
127
    }
128
129
    /**
130
     * Get the total number of major (non-minor) edits with summaries.
131
     * @return int
132
     */
133
    public function getTotalSummariesMajor(): int
134
    {
135
        return $this->data['total_summaries_major'];
136
    }
137
138
    /**
139
     * Get the total number of recent minor edits with with summaries.
140
     * @return int
141
     */
142
    public function getRecentSummariesMinor(): int
143
    {
144
        return $this->data['recent_summaries_minor'];
145
    }
146
147
    /**
148
     * Get the total number of recent major (non-minor) edits with with summaries.
149
     * @return int
150
     */
151
    public function getRecentSummariesMajor(): int
152
    {
153
        return $this->data['recent_summaries_major'];
154
    }
155
156
    /**
157
     * Get the month counts.
158
     * @return array Months as 'YYYY-MM' as the keys,
159
     *   with key 'total' and 'summaries' as the values.
160
     */
161
    public function getMonthCounts(): array
162
    {
163
        return $this->data['month_counts'];
164
    }
165
166
    /**
167
     * Get the whole blob of counts.
168
     * @return array Counts of summaries, raw edits, and per-month breakdown.
169
     * @codeCoverageIgnore
170
     */
171
    public function getData(): array
172
    {
173
        return $this->data;
174
    }
175
176
    /**
177
     * Fetch the data from the database, process, and put in memory.
178
     * @codeCoverageIgnore
179
     */
180
    public function prepareData(): array
181
    {
182
        // Do our database work in the Repository, passing in reference
183
        // to $this->processRow so we can do post-processing here.
184
        $ret = $this->repository->prepareData(
0 ignored issues
show
The method prepareData() does not exist on App\Repository\Repository. It seems like you code against a sub-type of App\Repository\Repository such as App\Repository\EditSummaryRepository. ( Ignorable by Annotation )

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

184
        /** @scrutinizer ignore-call */ 
185
        $ret = $this->repository->prepareData(
Loading history...
185
            [$this, 'processRow'],
186
            $this->project,
187
            $this->user,
188
            $this->namespace,
189
            $this->start,
190
            $this->end
191
        );
192
193
        // We want to keep all the default zero values if there are no contributions.
194
        if (count($ret) > 0) {
195
            $this->data = $ret;
196
        }
197
198
        return $ret;
199
    }
200
201
    /**
202
     * Process a single row from the database, updating class properties with counts.
203
     * @param string[] $row As retrieved from the revision table.
204
     * @return string[]
205
     */
206
    public function processRow(array $row): array
207
    {
208
        // Extract the date out of the date field
209
        $timestamp = DateTime::createFromFormat('YmdHis', $row['rev_timestamp']);
210
211
        $monthKey = $timestamp->format('Y-m');
212
213
        // Grand total for number of edits
214
        $this->data['total_edits']++;
215
216
        // Update total edit count for this month.
217
        $this->updateMonthCounts($monthKey, 'total');
218
219
        // Total edit summaries
220
        if ($this->hasSummary($row)) {
221
            $this->data['total_summaries']++;
222
223
            // Update summary count for this month.
224
            $this->updateMonthCounts($monthKey, 'summaries');
225
        }
226
227
        if ($this->isMinor($row)) {
228
            $this->updateMajorMinorCounts($row, 'minor');
229
        } else {
230
            $this->updateMajorMinorCounts($row, 'major');
231
        }
232
233
        return $this->data;
234
    }
235
236
    /**
237
     * Given the row in `revision`, update minor counts.
238
     * @param string[] $row As retrieved from the revision table.
239
     * @param string $type Either 'minor' or 'major'.
240
     * @codeCoverageIgnore
241
     */
242
    private function updateMajorMinorCounts(array $row, string $type): void
243
    {
244
        $this->data['total_edits_'.$type]++;
245
246
        $hasSummary = $this->hasSummary($row);
247
        $isRecent = $this->data['recent_edits_'.$type] < $this->numEditsRecent;
248
249
        if ($hasSummary) {
250
            $this->data['total_summaries_'.$type]++;
251
        }
252
253
        // Update recent edits counts.
254
        if ($isRecent) {
255
            $this->data['recent_edits_'.$type]++;
256
257
            if ($hasSummary) {
258
                $this->data['recent_summaries_'.$type]++;
259
            }
260
        }
261
    }
262
263
    /**
264
     * Was the given row in `revision` marked as a minor edit?
265
     * @param string[] $row As retrieved from the revision table.
266
     * @return boolean
267
     */
268
    private function isMinor(array $row): bool
269
    {
270
        return 1 === (int)$row['rev_minor_edit'];
271
    }
272
273
    /**
274
     * Taking into account automated edit summaries, does the given
275
     * row in `revision` have a user-supplied edit summary?
276
     * @param string[] $row As retrieved from the revision table.
277
     * @return boolean
278
     */
279
    private function hasSummary(array $row): bool
280
    {
281
        $summary = preg_replace("/^\/\* (.*?) \*\/\s*/", '', $row['comment'] ?: '');
282
        return '' !== $summary;
283
    }
284
285
    /**
286
     * Check and see if the month is set for given $monthKey and $type.
287
     * If it is, increment it, otherwise set it to 1.
288
     * @param string $monthKey In the form 'YYYY-MM'.
289
     * @param string $type     Either 'total' or 'summaries'.
290
     * @codeCoverageIgnore
291
     */
292
    private function updateMonthCounts(string $monthKey, string $type): void
293
    {
294
        if (isset($this->data['month_counts'][$monthKey][$type])) {
295
            $this->data['month_counts'][$monthKey][$type]++;
296
        } else {
297
            $this->data['month_counts'][$monthKey][$type] = 1;
298
        }
299
    }
300
}
301