GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.
Completed
Push — master ( 33c34a...b1f0c4 )
by Steve
14:28
created

Audit::findPanelIdentifier()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 10
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 3.0263

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 10
ccs 6
cts 7
cp 0.8571
rs 9.4286
cc 3
eloc 6
nc 3
nop 1
crap 3.0263
1
<?php
2
/**
3
 * This serves as both the Module for the MVC part of the audit and the configuration/entry point for the actual
4
 * audit process.
5
 *
6
 * @author    Steve Guns <[email protected]>
7
 * @package   com.bedezign.yii2.audit
8
 * @copyright 2014-2015 B&E DeZign
9
 */
10
11
namespace bedezign\yii2\audit;
12
13
use bedezign\yii2\audit\components\panels\Panel;
14
use bedezign\yii2\audit\models\AuditEntry;
15
use bedezign\yii2\audit\models\AuditError;
16
use Yii;
17
use yii\base\ActionEvent;
18
use yii\base\Application;
19
use yii\base\InvalidConfigException;
20
use yii\base\InvalidParamException;
21
use yii\base\Module;
22
use yii\helpers\ArrayHelper;
23
24
/**
25
 * Audit main module.
26
 *
27
 * This module is also responsible for starting the audit process.
28
 * To configure it you need to do 2 things:
29
 * - add a module configuration entry:
30
 *     'modules' => [
31
 *        'audit' => 'bedezign\yii2\audit\Audit',
32
 *     ]
33
 *   or optionally with configuration:
34
 *     'modules' => [
35
 *        'audit' => [
36
 *            'class' => 'bedezign\yii2\audit\Audit',
37
 *            'ignoreActions' => ['debug/*']
38
 *     ]
39
 * - If you want to auto track actions, be sure to add the module to the application bootstrapping:
40
 *    'bootstrap' => ['audit'],
41
 *
42
 * @package bedezign\yii2\audit
43
 * @property AuditEntry $entry
44
 *
45
 * @method void data($type, $data)                                                                      @see ExtraDataPanel::trackData()
46
 * @method \bedezign\yii2\audit\models\AuditError exception(\Exception $exception)                      @see ErrorPanel::log()
47
 * @method \bedezign\yii2\audit\models\AuditError errorMessage($message, $code, $file, $line, $trace)   @see ErrorPanel::logMessage()
48
 */
