Lines 0.00% 0 / 52
Functions and Methods 0.00% 0 / 5
Classes and Traits 0.00% 0 / 1
Name Lines Functions and Methods CRAP Classes and Traits
Sanitizer 0.00% 0 / 52 0.00% 0 / 5 306 0.00% 0 / 1
 sanitizeStackTrace 0.00% 0 / 2 0.00% 0 / 1 2
 applyCatchAllPatterns 0.00% 0 / 19 0.00% 0 / 1 2
 applySpecificPatterns 0.00% 0 / 21 0.00% 0 / 1 110
 replaceQuoted 0.00% 0 / 7 0.00% 0 / 1 12
 replace 0.00% 0 / 3 0.00% 0 / 1 6
1<?php
2
3namespace BO\Slim\Helper;
4
5final class Sanitizer
6{
7    public static function sanitizeStackTrace(string $trace): string
8    {
9        $trace = self::applyCatchAllPatterns($trace);
10
11        return self::applySpecificPatterns($trace);
12    }
13
14    protected static function applyCatchAllPatterns(string $trace): string
15    {
16        $trace = self::replace('/mysql:dbname=[^;]+;host=[^;]+;port=\d+/', 'mysql:dbname=***;host=***;port=***', $trace);
17        $trace = self::replace('/sqlite:[^;]+/', 'sqlite:***', $trace);
18
19        $trace = self::replace('/[^:\s]+:[^@\s]+@[^:\s]+:\d+/', '***:***@***:***', $trace);
20        $trace = self::replace('/[^:\s]+:[^@\s]+@[^:\s]+/', '***:***@***', $trace);
21
22        $trace = self::replace('/port=\d+/', 'port=***', $trace);
23        $trace = self::replace('/:\d+(\/|$)/', ':***$1', $trace);
24
25        $trace = self::replace('/@[\d\.]+/', '@***', $trace); // IP addresses
26        $trace = self::replace('/@[a-zA-Z0-9\-\.]+/', '@***', $trace); // Hostnames
27        $trace = self::replace('/host=[a-zA-Z0-9\-\.]+/', 'host=***', $trace); // Hostnames in connection strings
28        $trace = self::replace('/host=\d+\.\d+\.\d+\.\d+/', 'host=***', $trace); // IP addresses in connection strings
29
30        $trace = self::replace('/dbname=[a-zA-Z0-9\-_]+/', 'dbname=***', $trace);
31        $trace = self::replace('/database \'[a-zA-Z0-9\-_]+\'/', 'database \'***\'', $trace);
32
33        $trace = self::replace('/user=\'[^\']+\'/', 'user=\'***\'', $trace);
34        $trace = self::replace('/user=[^;]+/', 'user=***', $trace);
35
36        $trace = self::replace('/password=\'[^\']+\'/', 'password=\'***\'', $trace);
37        $trace = self::replace('/password=[^;]+/', 'password=***', $trace);
38
39        $trace = self::replace('/Access denied for user \'[^\']+\'@\'[^\']+\'/', 'Access denied for user \'***\'@\'***\'', $trace);
40        $trace = self::replace('/Access denied for user [^@]+@[^\s]+/', 'Access denied for user ***@***', $trace);
41
42        return $trace;
43    }
44
45    protected static function applySpecificPatterns(string $trace): string
46    {
47        if (defined('\App::DB_PASSWORD')) {
48            $trace = self::replaceQuoted(\App::DB_PASSWORD, $trace);
49        }
50        if (defined('\App::DB_USER')) {
51            $trace = self::replaceQuoted(\App::DB_USER, $trace);
52        }
53        if (defined('\App::DB_HOST')) {
54            $trace = self::replaceQuoted(\App::DB_HOST, $trace);
55        }
56        if (defined('\App::DB_NAME')) {
57            $trace = self::replaceQuoted(\App::DB_NAME, $trace);
58        }
59        if (defined('\App::DB_PORT')) {
60            $port = constant('App::DB_PORT');
61            if (!is_string($port) && !is_int($port) && !is_float($port)) {
62                return $trace;
63            }
64            $port = (string) $port;
65            if ($port !== '') {
66                $encodedPort = preg_quote($port, '/');
67                $trace = self::replace('/' . $encodedPort . '/', '***', $trace);
68                $trace = self::replace('/' . preg_quote(urlencode($port), '/') . '/', '***', $trace);
69                $trace = self::replace('/\'' . $encodedPort . '\'/', '\'***\'', $trace);
70                $trace = self::replace('/port=' . $encodedPort . '/', 'port=***', $trace);
71                $trace = self::replace('/port=' . preg_quote(urlencode($port), '/') . '/', 'port=***', $trace);
72            }
73        }
74
75        return $trace;
76    }
77
78    protected static function replaceQuoted(mixed $value, string $trace): string
79    {
80        if (!is_string($value) || $value === '') {
81            return $trace;
82        }
83        $encoded = preg_quote($value, '/');
84        $trace = self::replace('/' . $encoded . '/', '***', $trace);
85        $trace = self::replace('/' . preg_quote(urlencode($value), '/') . '/', '***', $trace);
86        $trace = self::replace('/\'' . $encoded . '\'/', '\'***\'', $trace);
87
88        return $trace;
89    }
90
91    protected static function replace(string $pattern, string $replacement, string $subject): string
92    {
93        if ($pattern === '') {
94            return $subject;
95        }
96        return preg_replace($pattern, $replacement, $subject) ?? $subject;
97    }
98}