Test Failed
Push — master ( f4077b...8d6a7b )
by Tomasz
12:00
created

Logging::debug_s()   A

Complexity

Conditions 4
Paths 5

Size

Total Lines 22
Code Lines 16

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 16
c 1
b 0
f 0
dl 0
loc 22
rs 9.7333
cc 4
nc 5
nop 4
1
<?php
2
3
/*
4
 * *****************************************************************************
5
 * Contributions to this work were made on behalf of the GÉANT project, a 
6
 * project that has received funding from the European Union’s Framework 
7
 * Programme 7 under Grant Agreements No. 238875 (GN3) and No. 605243 (GN3plus),
8
 * Horizon 2020 research and innovation programme under Grant Agreements No. 
9
 * 691567 (GN4-1) and No. 731122 (GN4-2).
10
 * On behalf of the aforementioned projects, GEANT Association is the sole owner
11
 * of the copyright in all material which was developed by a member of the GÉANT
12
 * project. GÉANT Vereniging (Association) is registered with the Chamber of 
13
 * Commerce in Amsterdam with registration number 40535155 and operates in the 
14
 * UK as a branch of GÉANT Vereniging.
15
 * 
16
 * Registered office: Hoekenrode 3, 1102BR Amsterdam, The Netherlands. 
17
 * UK branch address: City House, 126-130 Hills Road, Cambridge CB2 1PQ, UK
18
 *
19
 * License: see the web/copyright.inc.php file in the file structure or
20
 *          <base_url>/copyright.php after deploying the software
21
 */
