Issues (2)

Security Analysis    no request data  

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.

src/SagaModule.php (1 issue)

Labels
Severity
1
<?php
2
3
/**
4
 * Saga pattern implementation module.
5
 *
6
 * @author  Maksim Masiukevich <[email protected]>
7
 * @license MIT
8
 * @license https://opensource.org/licenses/MIT
9
 */
10
11
declare(strict_types = 1);
12
13
namespace ServiceBus\Sagas\Module;
14
15
use ServiceBus\AnnotationsReader\Reader;
16
use ServiceBus\Mutex\InMemory\InMemoryMutexFactory;
17
use function ServiceBus\Common\canonicalizeFilesPath;
18
use function ServiceBus\Common\extractNamespaceFromFile;
19
use function ServiceBus\Common\searchFiles;
20
use ServiceBus\Common\Module\ServiceBusModule;
21
use ServiceBus\MessagesRouter\ChainRouterConfigurator;
22
use ServiceBus\MessagesRouter\Router;
23
use ServiceBus\Mutex\MutexFactory;
24
use ServiceBus\Sagas\Configuration\Annotations\SagaAnnotationBasedConfigurationLoader;
25
use ServiceBus\Sagas\Configuration\DefaultEventListenerProcessorFactory;
26
use ServiceBus\Sagas\Configuration\EventListenerProcessorFactory;
27
use ServiceBus\Sagas\Configuration\SagaConfigurationLoader;
28
use ServiceBus\Sagas\Saga;
29
use ServiceBus\Sagas\Store\SagasStore;
30
use ServiceBus\Sagas\Store\Sql\SQLSagaStore;
31
use ServiceBus\Storage\Common\DatabaseAdapter;
32
use Symfony\Component\DependencyInjection\ContainerBuilder;
33
use Symfony\Component\DependencyInjection\Definition;
34
use Symfony\Component\DependencyInjection\Reference;
35
36
/**
37
 *
38
 */