49
class Audit extends Module
50
{
51
    /**
52
     * @var string|boolean the layout that should be applied for views within this module. This refers to a view name
53
     * relative to [[layoutPath]]. If this is not set, it means the layout value of the [[module|parent module]]
54
     * will be taken. If this is false, layout will be disabled within this module.
55
     */
56
    public $layout = 'main';
57
58
    /**
59
     * @var string name of the component to use for database access
60
     */
61
    public $db = 'db';
62
63
    /**
64
     * @var string[] Action or list of actions to track. '*' is allowed as the first or last character to use as wildcard.
65
     */
66
    public $trackActions = ['*'];
67
68
    /**
69
     * @var string[] Action or list of actions to ignore. '*' is allowed as the first or last character to use as wildcard (eg 'debug/*').
70
     */
71
    public $ignoreActions = [];
72
73
    /**
74
     * @var int Maximum age (in days) of the audit entries before they are truncated
75
     */
76
    public $maxAge = null;
77
78
    /**
79
     * @var string[] IP address or list of IP addresses with access to the viewer, null for everyone (if the IP matches)
80
     * An IP address can contain the wildcard `*` at the end so that it matches IP addresses with the same prefix.
81
     * For example, '192.168.*' matches all IP addresses in the segment '192.168.'.
82
     */
83
    public $accessIps = null;
84
85
    /**
86
     * @var string[] Role or list of roles with access to the viewer, null for everyone (if the user matches)
87
     */
88
    public $accessRoles = ['admin'];
89
90
    /**
91
     * @var int[] User ID or list of user IDs with access to the viewer, null for everyone (if the role matches)
92
     */
93
    public $accessUsers = null;
94
95
    /**
96
     * @var bool Compress extra data generated or just keep in text? For people who don't like binary data in the DB
97
     */
98
    public $compressData = true;
99
100
    /**
101
     * @var string The callback to use to convert a user id into an identifier (username, email, ...). Can also be html.
102
     */
103
    public $userIdentifierCallback = false;
104
105
    /**
106
     * @var string Will be called to translate text in the user filter into a (or more) user id's
107
     */
108
    public $userFilterCallback = false;
109
110
    /**
111
     * @var bool The module does batch saving of the data records by default. You can disable this if you are experiencing
112
     * `max_allowed_packet` errors when logging huge data quantities. Records will be saved per piece instead of all at once
113
     */
114
    public $batchSave = true;
115
116
    /**
117
     * @var array|Panel[] list of panels that should be active/tracking/available during the auditing phase.
118
     * If the value is a simple string, it is the identifier of an internal panel to activate (with default settings)
119
     * If the entry is a '<key>' => '<string>|<array>' it is either a new panel or a panel override (if you specify a core id).
120
     * It is important that the key is unique, as this is the identifier used to store any data associated with the panel.
121
     *
122
     * Please note:
123
     * - If you just want to change the configuration for a core panel, use the `$panelConfiguration`, it will be merged into this one
124
     * - If you add custom panels, please namespace them ("mynamespace/panelname").
125
     */
126
    public $panels = [
127
        'audit/request',
128
        'audit/db',
129
        'audit/log',
130
        'audit/mail',
131
        'audit/profiling',
132
        'audit/trail',
133
        'audit/javascript',
134
        // 'audit/asset',
135
        // 'audit/config',
136
137
        // These provide special functionality and get loaded to activate it
138
        'audit/error',      // Links the extra error reporting functions (`exception()` and `errorMessage()`)
139
        'audit/extra',      // Links the data functions (`data()`)
140
        'audit/curl',       // Links the curl tracking function (`curlBegin()`, `curlEnd()` and `curlExec()`)
141
    ];
142
143
    /**
144
     * Everything you add in here will be merged with the basic panel configuration.
145
     * This gives you an easy way to just add or modify panels/configurations without having to re-specify every panel.
146
     * This only accepts regular definitions ('<key>' => '<array>'), but the core class will be added if needed
147
     * Take a look at the [module configuration](docs/module-configuration.md) for more information.
148
     */
149
    public $panelsMerge = [];
150
151
    /**
152
     * @var LogTarget
153
     */
154
    public $logTarget;
155
156
    /**
157
     * @var array
158
     */
159
    private $_corePanels = [
160
        // Tracking/logging panels
161
        'audit/request'    => ['class' => 'bedezign\yii2\audit\panels\RequestPanel'],
162
        'audit/db'         => ['class' => 'bedezign\yii2\audit\panels\DbPanel'],
163
        'audit/log'        => ['class' => 'bedezign\yii2\audit\panels\LogPanel'],
164
        'audit/asset'      => ['class' => 'bedezign\yii2\audit\panels\AssetPanel'],
165
        'audit/config'     => ['class' => 'bedezign\yii2\audit\panels\ConfigPanel'],
166
        'audit/profiling'  => ['class' => 'bedezign\yii2\audit\panels\ProfilingPanel'],
167
168
        // Special other panels
169
        'audit/error'      => ['class' => 'bedezign\yii2\audit\panels\ErrorPanel'],
170
        'audit/javascript' => ['class' => 'bedezign\yii2\audit\panels\JavascriptPanel'],
171
        'audit/trail'      => ['class' => 'bedezign\yii2\audit\panels\TrailPanel'],
172
        'audit/mail'       => ['class' => 'bedezign\yii2\audit\panels\MailPanel'],
173
        'audit/extra'      => ['class' => 'bedezign\yii2\audit\panels\ExtraDataPanel'],
174
        'audit/curl'       => ['class' => 'bedezign\yii2\audit\panels\CurlPanel'],
175
        'audit/soap'       => ['class' => 'bedezign\yii2\audit\panels\SoapPanel'],
176
    ];
177
178
    /**
179
     * @var array
180
     */
181
    private $_panelFunctions = [];
182
183
    /**
184
     * @var \bedezign\yii2\audit\models\AuditEntry If activated this is the active entry
185
     */
186
    private $_entry = null;
187
188
    /**
189
     * @throws InvalidConfigException
190
     */
191 114
    public function init()
192
    {
193 114
        parent::init();
194 114
        $app = Yii::$app;
195
196
        // Before action triggers a new audit entry
197 114
        $app->on(Application::EVENT_BEFORE_ACTION, [$this, 'onBeforeAction']);
198
        // After request finalizes the audit entry.
199 114
        $app->on(Application::EVENT_AFTER_REQUEST, [$this, 'onAfterRequest']);
200
201
        // Activate the logging target
202 114
        $this->logTarget = $app->getLog()->targets['audit'] = new LogTarget($this);
203
204
        // Boot all active panels
205 114
        $this->normalizePanelConfiguration();
206 114
        $this->panels = $this->loadPanels(array_keys($this->panels));
207 114
    }
208
209
    /**
210
     * Called to evaluate if the current request should be logged
211
     * @param ActionEvent $event
212
     */
213 55
    public function onBeforeAction($event)
214
    {
215 43
        if (!empty($this->trackActions) && !$this->routeMatches($event->action->uniqueId, $this->trackActions)) {
216 9
            return;
217
        }
218 34
        if (!empty($this->ignoreActions) && $this->routeMatches($event->action->uniqueId, $this->ignoreActions)) {
219 42
            return;
220
        }
221
        // Still here, start audit
222 14
        $this->getEntry(true);
223 40
    }
224
225
    /**
226
     *
227
     */
228 50
    public function onAfterRequest()
229
    {
230 50
        if ($this->_entry) {
231 18
            $this->_entry->finalize();
232 18
        }
233 50
    }
234
235
    /**
236
     * Allows panels to register functions that can be called directly on the module
237
     * @param string    $name
238
     * @param callable  $callback
239
     */
240 114
    public function registerFunction($name, $callback)
241
    {
242 114
        if (isset($this->_panelFunctions[$name]))
243 114
            throw new InvalidParamException("The '$name'-function has already been defined.");
244
245 114
        $this->_panelFunctions[$name] = $callback;
246 114
    }
247
248
    /**
249
     * @param \yii\debug\Panel $panel
250
     */
251
    public function registerPanel(\yii\debug\Panel $panel)
252
    {
253
        $this->panels[$panel->id] = $panel;
254
    }
255
256
    /**
257
     * @param string $name
258
     * @param array $params
259
     * @return mixed
260
     */
261 21
    public function __call($name, $params)
262
    {
263 21
        if (!isset($this->_panelFunctions[$name]))
264 7
            throw new \yii\base\InvalidCallException("Unknown panel function '$name'");
265
266 7
        return call_user_func_array($this->_panelFunctions[$name], $params);
267
    }
268
269
    /**
270
     * @return \yii\db\Connection the database connection.
271
     */
272 71
    public function getDb()
273
    {
274 71
        return Yii::$app->{$this->db};
275
    }
276
277
    /**
278
     * @param bool $create
279
     * @param bool $new
280
     * @return AuditEntry|static
281
     */
282 92
    public function getEntry($create = false, $new = false)
283
    {
284 92
        if ((!$this->_entry && $create) || $new) {
285 40
            $this->_entry = AuditEntry::create(true);
286 40
        }
287 92
        return $this->_entry;
288 32
    }
289
290
    /**
291
     * @param $user_id
292
     * @return string
293
     */
294 14
    public function getUserIdentifier($user_id)
295
    {
296 14
        if (!$user_id) {
297
            return Yii::t('audit', 'Guest');
298
        }
299 12
        if ($this->userIdentifierCallback && is_callable($this->userIdentifierCallback)) {
300 1
            return call_user_func($this->userIdentifierCallback, $user_id);
301
        }
302 11
        return $user_id;
303
    }
304
305
    /**
306
     * Returns a list of all available panel identifiers
307
     * @return string[]
308
     */
309 1
    public function getPanelIdentifiers()
310
    {
311 1
        return array_unique(array_merge(array_keys($this->panels), array_keys($this->_corePanels)));
312
    }
313
314
    /**
315
     * Tries to assemble the configuration for the panels that the user wants for auditing
316
     * @param string[]          Set of panel identifiers that should be loaded
317
     * @return Panel[]
318
     */
319 114
    public function loadPanels($list)
320
    {
321 114
        $panels = [];
322 114
        foreach ($list as $panel) {
323 114
            $panels[$panel] = $this->getPanel($panel);
324 114
        }
325 114
        return $panels;
326
    }
327
328
    /**
329
     * @param string $identifier
330
     * @return null|Panel
331
     * @throws InvalidConfigException
332
     */
333 142
    public function getPanel($identifier)
334
    {
335 114
        $config = null;
336 114
        if (isset($this->panels[$identifier]))
337 114
            $config = $this->panels[$identifier];
338 1
        elseif (isset($this->_corePanels[$identifier]))
339 1
            $config = $this->_corePanels[$identifier];
340
341 114
        if (!$config)
342 114
            throw new InvalidConfigException("'$identifier' is not a valid panel identifier");
343
344 114
        if (is_array($config)) {
345 114
            $config['module'] = $this;
346 114
            $config['id'] = $identifier;
347 114
            return Yii::createObject($config);
348
        }
349
350 46
        return $config;
351
    }
352
353
    /**
354
     * Make sure the configured panels array is a uniform set of <identifier> => <config> entries.
355
     * @throws InvalidConfigException
356
     */
357 114
    protected function normalizePanelConfiguration()
358
    {
359 114
        $panels = [];
360 114
        foreach ($this->panels as $key => $value) {
361 114
            if (is_numeric($key)) {
362
                // The $value contains the identifier of a core panel
363 114
                if (!isset($this->_corePanels[$value]))
364 114
                    throw new InvalidConfigException("'$value' is not a valid panel identifier");
365 114
                $panels[$value] = $this->_corePanels[$value];
366 114
            }
367
            else {
368
                // The key contains the identifier and the value is either a class name or a full array
369
                $panels[$key] = is_string($value) ? ['class' => $value] : $value;
370
            }
371 114
        }
372 114
        $this->panels = ArrayHelper::merge($panels, $this->panelsMerge);
373
374
        // We now need one more iteration to add core classes to the panels added via the merge, if needed
375 114
        array_walk($this->panels, function(&$value, $key) {
376 114
           if (!isset($value['class'])) {
377
               if (isset($this->_corePanels[$key]))
378
                   $value = ArrayHelper::merge($value, $this->_corePanels[$key]);
379
               else
380
                   throw new InvalidConfigException("Invalid configuration for '$key'. No 'class' specified.");
381
           }
382 114
        });
383 114
    }
384
385
    /**
386
     * @return int|null|string
387
     */
388 118
    public static function findModuleIdentifier()
389
    {
390 114
        foreach (Yii::$app->modules as $name => $module) {
391 114
            $class = null;
392 114
            if (is_string($module))
393 114
                $class = $module;
394 114
            elseif (is_array($module)) {
395 114
                if (isset($module['class']))
396 114
                    $class = $module['class'];
397 114
            } else
398
                /** @var Module $module */
399 1
                $class = $module::className();
400
401 114
            $parts = explode('\\', $class);
402 114
            if ($class && strtolower(end($parts)) == 'audit')
403 114
                return $name;
404 2
        }
405 6
        return null;
406
    }
407
408
    /**
409
     * @param string $className
410
     * @return bool|string
411
     */
412 27
    public static function findPanelIdentifier($className)
413
    {
414 9
        $audit = Audit::getInstance();
415 27
        foreach ($audit->panels as $panel) {
416 9
            if ($panel->className() == $className) {
417 27
                return $panel->id;
418
            }
419 9
        }
420
        return false;
421
    }
422
423
    /**
424
     * Verifies a route against a given list and returns whether it matches or not.
425
     * Entries in the list are allowed to end with a '*', which means that a substring will be used for the match
426
     * instead of a full compare.
427
     *
428
     * @param string $route An application rout
429
     * @param string[] $list List of routes to compare against.
430
     * @return bool
431
     */
432 67
    protected function routeMatches($route, $list)
433
    {
434 29
        $list = ArrayHelper::toArray($list);
435 29
        foreach ($list as $compare) {
436 29
            $len = strlen($compare);
437 57
            if ($compare[$len - 1] == '*') {
438 19
                $compare = rtrim($compare, '*');
439 19
                if (substr($route, 0, $len - 1) === $compare)
440 25
                    return true;
441 9
            }
442
443 65
            if ($compare[0] == '*') {
444 6
                $compare = ltrim($compare, '*');
445 6
                if (substr($route, - ($len - 1)) === $compare)
446 14
                    return true;
447 2
            }
448
449 53
            if ($route === $compare)
450 27
                return true;
451 37
        }
452 39
        return false;
453
    }
454
455
}
456