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 ( bbce69...2814a2 )
by Brett
02:41
created

Audit::getUserId()   B

Complexity

Conditions 5
Paths 5

Size

Total Lines 7
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 5

Importance

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