39
final class SagaModule implements ServiceBusModule
40
{
41
    /** @var string */
42
    private $sagaStoreServiceId;
43
44
    /** @var string */
45
    private $databaseAdapterServiceId;
46
47
    /**
48
     * @psalm-var array<array-key, class-string<\ServiceBus\Sagas\Saga>>
49
     *
50
     * @var array
51
     */
52
    private $sagasToRegister = [];
53
54
    /** @var string|null */
55
    private $configurationLoaderServiceId;
56
57
    /**
58
     * @param string|null $configurationLoaderServiceId If not specified, the default annotation-based configurator
59
     *                                                  will be used
60
     *
61
     * @throws \LogicException The component "php-service-bus/storage-sql" was not installed
62
     * @throws \LogicException The component "php-service-bus/annotations-reader" was not installed
63
     */
64 11
    public static function withSqlStorage(
65
        string $databaseAdapterServiceId,
66
        ?string $configurationLoaderServiceId = null
67
    ): self {
68 11
        if (false === \interface_exists(DatabaseAdapter::class))
69
        {
70
            throw new \LogicException('The component "php-service-bus/storage-sql" was not installed');
71
        }
72
73 11
        if (null === $configurationLoaderServiceId && false === \interface_exists(Reader::class))
74
        {
75
            throw new \LogicException('The component "php-service-bus/annotations-reader" was not installed');
76
        }
77
78 11
        return new self(
79 11
            SQLSagaStore::class,
80
            $databaseAdapterServiceId,
81
            $configurationLoaderServiceId
82
        );
83
    }
84
85
    /**
86
     * @param string|null $configurationLoaderServiceId If not specified, the default annotation-based configurator
87
     *                                                  will be used
88
     *
89
     * @throws \LogicException The component "php-service-bus/annotations-reader" was not installed
90
     */
91 1
    public static function withCustomStore(
92
        string $storeImplementationServiceId,
93
        string $databaseAdapterServiceId,
94
        ?string $configurationLoaderServiceId = null
95
    ): self {
96 1
        if (null === $configurationLoaderServiceId && false === \interface_exists(Reader::class))
97
        {
98
            throw new \LogicException('The component "php-service-bus/annotations-reader" was not installed');
99
        }
100
101 1
        return new self(
102 1
            $storeImplementationServiceId,
103
            $databaseAdapterServiceId,
104
            $configurationLoaderServiceId
105
        );
106
    }
107
108
    /**
109
     * All sagas from the specified directories will be registered automatically.
110
     *
111
     * @noinspection PhpDocMissingThrowsInspection
112
     *
113
     * Note: All files containing user-defined functions must be excluded
114
     * Note: Increases start time because of the need to scan files
115
     *
116
     * @psalm-param  array<array-key, string> $directories
117
     * @psalm-param  array<array-key, string> $excludedFiles
118
     */
119 10
    public function enableAutoImportSagas(array $directories, array $excludedFiles = []): self
120
    {
121 10
        $excludedFiles = canonicalizeFilesPath($excludedFiles);
122 10
        $files         = searchFiles($directories, '/\.php/i');
123
124
        /** @var \SplFileInfo $file */
125 10
        foreach ($files as $file)
126
        {
127 10
            $filePath = $file->getRealPath();
0 ignored issues
show
The method getRealPath() does not exist on RegexIterator. ( 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
            $filePath = $file->getRealPath();

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...
128
129 10
            if (false === $filePath || true === \in_array($filePath, $excludedFiles, true))
130
            {
131
                continue;
132
            }
133
134
            /** @noinspection PhpUnhandledExceptionInspection */
135 10
            $class = extractNamespaceFromFile($filePath);
136
137 10
            if (null !== $class && true === \is_a($class, Saga::class, true))
138
            {
139
                /** @psalm-var class-string<\ServiceBus\Sagas\Saga> $class */
140
141 10
                $this->configureSaga($class);
142
            }
143
        }
144
145 10
        return $this;
146
    }
147
148
    /**
149
     * Enable sagas.
150
     *
151
     * @psalm-param array<array-key, class-string<\ServiceBus\Sagas\Saga>> $sagas
152
     */
153
    public function configureSagas(array $sagas): self
154
    {
155
        foreach ($sagas as $saga)
156
        {
157
            $this->configureSaga($saga);
158
        }
159
160
        return $this;
161
    }
162
163
    /**
164
     * Enable specified saga.
165
     *
166
     * @psalm-param class-string<\ServiceBus\Sagas\Saga> $sagaClass
167
     */
168 11
    public function configureSaga(string $sagaClass): self
169
    {
170 11
        $this->sagasToRegister[\sha1($sagaClass)] = $sagaClass;
171
172 11
        return $this;
173
    }
174
175
    /**
176
     * {@inheritdoc}
177
     */
178 12
    public function boot(ContainerBuilder $containerBuilder): void
179
    {
180 12
        $containerBuilder->setParameter('service_bus.sagas.list', $this->sagasToRegister);
181
182 12
        $this->registerSagaStore($containerBuilder);
183 12
        $this->registerMutexFactory($containerBuilder);
184 12
        $this->registerSagasProvider($containerBuilder);
185
186 12
        if ($this->configurationLoaderServiceId === null)
187
        {
188 12
            $this->registerDefaultConfigurationLoader($containerBuilder);
189
190 12
            $this->configurationLoaderServiceId = SagaConfigurationLoader::class;
191
        }
192
193 12
        $this->registerRoutesConfigurator($containerBuilder);
194 12
    }
195
196 12
    private function registerMutexFactory(ContainerBuilder $containerBuilder): void
197
    {
198 12
        if ($containerBuilder->hasDefinition(MutexFactory::class) === false)
199
        {
200 12
            $containerBuilder->setDefinition(MutexFactory::class, new Definition(InMemoryMutexFactory::class));
201
        }
202 12
    }
203
204 12
    private function registerRoutesConfigurator(ContainerBuilder $containerBuilder): void
205
    {
206 12
        if ($containerBuilder->hasDefinition(ChainRouterConfigurator::class) === false)
207
        {
208 12
            $containerBuilder->setDefinition(ChainRouterConfigurator::class, new Definition(ChainRouterConfigurator::class));
209
        }
210
211 12
        $routerConfiguratorDefinition = $containerBuilder->getDefinition(ChainRouterConfigurator::class);
212
213 12
        if ($containerBuilder->hasDefinition(Router::class) === false)
214
        {
215 12
            $containerBuilder->setDefinition(Router::class, new Definition(Router::class));
216
        }
217
218 12
        $routerDefinition = $containerBuilder->getDefinition(Router::class);
219 12
        $routerDefinition->setConfigurator(
220 12
            [new Reference(ChainRouterConfigurator::class), 'configure']
221
        );
222
223 12
        $sagaRoutingConfiguratorDefinition = (new Definition(SagaMessagesRouterConfigurator::class))
224 12
            ->setArguments([
225 12
                new Reference(SagasProvider::class),
226 12
                new Reference(SagaConfigurationLoader::class),
227 12
                '%service_bus.sagas.list%',
228
            ]);
229
230 12
        $containerBuilder->setDefinition(SagaMessagesRouterConfigurator::class, $sagaRoutingConfiguratorDefinition);
231
232 12
        $routerConfiguratorDefinition->addMethodCall(
233 12
            'addConfigurator',
234 12
            [new Reference(SagaMessagesRouterConfigurator::class)]
235
        );
236 12
    }
237
238 12
    private function registerSagasProvider(ContainerBuilder $containerBuilder): void
239
    {
240 12
        $sagasProviderDefinition = (new Definition(SagasProvider::class))
241 12
            ->setArguments(
242
                [
243 12
                    new Reference(SagasStore::class),
244 12
                    new Reference(MutexFactory::class)
245
                ]
246
            );
247
248 12
        $containerBuilder->setDefinition(SagasProvider::class, $sagasProviderDefinition);
249 12
    }
250
251 12
    private function registerSagaStore(ContainerBuilder $containerBuilder): void
252
    {
253 12
        if ($containerBuilder->hasDefinition(SagasStore::class) === true)
254
        {
255
            return;
256
        }
257
258 12
        $sagaStoreDefinition = (new Definition($this->sagaStoreServiceId))
259 12
            ->setArguments([new Reference($this->databaseAdapterServiceId)]);
260
261 12
        $containerBuilder->setDefinition(SagasStore::class, $sagaStoreDefinition);
262 12
    }
263
264 12
    private function registerDefaultConfigurationLoader(ContainerBuilder $containerBuilder): void
265
    {
266 12
        if ($containerBuilder->hasDefinition(SagaConfigurationLoader::class) === true)
267
        {
268
            return;
269
        }
270
271 12
        if ($containerBuilder->hasDefinition(EventListenerProcessorFactory::class) === true)
272
        {
273
            return;
274
        }
275
276
        /** Event listener factory */
277 12
        $listenerFactoryDefinition = (new Definition(DefaultEventListenerProcessorFactory::class))
278 12
            ->setArguments([new Reference(SagasStore::class)]);
279
280 12
        $containerBuilder->setDefinition(EventListenerProcessorFactory::class, $listenerFactoryDefinition);
281
282
        /** Configuration loader */
283 12
        $configurationLoaderDefinition = (new Definition(SagaAnnotationBasedConfigurationLoader::class))
284 12
            ->setArguments([new Reference(EventListenerProcessorFactory::class)]);
285
286 12
        $containerBuilder->setDefinition(SagaConfigurationLoader::class, $configurationLoaderDefinition);
287
288 12
        $this->configurationLoaderServiceId = SagaConfigurationLoader::class;
289 12
    }
290
291 12
    private function __construct(
292
        string $sagaStoreServiceId,
293
        string $databaseAdapterServiceId,
294
        ?string $configurationLoaderServiceId = null
295
    ) {
296 12
        $this->sagaStoreServiceId           = $sagaStoreServiceId;
297 12
        $this->databaseAdapterServiceId     = $databaseAdapterServiceId;
298 12
        $this->configurationLoaderServiceId = $configurationLoaderServiceId;
299 12
    }
300
}
301