22
23
namespace core\common;
24
25
use \Exception;
0 ignored issues
show
Bug introduced by
The type \Exception was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
26
27
class Logging
28
{
29
30
    /**
31
     * We don't have a lot to do here, but at least make sure that the logdir 
32
     * is specified and exists.
33
     * 
34
     * @throws Exception
35
     */
36
    public function __construct()
37
    {
38
        if (!isset(\config\Master::PATHS['logdir'])) {
39
            throw new Exception("No logdir was specified in the configuration. We cannot continue without one!");
40
        }
41
    }
42
43
    /**
44
     * writes a message to file
45
     * 
46
     * @param string $filename the name of the log file, relative (path to logdir gets prepended)
47
     * @param string $message  what to write into the file
48
     * @return void
49
     */
50
    private function writeToFile($filename, $message)
51
    {
52
        file_put_contents(\config\Master::PATHS['logdir'] . "/$filename", sprintf("%-015s", microtime(TRUE)) . $message, FILE_APPEND);
0 ignored issues
show
Security File Manipulation introduced by
config\Master::PATHS['logdir'] . '/'.$filename can contain request data and is used in file manipulation context(s) leading to a potential security vulnerability.

1 path for user data to reach this point

  1. Read from $_REQUEST
    in web/lib/user/Gui.php on line 41

General Strategies to prevent injection

In general, it is advisable to prevent any user-data to reach this point. This can be done by white-listing certain values:

if ( ! in_array($value, array('this-is-allowed', 'and-this-too'), true)) {
    throw new \InvalidArgumentException('This input is not allowed.');
}

For numeric data, we recommend to explicitly cast the data:

$sanitized = (integer) $tainted;
Loading history...
Security File Manipulation introduced by
sprintf('%-015s', microtime(TRUE)) . $message can contain request data and is used in file manipulation context(s) leading to a potential security vulnerability.

3 paths for user data to reach this point

  1. Path: Read tainted data from array, and Data is passed through strip_tags(), and Data is passed through htmlspecialchars(), and htmlspecialchars(strip_tags($_SERVER['HTTP_USER_AGENT']), core\ENT_QUOTES) is assigned to $browser in core/UserAPI.php on line 525
  1. Read tainted data from array, and Data is passed through strip_tags(), and Data is passed through htmlspecialchars(), and htmlspecialchars(strip_tags($_SERVER['HTTP_USER_AGENT']), core\ENT_QUOTES) is assigned to $browser
    in core/UserAPI.php on line 525
  2. Logging::debug() is called
    in core/UserAPI.php on line 532
  3. Enters via parameter $stuff
    in core/common/Logging.php on line 76
  4. $prefix . $stuff . $suffix is assigned to $output
    in core/common/Logging.php on line 92
  5. Logging::writeToFile() is called
    in core/common/Logging.php on line 96
  6. Enters via parameter $message
    in core/common/Logging.php on line 50
  2. Path: Read from $_GET, and Data is passed through strip_tags(), and Data is passed through htmlspecialchars(), and htmlspecialchars(strip_tags($_GET['device'])) is assigned to $devId in core/UserAPI.php on line 571
  1. Read from $_GET, and Data is passed through strip_tags(), and Data is passed through htmlspecialchars(), and htmlspecialchars(strip_tags($_GET['device'])) is assigned to $devId
    in core/UserAPI.php on line 571
  2. $devId is returned
    in core/UserAPI.php on line 583
  3. $this->deviceFromRequest() is assigned to $devId
    in core/UserAPI.php on line 517
  4. Data is passed through returnDevice(), and $this->returnDevice($devId, $Dev[$devId]) is assigned to $ret
    in core/UserAPI.php on line 519
  5. $ret is returned
    in core/UserAPI.php on line 521
  6. $this->detectOS() is assigned to property Gui::$operatingSystem
    in web/lib/user/Gui.php on line 48
  7. Read from property Gui::$operatingSystem, and Logging::debug() is called
    in web/lib/user/Gui.php on line 49
  8. Enters via parameter $stuff
    in core/common/Logging.php on line 76
  9. $prefix . $stuff . $suffix is assigned to $output
    in core/common/Logging.php on line 92
  10. Logging::writeToFile() is called
    in core/common/Logging.php on line 96
  11. Enters via parameter $message
    in core/common/Logging.php on line 50
  3. Path: Read from $_POST, and Data is passed through strip_tags(), and Data is passed through htmlspecialchars(), and htmlspecialchars(strip_tags($_POST['device'])) is assigned to $devId in core/UserAPI.php on line 573
  1. Read from $_POST, and Data is passed through strip_tags(), and Data is passed through htmlspecialchars(), and htmlspecialchars(strip_tags($_POST['device'])) is assigned to $devId
    in core/UserAPI.php on line 573
  2. $devId is returned
    in core/UserAPI.php on line 583
  3. $this->deviceFromRequest() is assigned to $devId
    in core/UserAPI.php on line 517
  4. Data is passed through returnDevice(), and $this->returnDevice($devId, $Dev[$devId]) is assigned to $ret
    in core/UserAPI.php on line 519
  5. $ret is returned
    in core/UserAPI.php on line 521
  6. $this->detectOS() is assigned to property Gui::$operatingSystem
    in web/lib/user/Gui.php on line 48
  7. Read from property Gui::$operatingSystem, and Logging::debug() is called
    in web/lib/user/Gui.php on line 49
  8. Enters via parameter $stuff
    in core/common/Logging.php on line 76
  9. $prefix . $stuff . $suffix is assigned to $output
    in core/common/Logging.php on line 92
  10. Logging::writeToFile() is called
    in core/common/Logging.php on line 96
  11. Enters via parameter $message
    in core/common/Logging.php on line 50

General Strategies to prevent injection

In general, it is advisable to prevent any user-data to reach this point. This can be done by white-listing certain values:

if ( ! in_array($value, array('this-is-allowed', 'and-this-too'), true)) {
    throw new \InvalidArgumentException('This input is not allowed.');
}

For numeric data, we recommend to explicitly cast the data:

$sanitized = (integer) $tainted;
Loading history...
53
    }
54
55
    /**
56
     * writes a message to file (static version)
57
     * 
58
     * @param string $filename the name of the log file, relative (path to logdir gets prepended)
59
     * @param string $message  what to write into the file
60
     * @return void
61
     */
62
    private static function writeToFile_s($filename, $message)
0 ignored issues
show
Coding Style introduced by
Method name "Logging::writeToFile_s" is not in camel caps format
Loading history...
63
    {
64
        file_put_contents(\config\Master::PATHS['logdir'] . "/$filename", sprintf("%-015s", microtime(TRUE)) . $message, FILE_APPEND);
65
    }
66
    
67
    /**
68
     * write debug messages to the log, if the debug level is high enough
69
     *
70
     * @param int    $level  the debug level of the message that is to be logged
71
     * @param mixed  $stuff  the stuff to be logged (via print_r)
72
     * @param string $prefix prefix to the message, optional
73
     * @param string $suffix suffix to the message, optional
74
     * @return void
75
     */
76
    public function debug($level, $stuff, $prefix = '', $suffix = '')
77
    {
78
        if (\config\Master::DEBUG_LEVEL < $level) {
79
            return;
80
        }
81
82
        $output = " ($level) ";
83
        if ($level > 3) {
84
            $backtrace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);
85
            $orig_file = $backtrace[1]['file'] ?? "no file";
86
            $file = str_replace(ROOT, "", $orig_file);
87
            $function = $backtrace[1]['function'] ?? "no function";
88
            $line = $backtrace[1]['line'] ?? "no line";
89
            $output .= " [$file / $function / $line] ";
90
        }
91
        if (is_string($stuff)) {
92
            $output .= $prefix . $stuff . $suffix;
93
        } else {
94
            $output .= $prefix . var_export($stuff, TRUE) . $suffix;
95
        }
96
        $this->writeToFile("debug.log", $output);
97
98
        return;
99
    }
