Issues (608)

Security Analysis    not enabled

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.

class/Plugin.php (2 issues)

1
<?php
2
3
namespace XoopsModules\Oledrion;
4
5
/*
6
 You may not change or alter any portion of this comment or credits
7
 of supporting developers from this source code or any supporting source code
8
 which is considered copyrighted (c) material of the original comment or credit authors.
9
10
 This program is distributed in the hope that it will be useful,
11
 but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13
*/
14
15
/**
16
 * oledrion
17
 *
18
 * @copyright   {@link https://xoops.org/ XOOPS Project}
19
 * @license     {@link http://www.fsf.org/copyleft/gpl.html GNU public license}
20
 * @author      Hervé Thouzard (http://www.herve-thouzard.com/)
21
 */
22
23
use XoopsModules\Oledrion;
24
25
/**
26
 * Gestion des plugins du module
27
 *
28
 * On distingue les "filtres" (plugin qui reçoit du contenu qu'il peut modifier et dont le retour est passé au filtre suivant)
29
 * des "actions" (plugin qui est généralement appelé sur un évènement et qui ne doit rien modifier).
30
 *
31
 * Chaque plugin dispose d'une priorité de 1 à 5, 1 étant la priorité la plus haute, 5 la plus basse
32
 *
33
 * Dans le répertoire plugins on a 2 sous répertoires, "actions" et "filters", en fonction du type du plugin
34
 *
35
 * Chaque plugin doit se trouver dans son propre sous-répertoire, par exemple :
36
 *     /xoops/modules/oledrion/plugins/pdf/
37
 *
38
 * Cela permet aux plugins d'avoir plusieurs fichiers et de ne pas les mélanger avec les autres plugins
39
 *
40
 * Le module scrute ces 2 répertoires ("actions" et "filters") pour charger les plugins.
41
 * Chaque répertoire doit contenir un script "plugins.php" qui permet la descriptions des plugins qui se trouvent dans ce répertoire.
42
 * A titre d'exemple, voir ceux fournits de base avec le module
43
 *
44
 * Les modèles de classe à étendre se trouvent dans /xoops/modules/oledrion/plugins/modules/oledrion_action.php et OledrionFilter.php
45
 *
46
 * @since 2.31
47
 */
