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 ( db2f26...08e4d5 )
by Brett
03:11
created

Audit::getEntry()   B

Complexity

Conditions 5
Paths 3

Size

Total Lines 11
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 5

Importance

Changes 1
Bugs 1 Features 0
Metric Value
cc 5
eloc 7
c 1
b 1
f 0
nc 3
nop 2
dl 0
loc 11
ccs 6
cts 6
cp 1
crap 5
rs 8.8571
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 280
    public function init()
192
    {
193 114
        parent::init();
194 280
        $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 54
    public function onBeforeAction($event)
214
    {
215 42
        if (!empty($this->trackActions) && !$this->routeMatches($event->action->uniqueId, $this->trackActions)) {
216 9
            return;
217
        }
218 33
        if (!empty($this->ignoreActions) && $this->routeMatches($event->action->uniqueId, $this->ignoreActions)) {
219 42
            return;
220
        }
221
        // Still here, start audit
222 13
        $this->getEntry(true);
223 39
    }
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 70
    public function getDb()
273
    {
274 70
        return Yii::$app->{$this->db};
275
    }
276
277
    /**
278
     * @param bool $create
279
     * @param bool $new
280
     * @return AuditEntry|static
281
     */
282 91
    public function getEntry($create = false, $new = false)
283
    {
284 91
        $entry = new AuditEntry();
285 39
        $tableSchema = $entry->getDb()->schema->getTableSchema($entry->tableName());
286 39
        if ($tableSchema) {
287 91
            if ((!$this->_entry && $create) || $new) {
288 32
                $this->_entry = AuditEntry::create(true);
289
            }
290
        }
291
        return $this->_entry;
292
    }
293
294 14
    /**
295
     * @param $user_id
296 14
     * @return string
297
     */
298
    public function getUserIdentifier($user_id)
299 12
    {
300 1
        if (!$user_id) {
301
            return Yii::t('audit', 'Guest');
302 11
        }
303
        if ($this->userIdentifierCallback && is_callable($this->userIdentifierCallback)) {
304
            return call_user_func($this->userIdentifierCallback, $user_id);
305
        }
306
        return $user_id;
307
    }
308
309 1
    /**
310
     * Returns a list of all available panel identifiers
311 1
     * @return string[]
312
     */
313
    public function getPanelIdentifiers()
314
    {
315
        return array_unique(array_merge(array_keys($this->panels), array_keys($this->_corePanels)));
316
    }
317
318
    /**
319 280
     * Tries to assemble the configuration for the panels that the user wants for auditing
320
     * @param string[]          Set of panel identifiers that should be loaded
321 280
     * @return Panel[]
322 114
     */
323 114
    public function loadPanels($list)
324 114
    {
325 280
        $panels = [];
326
        foreach ($list as $panel) {
327
            $panels[$panel] = $this->getPanel($panel);
328
        }
329
        return $panels;
330
    }
331
332
    /**
333 142
     * @param string $identifier
334
     * @return null|Panel
335 114
     * @throws InvalidConfigException
336 114
     */
337 114
    public function getPanel($identifier)
338 1
    {
339 1
        $config = null;
340
        if (isset($this->panels[$identifier]))
341 114
            $config = $this->panels[$identifier];
342 114
        elseif (isset($this->_corePanels[$identifier]))
343
            $config = $this->_corePanels[$identifier];
344 114
345 114
        if (!$config)
346 114
            throw new InvalidConfigException("'$identifier' is not a valid panel identifier");
347 114
348
        if (is_array($config)) {
349
            $config['module'] = $this;
350 46
            $config['id'] = $identifier;
351
            return Yii::createObject($config);
352
        }
353
354
        return $config;
355
    }
356
357 280
    /**
358
     * Make sure the configured panels array is a uniform set of <identifier> => <config> entries.
359 280
     * @throws InvalidConfigException
360 280
     */
361 114
    protected function normalizePanelConfiguration()
362
    {
363 114
        $panels = [];
364 114
        foreach ($this->panels as $key => $value) {
365 114
            if (is_numeric($key)) {
366 114
                // The $value contains the identifier of a core panel
367
                if (!isset($this->_corePanels[$value]))
368
                    throw new InvalidConfigException("'$value' is not a valid panel identifier");
369
                $panels[$value] = $this->_corePanels[$value];
370
            }
371 114
            else {
372 114
                // The key contains the identifier and the value is either a class name or a full array
373
                $panels[$key] = is_string($value) ? ['class' => $value] : $value;
374
            }
375 114
        }
376 114
        $this->panels = ArrayHelper::merge($panels, $this->panelsMerge);
377
378
        // We now need one more iteration to add core classes to the panels added via the merge, if needed
379
        array_walk($this->panels, function(&$value, $key) {
380
           if (!isset($value['class'])) {
381
               if (isset($this->_corePanels[$key]))
382 114
                   $value = ArrayHelper::merge($value, $this->_corePanels[$key]);
383 280
               else
384
                   throw new InvalidConfigException("Invalid configuration for '$key'. No 'class' specified.");
385
           }
386
        });
387
    }
388 280
389
    /**
390 274
     * @return int|null|string
391 278
     */
392 114
    public static function findModuleIdentifier()
393 114
    {
394 114
        foreach (Yii::$app->modules as $name => $module) {
395 280
            $class = null;
396 280
            if (is_string($module))
397 114
                $class = $module;
398
            elseif (is_array($module)) {
399 165
                if (isset($module['class']))
400
                    $class = $module['class'];
401 114
            } else
402 114
                /** @var Module $module */
403 278
                $class = $module::className();
404 162
405 6
            $parts = explode('\\', $class);
406
            if ($class && strtolower(end($parts)) == 'audit')
407
                return $name;
408
        }
409
        return null;
410
    }
411
412 27
    /**
413
     * @param string $className
414 9
     * @return bool|string
415 27
     */
416 9
    public static function findPanelIdentifier($className)
417 27
    {
418
        $audit = Audit::getInstance();
419 9
        foreach ($audit->panels as $panel) {
420
            if ($panel->className() == $className) {
421
                return $panel->id;
422
            }
423
        }
424
        return false;
425
    }
426
427
    /**
428
     * Verifies a route against a given list and returns whether it matches or not.
429
     * Entries in the list are allowed to end with a '*', which means that a substring will be used for the match
430
     * instead of a full compare.
431
     *
432 64
     * @param string $route An application rout
433
     * @param string[] $list List of routes to compare against.
434 28
     * @return bool
435 28
     */
436 28
    protected function routeMatches($route, $list)
437 56
    {
438 18
        $list = ArrayHelper::toArray($list);
439 18
        foreach ($list as $compare) {
440 22
            $len = strlen($compare);
441 8
            if ($compare[$len - 1] == '*') {
442
                $compare = rtrim($compare, '*');
443 62
                if (substr($route, 0, $len - 1) === $compare)
444 6
                    return true;
445 6
            }
446 14
447 2
            if ($compare[0] == '*') {
448
                $compare = ltrim($compare, '*');
449 50
                if (substr($route, - ($len - 1)) === $compare)
450 26
                    return true;
451 36
            }
452 36
453
            if ($route === $compare)
454
                return true;
455
        }
456
        return false;
457
    }
458
459
}
460