100
    
101
    /**
102
     * write debug messages to the log, if the debug level is high enough - static version
103
     *
104
     * @param int    $level  the debug level of the message that is to be logged
105
     * @param mixed  $stuff  the stuff to be logged (via print_r)
106
     * @param string $prefix prefix to the message, optional
107
     * @param string $suffix suffix to the message, optional
108
     * @return void
109
     */    
110
    public static function debug_s($level, $stuff, $prefix = '', $suffix = '')
0 ignored issues
show
Coding Style introduced by
Method name "Logging::debug_s" is not in camel caps format
Loading history...
111
    {
112
        if (\config\Master::DEBUG_LEVEL < $level) {
113
            return;
114
        }
115
116
        $output = " ($level) ";
117
        if ($level > 3) {
118
            $backtrace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);
119
            $orig_file = $backtrace[1]['file'] ?? "no file";
120
            $file = str_replace(ROOT, "", $orig_file);
121
            $function = $backtrace[1]['function'] ?? "no function";
122
            $line = $backtrace[1]['line'] ?? "no line";
123
            $output .= " [$file / $function / $line] ";
124
        }
125
        if (is_string($stuff)) {
126
            $output .= $prefix . $stuff . $suffix;
127
        } else {
128
            $output .= $prefix . var_export($stuff, TRUE) . $suffix;
129
        }
130
        self::writeToFile_s("debug.log", $output);
131
        return;
132
    }   
133
134
    /**
135
     * Writes an audit log entry to the audit log file. These audits are semantic logs; they don't record every single modification
136
     * in the database, but provide a logical "who did what" overview. The exact modification SQL statements are logged
137
     * automatically with writeSQLAudit() instead. The log file path is configurable in _config.php.
138
     * 
139
     * @param string $user     persistent identifier of the user who triggered the action
140
     * @param string $category type of modification, from the fixed vocabulary: "NEW", "OWN", "MOD", "DEL"
141
     * @param string $message  message to log into the audit log
142
     * @return boolean TRUE if successful. Will terminate script execution on failure. 
143
     * @throws Exception
144
     */
145
    public function writeAudit($user, $category, $message)
146
    {
147
        switch ($category) {
148
            case "NEW": // created a new object
149
            case "OWN": // ownership changes
150
            case "MOD": // modified existing object
151
            case "DEL": // deleted an object
152
                ob_start();
153
                echo " ($category)  $user : $message\n";
154
                $output = ob_get_clean();
155
                $this->writeToFile("audit-activity.log", $output);
156
                return TRUE;
157
            default:
158
                throw new Exception("Unable to write to AUDIT file (unknown category, requested data was $user, $category, $message!");
159
        }
160
    }
161
162
    /**
163
     * Write an audit log entry to the SQL log file. Every SQL statement which is not a simple SELECT one will be written
164
     * to the log file. The log file path is configurable in _config.php.
165
     * 
166
     * @param string $query the SQL query to be logged
167
     * @return void
168
     */
169
    public function writeSQLAudit($query)
170
    {
171
        // clean up text to be in one line, with no extra spaces
172
        // also clean up non UTF-8 to sanitise possibly malicious inputs
173
        $logTextStep1 = preg_replace("/[\n\r]/", "", $query);
174
        $logTextStep2 = preg_replace("/ +/", " ", $logTextStep1);
175
        $logTextStep3 = iconv("UTF-8", "UTF-8//IGNORE", $logTextStep2);
176
        $this->writeToFile("audit-SQL.log", " " . $logTextStep3 . "\n");
177
    }
178
}