48
class Plugin
49
{
50
    /**
51
     * Dictionnaire des évènements
52
     */
53
    const EVENT_ON_PRODUCT_CREATE = 'onProductCreate';
54
    const EVENT_ON_CATEGORY_CREATE = 'onCategoryCreate';
55
    const EVENT_ON_PRODUCT_DOWNLOAD = 'onProductDownload';
56
    // **************************************************************
57
58
    /**
59
     * Types d'évènements
60
     */
61
    const PLUGIN_ACTION = 0;
62
    const PLUGIN_FILTER = 1;
63
64
    /**
65
     * Nom du script Php inclut qui contient l'inscription des plugins
66
     */
67
    const PLUGIN_SCRIPT_NAME = 'plugins.php';
68
69
    /**
70
     * Dans le fichier Php qui contient l'inscription des plugins, méthode à appeler pour récupérer la liste des plugins
71
     */
72
    const PLUGIN_DESCRIBE_METHOD = 'registerEvents';
73
74
    /**
75
     * Nom de la variable de session qui contient la liste des plugins détachés
76
     */
77
    const PLUGIN_UNPLUG_SESSION_NAME = 'oledrion_plugins';
78
79
    /**
80
     * Priorités des plugins
81
     */
82
    const EVENT_PRIORITY_1 = 1; // Priorité la plus haute
83
    const EVENT_PRIORITY_2 = 2;
84
    const EVENT_PRIORITY_3 = 3;
85
    const EVENT_PRIORITY_4 = 4;
86
    const EVENT_PRIORITY_5 = 5; // Priorité la plus basse
87
88
    /**
89
     * Utilisé pour construire le nom de la classe
90
     */
91
    private $pluginsTypeLabel = [self::PLUGIN_ACTION => 'Action', self::PLUGIN_FILTER => 'Filter'];
92
93
    /**
94
     * Nom des classes qu'il faut étendre en tant que plugin
95
     */
96
    private $pluginsClassName = [
97
        self::PLUGIN_ACTION => 'oledrion_action',
98
        self::PLUGIN_FILTER => 'oledrion_filter',
99
    ];
100
101
    /**
102
     * Nom de chacun des dossiers en fonction du type de plugin
103
     */
104
    private $pluginsTypesFolder = [self::PLUGIN_ACTION => 'actions', self::PLUGIN_FILTER => 'filters'];
105
106
    /**
107
     * Contient l'unique instance de l'objet
108
     * @var Plugin
109
     */
110
    private static $instance = false;
0 ignored issues
show
The private property $instance is not used, and could be removed.
Loading history...
111
112
    /**
113
     * Liste des évènements
114
     * @var array
115
     */
116
    private static $events = [];
117
118
    /**
119
     * Retourne l'instance unique de la classe
120
     *
121
     * @return Plugin
122
     */
123
    public static function getInstance()
124
    {
125
        static $instance;
126
        if (null === $instance) {
127
            $instance = new static();
128
        }
129
130
        return $instance;
131
    }
132
133
    /**
134
     * Chargement des 2 types de plugins
135
     */
136
    private function __construct()
137
    {
138
        $this->events = [];
139
        $this->loadPlugins();
140
    }
141
142
    /**
143
     * Chargement des plugins (actions et filtres)
144
     */
145
    public function loadPlugins()
146
    {
147
        $this->loadPluginsFiles(OLEDRION_PLUGINS_PATH . $this->pluginsTypesFolder[self::PLUGIN_ACTION], self::PLUGIN_ACTION);
148
        $this->loadPluginsFiles(OLEDRION_PLUGINS_PATH . $this->pluginsTypesFolder[self::PLUGIN_FILTER], self::PLUGIN_FILTER);
149
    }
150
151
    /**
152
     * Vérifie que le fichier Php passé en paramètre contient bien une classe de filtre ou d'action et si c'est le cas, le charge dans la liste des plugins
153
     * @param  string $fullPathName Chemin complet vers le fichier (répertoire + nom)
154
     * @param int     $type         Type de plugin recherché (action ou filtre)
155
     * @param  string $pluginFolder Le nom du répertoire dans lequel se trouve le fichier (le "dernier nom")
156
     */
157
    private function loadClass($fullPathName, $type, $pluginFolder)
158
    {
159
        require_once $fullPathName;
160
        $className = mb_strtolower($pluginFolder) . $this->pluginsTypeLabel[$type];
161
        if (class_exists($className) && get_parent_class($className) == $this->pluginsClassName[$type]) {
162
            // TODO: Check that the event is not already in memory
163
            $events = call_user_func([$className, self::PLUGIN_DESCRIBE_METHOD]);
164
            foreach ($events as $event) {
165
                $eventName                                         = $event[0];
166
                $eventPriority                                     = $event[1];
167
                $fileToInclude                                     = OLEDRION_PLUGINS_PATH . $this->pluginsTypesFolder[$type] . '/' . $pluginFolder . '/' . $event[2];
168
                $classToCall                                       = $event[3];
169
                $methodToCall                                      = $event[4];
170
                $this->events[$type][$eventName][$eventPriority][] = [
171
                    'fullPathName' => $fileToInclude,
172
                    'className'    => $classToCall,
173
                    'method'       => $methodToCall,
174
                ];
175
            }
176
        }
177
    }
178
179
    /**
180
     * Part à la recherche d'un type de plugin dans les répertoires
181
     *
182
     * @param  string $path La racine
183
     * @param int     $type Le type de plugin recherché (action ou filtre)
184
     */
185
    private function loadPluginsFiles($path, $type)
186
    {
187
        $objects = new \DirectoryIterator($path);
188
        foreach ($objects as $object) {
189
            if ($object->isDir() && !$object->isDot()) {
190
                $file = $path . '/' . $object->current() . '/' . self::PLUGIN_SCRIPT_NAME;
191
                if (file_exists($file)) {
192
                    $this->loadClass($file, $type, $object->current());
193
                }
194
            }
195
        }
196
    }
197
198
    /**
199
     * Déclenchement d'une action et appel des plugins liés
200
     *
201
     * @param  string     $eventToFire L'action déclenchée
202
     * @param  Parameters $parameters  Les paramètres à passer à chaque plugin
203
     * @return Plugin                     L'objet lui même pour chaîner
204
     */
205
    public function fireAction($eventToFire, Parameters $parameters = null)
206
    {
207
        if (!isset($this->events[self::PLUGIN_ACTION][$eventToFire])) {
208
            trigger_error(sprintf(_OLEDRION_PLUGINS_ERROR_1, $eventToFire));
209
210
            return $this;
211
        }
212
        ksort($this->events[self::PLUGIN_ACTION][$eventToFire]); // Tri par priorité
213
        foreach ($this->events[self::PLUGIN_ACTION][$eventToFire] as $priority => $events) {
214
            foreach ($events as $event) {
215
                if ($this->isUnplug(self::PLUGIN_ACTION, $eventToFire, $event['fullPathName'], $event['className'], $event['method'])) {
216
                    continue;
217
                }
218
                require_once $event['fullPathName'];
219
                if (!class_exists($event['className'])) {
220
                    $class = new $event['className']();
221
                }
222
                if (!method_exists($event['className'], $event['method'])) {
223
                    continue;
224
                }
225
                call_user_func([$event['className'], $event['method']], $parameters);
226
                unset($class);
227
            }
228
        }
229
230
        return $this;
231
    }
232
233
    /**
234
     * Triggering a filter and calling linked plugins
235
     *
236
     * @param  string          $eventToFire The called filter
237
     * @param  Parameters|null $parameters  The parameters to be passed to each plugin
238
     * @return Parameters|Plugin            The content of the object passed as parameter
239
     */
240
    public function fireFilter($eventToFire, Parameters $parameters = null)
241
    {
242
        if (!isset($this->events[self::PLUGIN_FILTER][$eventToFire])) {
243
            trigger_error(sprintf(_OLEDRION_PLUGINS_ERROR_1, $eventToFire));
244
245
            return $this;
246
        }
247
        ksort($this->events[self::PLUGIN_FILTER][$eventToFire]); // Sort by priority
248
        foreach ($this->events[self::PLUGIN_FILTER][$eventToFire] as $priority => $events) {
249
            foreach ($events as $event) {
250
                if ($this->isUnplug(self::PLUGIN_FILTER, $eventToFire, $event['fullPathName'], $event['className'], $event['method'])) {
251
                    continue;
252
                }
253
                require_once $event['fullPathName'];
254
                if (!class_exists($event['className'])) {
255
                    $class = new $event['className']();
256
                }
257
                if (!method_exists($event['className'], $event['method'])) {
258
                    continue;
259
                }
260
                call_user_func([$event['className'], $event['method']], $parameters);
261
                unset($class);
262
            }
263
        }
264
265
        if (null !== $parameters) {
266
            return $parameters;
267
        }
268
    }
269
270
    /**
271
     * Indique si un plugin s'est détaché d'un évènement particulier
272
     *
273
     * @param int     $eventType
274
     * @param  string $eventToFire
275
     * @param  string $fullPathName
276
     * @param  string $className
277
     * @param  string $method
278
     * @return bool
279
     */
280
    public function isUnplug($eventType, $eventToFire, $fullPathName, $className, $method)
281
    {
282
        $unplug = [];
0 ignored issues
show
The assignment to $unplug is dead and can be removed.
Loading history...
283
        if (isset($_SESSION[self::PLUGIN_UNPLUG_SESSION_NAME])) {
284
            $unplug = $_SESSION[self::PLUGIN_UNPLUG_SESSION_NAME];
285
        } else {
286
            return false;
287
        }
288
289
        return isset($unplug[$eventType][$eventToFire][$fullPathName][$className][$method]);
290
    }
291
292
    /**
293
     * Permet à un plugin de se détacher d'un évènement
294
     *
295
     * @param int     $eventType
296
     * @param  string $eventToFire
297
     * @param  string $fullPathName
298
     * @param  string $className
299
     * @param  string $method
300
     */
301
    public function unplugFromEvent($eventType, $eventToFire, $fullPathName, $className, $method)
302
    {
303
        $unplug = [];
304
        if (isset($_SESSION[self::PLUGIN_UNPLUG_SESSION_NAME])) {
305
            $unplug = $_SESSION[self::PLUGIN_UNPLUG_SESSION_NAME];
306
        }
307
        $unplug[$eventType][$eventToFire][$fullPathName][$className][$method] = true;
308
        $_SESSION[self::PLUGIN_UNPLUG_SESSION_NAME]                           = $unplug;
309
    }
310
}
311