Issues (118)

Security Analysis    not enabled

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

  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.
  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.
  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.
  Code Injection
Code Injection enables an attacker to execute arbitrary code on the server.
  Response Splitting
Response Splitting can be used to send arbitrary responses.
  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.
  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.
  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.
  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.
  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.
  Header Injection
  Other Vulnerability
This category comprises other attack vectors such as manipulating the PHP runtime, loading custom extensions, freezing the runtime, or similar.
  Regex Injection
Regex Injection enables an attacker to execute arbitrary code in your PHP process.
  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.
  Variable Injection
Variable Injection enables an attacker to overwrite program variables with custom data, and can lead to further vulnerabilities.
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.

Builder/Message/AbstractMessageBuilder.php (3 issues)

Labels
Severity

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
3
/*
4
 * This file is part of the MilioooMessageBundle package.
5
 *
6
 * (c) Michiel boeckaert <[email protected]>
7
 * This source file is subject to the MIT license that is bundled
8
 * with this source code in the file LICENSE.
9
 */
10
11
namespace Miliooo\Messaging\Builder\Message;
12
13
use Miliooo\Messaging\Model\ThreadInterface;
14
use Miliooo\Messaging\User\ParticipantInterface;
15
use Miliooo\Messaging\Model\ThreadMetaInterface;
16
use Miliooo\Messaging\Model\MessageInterface;
17
use Miliooo\Messaging\Model\MessageMetaInterface;
18
use Miliooo\Messaging\Model\BuilderInterface;
19
use Miliooo\Messaging\ValueObjects\ThreadStatus;
20
21
/**
22
 * Description of AbstractMessageBuilder
23
 *
24
 * @author Michiel Boeckaert <[email protected]>
25
 */
