antonioribeiro /
tracker
This project does not seem to handle request data directly as such no vulnerable execution paths were found.
include, or for example
via PHP's auto-loading mechanism.
These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
| 1 | <?php |
||
| 2 | |||
| 3 | namespace PragmaRX\Tracker; |
||
| 4 | |||
| 5 | use Illuminate\Foundation\Application as Laravel; |
||
| 6 | use Illuminate\Http\Request; |
||
| 7 | use Illuminate\Routing\Router; |
||
| 8 | use PragmaRX\Support\Config; |
||
| 9 | use PragmaRX\Support\GeoIp\Updater as GeoIpUpdater; |
||
| 10 | use PragmaRX\Support\IpAddress; |
||
| 11 | use PragmaRX\Tracker\Data\RepositoryManager as DataRepositoryManager; |
||
| 12 | use PragmaRX\Tracker\Repositories\Message as MessageRepository; |
||
| 13 | use PragmaRX\Tracker\Support\Minutes; |
||
| 14 | use Psr\Log\LoggerInterface; |
||
| 15 | |||
| 16 | class Tracker |
||
| 17 | { |
||
| 18 | protected $config; |
||
| 19 | |||
| 20 | /** |
||
| 21 | * @var \Illuminate\Routing\Router |
||
| 22 | */ |
||
| 23 | protected $route; |
||
| 24 | |||
| 25 | protected $logger; |
||
| 26 | |||
| 27 | /** |
||
| 28 | * @var \Illuminate\Foundation\Application |
||
| 29 | */ |
||
| 30 | protected $laravel; |
||
| 31 | |||
| 32 | protected $enabled = true; |
||
| 33 | |||
| 34 | protected $sessionData; |
||
| 35 | |||
| 36 | protected $loggedItems = []; |
||
| 37 | |||
| 38 | protected $booted = false; |
||
| 39 | |||
| 40 | /** |
||
| 41 | * @var MessageRepository |
||
| 42 | */ |
||
| 43 | protected $messageRepository; |
||
| 44 | |||
| 45 | public function __construct( |
||
| 46 | Config $config, |
||
| 47 | DataRepositoryManager $dataRepositoryManager, |
||
| 48 | Request $request, |
||
|
0 ignored issues
–
show
Bug
introduced
by
Loading history...
|
|||
| 49 | Router $route, |
||
| 50 | LoggerInterface $logger, |
||
| 51 | Laravel $laravel, |
||
| 52 | MessageRepository $messageRepository |
||
| 53 | ) { |
||
| 54 | $this->config = $config; |
||
| 55 | |||
| 56 | $this->dataRepositoryManager = $dataRepositoryManager; |
||
|
0 ignored issues
–
show
The property
dataRepositoryManager does not exist. Did you maybe forget to declare it?
In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code: class MyClass { }
$x = new MyClass();
$x->foo = true;
Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion: class MyClass {
public $foo;
}
$x = new MyClass();
$x->foo = true;
Loading history...
|
|||
| 57 | |||
| 58 | $this->request = $request; |
||
|
0 ignored issues
–
show
The property
request does not exist. Did you maybe forget to declare it?
In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code: class MyClass { }
$x = new MyClass();
$x->foo = true;
Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion: class MyClass {
public $foo;
}
$x = new MyClass();
$x->foo = true;
Loading history...
|
|||
| 59 | |||
| 60 | $this->route = $route; |
||
| 61 | |||
| 62 | $this->logger = $logger; |
||
| 63 | |||
| 64 | $this->laravel = $laravel; |
||
| 65 | |||
| 66 | $this->messageRepository = $messageRepository; |
||
| 67 | } |
||
| 68 | |||
| 69 | public function allSessions() |
||
| 70 | { |
||
| 71 | return $this->dataRepositoryManager->getAllSessions(); |
||
| 72 | } |
||
| 73 | |||
| 74 | public function boot() |
||
| 75 | { |
||
| 76 | if ($this->booted) { |
||
| 77 | return false; |
||
| 78 | } |
||
| 79 | |||
| 80 | $this->booted = true; |
||
| 81 | |||
| 82 | if ($this->isTrackable()) { |
||
| 83 | $this->track(); |
||
| 84 | } |
||
| 85 | |||
| 86 | return true; |
||
| 87 | } |
||
| 88 | |||
| 89 | public function checkCurrentUser() |
||
| 90 | { |
||
| 91 | if (!$this->sessionData['user_id'] && $user_id = $this->getUserId()) { |
||
| 92 | return true; |
||
| 93 | } |
||
| 94 | |||
| 95 | return false; |
||
| 96 | } |
||
| 97 | |||
| 98 | public function currentSession() |
||
| 99 | { |
||
| 100 | return $this->dataRepositoryManager->sessionRepository->getCurrent(); |
||
| 101 | } |
||
| 102 | |||
| 103 | protected function deleteCurrentLog() |
||
| 104 | { |
||
| 105 | $this->dataRepositoryManager->logRepository->delete(); |
||
| 106 | } |
||
| 107 | |||
| 108 | public function errors($minutes, $results = true) |
||
| 109 | { |
||
| 110 | return $this->dataRepositoryManager->errors(Minutes::make($minutes), $results); |
||
| 111 | } |
||
| 112 | |||
| 113 | public function events($minutes, $results = true) |
||
| 114 | { |
||
| 115 | return $this->dataRepositoryManager->events(Minutes::make($minutes), $results); |
||
| 116 | } |
||
| 117 | |||
| 118 | public function getAgentId() |
||
| 119 | { |
||
| 120 | return $this->config->get('log_user_agents') |
||
| 121 | ? $this->dataRepositoryManager->getAgentId() |
||
| 122 | : null; |
||
| 123 | } |
||
| 124 | |||
| 125 | public function getConfig($key) |
||
| 126 | { |
||
| 127 | return $this->config->get($key); |
||
| 128 | } |
||
| 129 | |||
| 130 | public function getCookieId() |
||
| 131 | { |
||
| 132 | return $this->config->get('store_cookie_tracker') |
||
| 133 | ? $this->dataRepositoryManager->getCookieId() |
||
| 134 | : null; |
||
| 135 | } |
||
| 136 | |||
| 137 | public function getDeviceId() |
||
| 138 | { |
||
| 139 | return $this->config->get('log_devices') |
||
| 140 | ? $this->dataRepositoryManager->findOrCreateDevice( |
||
| 141 | $this->dataRepositoryManager->getCurrentDeviceProperties() |
||
| 142 | ) |
||
| 143 | : null; |
||
| 144 | } |
||
| 145 | |||
| 146 | public function getLanguageId() |
||
| 147 | { |
||
| 148 | return $this->config->get('log_languages') |
||
| 149 | ? $this->dataRepositoryManager->findOrCreateLanguage($this->dataRepositoryManager->getCurrentLanguage()) |
||
| 150 | : null; |
||
| 151 | } |
||
| 152 | |||
| 153 | public function getDomainId($domain) |
||
| 154 | { |
||
| 155 | return $this->dataRepositoryManager->getDomainId($domain); |
||
| 156 | } |
||
| 157 | |||
| 158 | public function getGeoIpId() |
||
| 159 | { |
||
| 160 | return $this->config->get('log_geoip') |
||
| 161 | ? $this->dataRepositoryManager->getGeoIpId($this->request->getClientIp()) |
||
| 162 | : null; |
||
| 163 | } |
||
| 164 | |||
| 165 | /** |
||
| 166 | * @return array |
||
| 167 | */ |
||
| 168 | public function getLogData() |
||
| 169 | { |
||
| 170 | return [ |
||
| 171 | 'session_id' => $this->getSessionId(true), |
||
| 172 | 'method' => $this->request->method(), |
||
| 173 | 'path_id' => $this->getPathId(), |
||
| 174 | 'query_id' => $this->getQueryId(), |
||
| 175 | 'referer_id' => $this->getRefererId(), |
||
| 176 | 'is_ajax' => $this->request->ajax(), |
||
| 177 | 'is_secure' => $this->request->isSecure(), |
||
| 178 | 'is_json' => $this->request->isJson(), |
||
| 179 | 'wants_json' => $this->request->wantsJson(), |
||
| 180 | ]; |
||
| 181 | } |
||
| 182 | |||
| 183 | public function getLogger() |
||
| 184 | { |
||
| 185 | return $this->logger; |
||
| 186 | } |
||
| 187 | |||
| 188 | public function getPathId() |
||
| 189 | { |
||
| 190 | return $this->config->get('log_paths') |
||
| 191 | ? $this->dataRepositoryManager->findOrCreatePath( |
||
| 192 | [ |
||
| 193 | 'path' => $this->request->path(), |
||
| 194 | ] |
||
| 195 | ) |
||
| 196 | : null; |
||
| 197 | } |
||
| 198 | |||
| 199 | public function getQueryId() |
||
| 200 | { |
||
| 201 | if ($this->config->get('log_queries')) { |
||
| 202 | if (count($arguments = $this->request->query())) { |
||
| 203 | return $this->dataRepositoryManager->getQueryId( |
||
| 204 | [ |
||
| 205 | 'query' => array_implode('=', '|', $arguments), |
||
| 206 | 'arguments' => $arguments, |
||
| 207 | ] |
||
| 208 | ); |
||
| 209 | } |
||
| 210 | } |
||
| 211 | } |
||
| 212 | |||
| 213 | public function getRefererId() |
||
| 214 | { |
||
| 215 | return $this->config->get('log_referers') |
||
| 216 | ? $this->dataRepositoryManager->getRefererId( |
||
| 217 | $this->request->headers->get('referer') |
||
| 218 | ) |
||
| 219 | : null; |
||
| 220 | } |
||
| 221 | |||
| 222 | public function getRoutePathId() |
||
| 223 | { |
||
| 224 | return $this->dataRepositoryManager->getRoutePathId($this->route, $this->request); |
||
| 225 | } |
||
| 226 | |||
| 227 | protected function logUntrackable($item) |
||
| 228 | { |
||
| 229 | if ($this->config->get('log_untrackable_sessions') && !isset($this->loggedItems[$item])) { |
||
| 230 | $this->getLogger()->warning('TRACKER (unable to track item): '.$item); |
||
| 231 | |||
| 232 | $this->loggedItems[$item] = $item; |
||
| 233 | } |
||
| 234 | } |
||
| 235 | |||
| 236 | /** |
||
| 237 | * @return array |
||
| 238 | */ |
||
| 239 | protected function makeSessionData() |
||
| 240 | { |
||
| 241 | $sessionData = [ |
||
| 242 | 'user_id' => $this->getUserId(), |
||
| 243 | 'device_id' => $this->getDeviceId(), |
||
| 244 | 'client_ip' => $this->request->getClientIp(), |
||
| 245 | 'geoip_id' => $this->getGeoIpId(), |
||
| 246 | 'agent_id' => $this->getAgentId(), |
||
| 247 | 'referer_id' => $this->getRefererId(), |
||
| 248 | 'cookie_id' => $this->getCookieId(), |
||
| 249 | 'language_id' => $this->getLanguageId(), |
||
| 250 | 'is_robot' => $this->isRobot(), |
||
| 251 | |||
| 252 | // The key user_agent is not present in the sessions table, but |
||
| 253 | // it's internally used to check if the user agent changed |
||
| 254 | // during a session. |
||
| 255 | 'user_agent' => $this->dataRepositoryManager->getCurrentUserAgent(), |
||
| 256 | ]; |
||
| 257 | |||
| 258 | return $this->sessionData = $this->dataRepositoryManager->checkSessionData($sessionData, $this->sessionData); |
||
| 259 | } |
||
| 260 | |||
| 261 | public function getSessionId($updateLastActivity = false) |
||
| 262 | { |
||
| 263 | return $this->dataRepositoryManager->getSessionId( |
||
| 264 | $this->makeSessionData(), |
||
| 265 | $updateLastActivity |
||
| 266 | ); |
||
| 267 | } |
||
| 268 | |||
| 269 | public function getUserId() |
||
| 270 | { |
||
| 271 | return $this->config->get('log_users') |
||
| 272 | ? $this->dataRepositoryManager->getCurrentUserId() |
||
| 273 | : null; |
||
| 274 | } |
||
| 275 | |||
| 276 | /** |
||
| 277 | * @param \Throwable $throwable |
||
| 278 | */ |
||
| 279 | public function handleThrowable($throwable) |
||
| 280 | { |
||
| 281 | if ($this->config->get('log_enabled')) { |
||
| 282 | $this->dataRepositoryManager->handleThrowable($throwable); |
||
| 283 | } |
||
| 284 | } |
||
| 285 | |||
| 286 | public function isEnabled() |
||
| 287 | { |
||
| 288 | return $this->enabled; |
||
| 289 | } |
||
| 290 | |||
| 291 | public function isRobot() |
||
| 292 | { |
||
| 293 | return $this->dataRepositoryManager->isRobot(); |
||
| 294 | } |
||
| 295 | |||
| 296 | protected function isSqlQueriesLoggableConnection($name) |
||
| 297 | { |
||
| 298 | return !in_array( |
||
| 299 | $name, |
||
| 300 | $this->config->get('do_not_log_sql_queries_connections') |
||
| 301 | ); |
||
| 302 | } |
||
| 303 | |||
| 304 | public function isTrackable() |
||
| 305 | { |
||
| 306 | return $this->config->get('enabled') && |
||
| 307 | $this->logIsEnabled() && |
||
| 308 | $this->allowConsole() && |
||
| 309 | $this->parserIsAvailable() && |
||
| 310 | $this->isTrackableIp() && |
||
| 311 | $this->isTrackableEnvironment() && |
||
| 312 | $this->routeIsTrackable() && |
||
| 313 | $this->pathIsTrackable() && |
||
| 314 | $this->notRobotOrTrackable(); |
||
| 315 | } |
||
| 316 | |||
| 317 | public function isTrackableEnvironment() |
||
| 318 | { |
||
| 319 | $trackable = !in_array( |
||
| 320 | $this->laravel->environment(), |
||
| 321 | $this->config->get('do_not_track_environments') |
||
| 322 | ); |
||
| 323 | |||
| 324 | if (!$trackable) { |
||
| 325 | $this->logUntrackable('environment '.$this->laravel->environment().' is not trackable.'); |
||
| 326 | } |
||
| 327 | |||
| 328 | return $trackable; |
||
| 329 | } |
||
| 330 | |||
| 331 | public function isTrackableIp() |
||
| 332 | { |
||
| 333 | $trackable = !IpAddress::ipv4InRange( |
||
| 334 | $ipAddress = $this->request->getClientIp(), |
||
| 335 | $this->config->get('do_not_track_ips') |
||
| 336 | ); |
||
| 337 | |||
| 338 | if (!$trackable) { |
||
| 339 | $this->logUntrackable($ipAddress.' is not trackable.'); |
||
| 340 | } |
||
| 341 | |||
| 342 | return $trackable; |
||
| 343 | } |
||
| 344 | |||
| 345 | public function logByRouteName($name, $minutes = null) |
||
| 346 | { |
||
| 347 | if ($minutes) { |
||
| 348 | $minutes = Minutes::make($minutes); |
||
| 349 | } |
||
| 350 | |||
| 351 | return $this->dataRepositoryManager->logByRouteName($name, $minutes); |
||
| 352 | } |
||
| 353 | |||
| 354 | public function logEvents() |
||
| 355 | { |
||
| 356 | if ( |
||
| 357 | $this->isTrackable() && |
||
| 358 | $this->config->get('log_enabled') && |
||
| 359 | $this->config->get('log_events') |
||
| 360 | ) { |
||
| 361 | $this->dataRepositoryManager->logEvents(); |
||
| 362 | } |
||
| 363 | } |
||
| 364 | |||
| 365 | public function logIsEnabled() |
||
| 366 | { |
||
| 367 | $enabled = |
||
| 368 | $this->config->get('log_enabled') || |
||
| 369 | $this->config->get('log_sql_queries') || |
||
| 370 | $this->config->get('log_sql_queries_bindings') || |
||
| 371 | $this->config->get('log_events') || |
||
| 372 | $this->config->get('log_geoip') || |
||
| 373 | $this->config->get('log_user_agents') || |
||
| 374 | $this->config->get('log_users') || |
||
| 375 | $this->config->get('log_devices') || |
||
| 376 | $this->config->get('log_languages') || |
||
| 377 | $this->config->get('log_referers') || |
||
| 378 | $this->config->get('log_paths') || |
||
| 379 | $this->config->get('log_queries') || |
||
| 380 | $this->config->get('log_routes') || |
||
| 381 | $this->config->get('log_exceptions'); |
||
| 382 | |||
| 383 | if (!$enabled) { |
||
| 384 | $this->logUntrackable('there are no log items enabled.'); |
||
| 385 | } |
||
| 386 | |||
| 387 | return $enabled; |
||
| 388 | } |
||
| 389 | |||
| 390 | public function logSqlQuery($query, $bindings, $time, $name) |
||
| 391 | { |
||
| 392 | if ( |
||
| 393 | $this->isTrackable() && |
||
| 394 | $this->config->get('log_enabled') && |
||
| 395 | $this->config->get('log_sql_queries') && |
||
| 396 | $this->isSqlQueriesLoggableConnection($name) |
||
| 397 | ) { |
||
| 398 | $this->dataRepositoryManager->logSqlQuery($query, $bindings, $time, $name); |
||
| 399 | } |
||
| 400 | } |
||
| 401 | |||
| 402 | protected function notRobotOrTrackable() |
||
| 403 | { |
||
| 404 | $trackable = |
||
| 405 | !$this->isRobot() || |
||
| 406 | !$this->config->get('do_not_track_robots'); |
||
| 407 | |||
| 408 | if (!$trackable) { |
||
| 409 | $this->logUntrackable('tracking of robots is disabled.'); |
||
| 410 | } |
||
| 411 | |||
| 412 | return $trackable; |
||
| 413 | } |
||
| 414 | |||
| 415 | public function pageViews($minutes, $results = true) |
||
| 416 | { |
||
| 417 | return $this->dataRepositoryManager->pageViews(Minutes::make($minutes), $results); |
||
| 418 | } |
||
| 419 | |||
| 420 | public function pageViewsByCountry($minutes, $results = true) |
||
| 421 | { |
||
| 422 | return $this->dataRepositoryManager->pageViewsByCountry(Minutes::make($minutes), $results); |
||
| 423 | } |
||
| 424 | |||
| 425 | public function allowConsole() |
||
| 426 | { |
||
| 427 | return |
||
| 428 | (!$this->laravel->runningInConsole()) || |
||
| 429 | $this->config->get('console_log_enabled', false); |
||
| 430 | } |
||
| 431 | |||
| 432 | public function parserIsAvailable() |
||
| 433 | { |
||
| 434 | if (!$this->dataRepositoryManager->parserIsAvailable()) { |
||
| 435 | $this->logger->error(trans('tracker::tracker.regex_file_not_available')); |
||
| 436 | |||
| 437 | return false; |
||
| 438 | } |
||
| 439 | |||
| 440 | return true; |
||
| 441 | } |
||
| 442 | |||
| 443 | public function routeIsTrackable() |
||
| 444 | { |
||
| 445 | if (!$this->route) { |
||
| 446 | return false; |
||
| 447 | } |
||
| 448 | |||
| 449 | if (!$trackable = $this->dataRepositoryManager->routeIsTrackable($this->route)) { |
||
| 450 | $this->logUntrackable('route '.$this->route->getCurrentRoute()->getName().' is not trackable.'); |
||
| 451 | } |
||
| 452 | |||
| 453 | return $trackable; |
||
| 454 | } |
||
| 455 | |||
| 456 | public function pathIsTrackable() |
||
| 457 | { |
||
| 458 | if (!$trackable = $this->dataRepositoryManager->pathIsTrackable($this->request->path())) { |
||
| 459 | $this->logUntrackable('path '.$this->request->path().' is not trackable.'); |
||
| 460 | } |
||
| 461 | |||
| 462 | return $trackable; |
||
| 463 | } |
||
| 464 | |||
| 465 | public function routerMatched($log) |
||
| 466 | { |
||
| 467 | if ($this->dataRepositoryManager->routeIsTrackable($this->route)) { |
||
| 468 | if ($log) { |
||
| 469 | $this->dataRepositoryManager->updateRoute( |
||
| 470 | $this->getRoutePathId() |
||
| 471 | ); |
||
| 472 | } |
||
| 473 | } |
||
| 474 | // Router was matched but this route is not trackable |
||
| 475 | // Let's just delete the stored data, because There's not a |
||
| 476 | // realy clean way of doing this because if a route is not |
||
| 477 | // matched, and this happens ages after the app is booted, |
||
| 478 | // we till need to store data from the request. |
||
| 479 | else { |
||
| 480 | $this->turnOff(); |
||
| 481 | |||
| 482 | $this->deleteCurrentLog(); |
||
| 483 | } |
||
| 484 | } |
||
| 485 | |||
| 486 | public function sessionLog($uuid, $results = true) |
||
| 487 | { |
||
| 488 | return $this->dataRepositoryManager->getSessionLog($uuid, $results); |
||
| 489 | } |
||
| 490 | |||
| 491 | public function sessions($minutes = 1440, $results = true) |
||
| 492 | { |
||
| 493 | return $this->dataRepositoryManager->getLastSessions(Minutes::make($minutes), $results); |
||
| 494 | } |
||
| 495 | |||
| 496 | public function onlineUsers($minutes = 3, $results = true) |
||
|
0 ignored issues
–
show
|
|||
| 497 | { |
||
| 498 | return $this->sessions(3); |
||
| 499 | } |
||
| 500 | |||
| 501 | public function track() |
||
| 502 | { |
||
| 503 | $log = $this->getLogData(); |
||
| 504 | |||
| 505 | if ($this->config->get('log_enabled')) { |
||
| 506 | $this->dataRepositoryManager->createLog($log); |
||
| 507 | } |
||
| 508 | } |
||
| 509 | |||
| 510 | public function trackEvent($event) |
||
| 511 | { |
||
| 512 | $this->dataRepositoryManager->trackEvent($event); |
||
| 513 | } |
||
| 514 | |||
| 515 | public function trackVisit($route, $request) |
||
| 516 | { |
||
| 517 | $this->dataRepositoryManager->trackRoute($route, $request); |
||
| 518 | } |
||
| 519 | |||
| 520 | public function turnOff() |
||
| 521 | { |
||
| 522 | $this->enabled = false; |
||
| 523 | } |
||
| 524 | |||
| 525 | public function userDevices($minutes, $user_id = null, $results = true) |
||
| 526 | { |
||
| 527 | return $this->dataRepositoryManager->userDevices( |
||
| 528 | Minutes::make($minutes), |
||
| 529 | $user_id, |
||
| 530 | $results |
||
| 531 | ); |
||
| 532 | } |
||
| 533 | |||
| 534 | public function users($minutes, $results = true) |
||
| 535 | { |
||
| 536 | return $this->dataRepositoryManager->users(Minutes::make($minutes), $results); |
||
| 537 | } |
||
| 538 | |||
| 539 | /** |
||
| 540 | * Get the messages. |
||
| 541 | * |
||
| 542 | * @return \Illuminate\Support\Collection |
||
| 543 | */ |
||
| 544 | public function getMessages() |
||
| 545 | { |
||
| 546 | return $this->messageRepository->getMessages(); |
||
| 547 | } |
||
| 548 | |||
| 549 | /** |
||
| 550 | * Update the GeoIp2 database. |
||
| 551 | * |
||
| 552 | * @return bool |
||
| 553 | */ |
||
| 554 | public function updateGeoIp() |
||
| 555 | { |
||
| 556 | $updater = new GeoIpUpdater(); |
||
| 557 | |||
| 558 | $success = $updater->updateGeoIpFiles($this->config->get('geoip_database_path')); |
||
| 559 | |||
| 560 | $this->messageRepository->addMessage($updater->getMessages()); |
||
| 561 | |||
| 562 | return $success; |
||
| 563 | } |
||
| 564 | } |
||
| 565 |