26
abstract class AbstractMessageBuilder
27
{
28
    /**
29
     * Fully qualified namespace of the custom message class
30
     *
31
     * @var string
32
     */
33
    protected $messageClass;
34
35
    /**
36
     * Fully qualified names of the message meta class
37
     *
38
     * @var string
39
     */
40
    protected $messageMetaClass;
41
42
    /**
43
     * Fully qualified name of the thread class
44
     *
45
     * @var string
46
     */
47
    protected $threadClass;
48
49
    /**
50
     * Fully qualified name of the thread meta class
51
     *
52
     * @var string
53
     */
54
    protected $threadMetaClass;
55
56
    /**
57
     * Sets the message class
58
     *
59
     * @param string $messageClass Fully qualified name of message class
60
     */
61
    public function setMessageClass($messageClass)
62
    {
63
        $this->messageClass = $messageClass;
64
    }
65
66
    /**
67
     * Sets the message meta class
68
     *
69
     * @param string $messageMetaClass Fully qualified name the message meta class
70
     */
71
    public function setMessageMetaClass($messageMetaClass)
72
    {
73
        $this->messageMetaClass = $messageMetaClass;
74
    }
75
76
    /**
77
     * Sets the thread class
78
     *
79
     * @param string $threadClass Fully qualified name of the thread class
80
     */
81
    public function setThreadClass($threadClass)
82
    {
83
        $this->threadClass = $threadClass;
84
    }
85
86
    /**
87
     * Sets the thread meta class
88
     *
89
     * @param string $threadMetaClass Fully qualified name of the thread meta class
90
     */
91
    public function setThreadMetaClass($threadMetaClass)
92
    {
93
        $this->threadMetaClass = $threadMetaClass;
94
    }
95
96
    /**
97
     * Builds a new message
98
     *
99
     * @param ThreadInterface $thread
100
     */
101
    protected function buildNewMessage(ThreadInterface $thread)
102
    {
103
        //creates a blank message
104
        $message = $this->createMessage();
105
106
        //adds data to the message
107
        $this->setMessageData($message);
108
109
        //adds the thread to the message
110
        $message->setThread($thread);
111
112
        //adds the message to the thread
113
        $thread->addMessage($message);
114
115
        //sets the last message
116
        $thread->setLastMessage($message);
117
118
        //creates message meta
119
        $this->createMessageMetaForNewMessage($message);
120
    }
121
122
    /**
123
     * Creates new message meta for the participant
124
     *
125
     * @param MessageInterface     $message     The message the meta belongs
126
     * @param ParticipantInterface $participant The participant in the thread this message belongs to
127
     *
128
     * @return MessageMetaInterface
129
     */
130
    private function createNewMessageMetaForParticipant(MessageInterface $message, ParticipantInterface $participant)
131
    {
132
        //creates an empty message meta object
133
        $messageMeta = $this->createMessageMeta();
134
135
        //adds the message to the message meta
136
        $messageMeta->setMessage($message);
137
138
        //adds the participant to the message meta
139
        $messageMeta->setParticipant($participant);
140
141
        //adds the message meta to the message
142
        $message->addMessageMeta($messageMeta);
143
144
        return $messageMeta;
145
    }
146
147
    /**
148
     * Updates the message with the message data in the builder model
149
     *
150
     * @param MessageInterface $message
151
     */
152
    protected function setMessageData(MessageInterface $message)
153
    {
154
        $this->processbuilderModel('getMessageData', null, $message);
155
    }
156
157
    /**
158
     * Updates the message meta for the sender.
159
     *
160
     * It processes first the message meta for all participants
161
     * Then it processes the message meta specific for the sender
162
     *
163
     * @param MessageMetaInterface $messageMeta
164
     */
165
    protected function updateMessageMetaForSender(MessageMetaInterface $messageMeta)
166
    {
167
        $this->processBuilderModel('getMessageMeta', 'all', $messageMeta);
168
        $this->processBuilderModel('getMessageMeta', 'sender', $messageMeta);
169
    }
170
171
    /**
172
     * Updates the message meta for the recipient.
173
     *
174
     * It processes first the message meta for all participants
175
     * Then it processes the message meta specific for the recipient.
176
     *
177
     * @param MessageMetaInterface $messageMeta
178
     */
179
    protected function updateMessageMetaForRecipient(MessageMetaInterface $messageMeta)
180
    {
181
        //process the data for all participants
182
        $this->processBuilderModel('getMessageMeta', 'all', $messageMeta);
183
184
        //process the data for the recipients
185
        $this->processBuilderModel('getMessageMeta', 'recipients', $messageMeta);
186
    }
187
188
    /**
189
     * Updates the given object with the given methodName and argumentName
190
     *
191
     * @param string           $callMethodName     Calls the builder with this methodName
192
     * @param string|null      $callMethodArgument Calls the builder with this argument for the given methodName
193
     * @param BuilderInterface $object             The object which gets updated
194
     */
195
    protected function processBuilderModel($callMethodName, $callMethodArgument, BuilderInterface $object)
196
    {
197
        $data = $this->builderModel->$callMethodName($callMethodArgument);
0 ignored issues
show
The property builderModel does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
198
199
        if (!$data) {
200
            return;
201
        }
202
203
        foreach ($data as $key => $value) {
204
            $setterMethod = $this->getSetter($key, $object);
205
            $object->$setterMethod($value);
206
        }
207
    }
208
209
    /**
210
     * Gets the setter method for the given key.
211
     *
212
     * This function tries to find the setter for the given key. By convention this should be setKey.
213
     *
214
     * It checks the object if there is a method which is named setKey and if that method is callable (is public)
215
     * If not it throws an invalidArgumentException
216
     *
217
     * @param string $key
218
     * @param object $object
219
     *
220
     * @return string The callable setter method
221
     *
222
     * @throws \InvalidArgumentException If no callable setter found
223
     */
224
    protected function getSetter($key, $object)
225
    {
226
        if (!is_string($key)) {
227
            throw new \InvalidArgumentException('could not create setter method, no string given');
228
        }
229
230
        //try with setMethodName
231
        $setMethodName = 'set' . ucFirst($key);
232
233
        if (method_exists($object, $setMethodName) && is_callable([$object, $setMethodName])) {
234
            return $setMethodName;
235
        }
236
237
        throw new \InvalidArgumentException(sprintf('could not find setter for %s', $key));
238
    }
239
240
    /**
241
     * creates a new message object
242
     *
243
     * @return MessageInterface
244
     */
245
    private function createMessage()
246
    {
247
        return new $this->messageClass;
248
    }
249
250
    /**
251
     * creates a new message meta object
252
     *
253
     * @return MessageMetaInterface
254
     */
255
    private function createMessageMeta()
256
    {
257
        return new $this->messageMetaClass;
258
    }
259
260
    /**
261
     * Creates the message meta for a new message.
262
     *
263
     * @param MessageInterface $message
264
     */
265
    private function createMessageMetaForNewMessage(MessageInterface $message)
266
    {
267
        $messageMeta = $this->createNewMessageMetaForParticipant($message, $this->sender);
0 ignored issues
show
The property sender does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
268
        $this->updateMessageMetaForSender($messageMeta);
269
270
        foreach ($this->recipients as $recipient) {
0 ignored issues
show
The property recipients does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
271
            $messageMeta = $this->createNewMessageMetaForParticipant($message, $recipient);
272
            $this->updateMessageMetaForRecipient($messageMeta);
273
        }
274
    }
275
276
    /**
277
     * Updates the thread meta with settings specific for the sender
278
     *
279
     * @param ThreadMetaInterface $threadMeta
280
     */
281
    protected function updateThreadMetaForSender(ThreadMetaInterface $threadMeta)
282
    {
283
        $this->processBuilderModel('getThreadMeta', 'all', $threadMeta);
284
        $this->processBuilderModel('getThreadMeta', 'sender', $threadMeta);
285
    }
286
287
    /**
288
     * Updates the thread meta with the settings specific for the recipient
289
     *
290
     * This processes the builder model
291
     *
292
     * @param ThreadMetaInterface $threadMeta
293
     */
294
    protected function updateThreadMetaForRecipient(ThreadMetaInterface $threadMeta)
295
    {
296
        $this->processBuilderModel('getThreadMeta', 'all', $threadMeta);
297
        $this->processBuilderModel('getThreadMeta', 'recipients', $threadMeta);
298
        $this->increaseUnreadMessageCountRecipient($threadMeta);
299
        $this->maybeUpdateThreadStatusForRecipient($threadMeta);
300
    }
301
302
    /**
303
     * Increases the unread message count for the recipient.
304
     *
305
     * Since the recipient has received a new message we need to increase the unread message count for the recipient.
306
     * When it's a new thread this count should become one.
307
     * When it's a we should add +1 to the current unread count.
308
     *
309
     * @param ThreadMetaInterface $threadMeta
310
     */
311
    protected function increaseUnreadMessageCountRecipient(ThreadMetaInterface $threadMeta)
312
    {
313
        //updates the unread message count for the recipient.
314
        $previousUnreadCount = intval($threadMeta->getUnreadMessageCount());
315
        $threadMeta->setUnreadMessageCount(++$previousUnreadCount);
316
    }
317
318
    /**
319
     * If the recipient has marked his message as archived but receives a new message that message would not appear
320
     * in his inbox folder. This feels wrong since now there is an unread message count in the archived box.
321
     *
322
     * Archived also means no longer active, but receiving a new reply makes it active again. So it makes sense to put
323
     * this back in the inbox folder.
324
     *
325
     * To consider: using the thread status manager for this, since there is also an event bound to the thread status
326
     * manager which we are not receiving now...
327
     *
328
     * @param ThreadMetaInterface $threadMeta
329
     */
330
    protected function maybeUpdateThreadStatusForRecipient(ThreadMetaInterface $threadMeta)
331
    {
332
        //updates the thread meta status for the recipient
333
        //Not sure if the best way is to do this here or to use the thread status manager, this way we loose the event
334
        // but is there really a good reason we need the event?
335
        $status = $threadMeta->getStatus();
336
        if (in_array($status, [ThreadMetaInterface::STATUS_ARCHIVED], true)) {
337
            $updateStatus = new ThreadStatus(ThreadMetaInterface::STATUS_ACTIVE);
338
            $threadMeta->setStatus($updateStatus->getThreadStatus());
339
        }
340
    }
341
}
342