Completed
Push — master ( af3ce8...b4d558 )
by Stefan
12:25
created

common.inc.php ➔ check_upload_sanity()   D

Complexity

Conditions 10
Paths 11

Size

Total Lines 36
Code Lines 25

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 2 Features 0
Metric Value
cc 10
eloc 25
c 2
b 2
f 0
nc 11
nop 2
dl 0
loc 36
rs 4.8196

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
/* * *********************************************************************************
4
 * (c) 2011-15 GÉANT on behalf of the GN3, GN3plus and GN4 consortia
5
 * License: see the LICENSE file in the root directory
6
 * ********************************************************************************* */
7
?>
8
<?php
9
10
require_once(dirname(dirname(dirname(dirname(__FILE__)))) . "/config/_config.php");
11
12
require_once("Helper.php");
13
require_once("Options.php");
14
require_once("CAT.php");
15
require_once("X509.php");
16
require_once("EAP.php");
17
require_once("DBConnection.php");
18
19
require_once("input_validation.inc.php");
20
require_once("auth.inc.php"); // no authentication here, but we need to check if authenticated
21
22
define("BUTTON_CLOSE", 0);
23
define("BUTTON_CONTINUE", 1);
24
define("BUTTON_DELETE", 2);
25
define("BUTTON_SAVE", 3);
26
define("BUTTON_EDIT", 4);
27
define("BUTTON_TAKECONTROL", 5);
28
define("BUTTON_PURGECACHE", 6);
29
define("BUTTON_FLUSH_AND_RESTART", 7);
30
define("BUTTON_SANITY_TESTS", 8);
31
32
$global_location_count = 0;
33
34
function display_name($input) {
35
    $DisplayNames = [_("Support: Web") => "support:url",
36
        _("Support: EAP Types") => "support:eap_types",
37
        _("Support: Phone") => "support:phone",
38
        _("Support: E-Mail") => "support:email",
39
        _("Institution Name") => "general:instname",
40
        _("Location") => "general:geo_coordinates",
41
        _("Logo URL") => "general:logo_url",
42
        _("Logo image") => "general:logo_file",
43
        _("Configure Wired Ethernet") => "media:wired",
44
        _("Name (CN) of Authentication Server") => "eap:server_name",
45
        _("Enable device assessment") => "eap:enable_nea",
46
        _("Terms of Use") => "support:info_file",
47
        _("CA Certificate URL") => "eap:ca_url",
48
        _("CA Certificate File") => "eap:ca_file",
49
        _("Profile Display Name") => "profile:name",
50
        _("Production-Ready") => "profile:production",
51
        _("Extra text on downloadpage for device") => "device-specific:customtext",
52
        _("Redirection Target") => "device-specific:redirect",
53
        _("Extra text on downloadpage for EAP method") => "eap-specific:customtext",
54
        _("Turn on selection of EAP-TLS User-Name") => "eap-specific:tls_use_other_id",
55
        _("Profile Description") => "profile:description",
56
        _("Federation Administrator") => "user:fedadmin",
57
        _("Real Name") => "user:realname",
58
        _("E-Mail Address") => "user:email",
59
        _("PEAP-MSCHAPv2") => EAP::$PEAP_MSCHAP2,
60
        _("TLS") => EAP::$TLS,
61
        _("TTLS-PAP") => EAP::$TTLS_PAP,
62
        _("TTLS-MSCHAPv2") => EAP::$TTLS_MSCHAP2,
63
        _("TTLS-GTC") => EAP::$TTLS_GTC,
64
        _("FAST-GTC") => EAP::$FAST_GTC,
65
        _("EAP-pwd") => EAP::$PWD,
66
        _("eduroam-as-a-service") => EAP::$SILVERBULLET,
67
        _("Remove/Disable SSID") => "media:remove_SSID",
68
        _("Custom CSS file for User Area") => "fed:css_file",
69
        _("Federation Logo") => "fed:logo_file",
70
        _("Preferred Skin for User Area") => "fed:desired_skin",
71
        _("Federation Operator Name") => "fed:realname",
72
        _("Custom text in IdP Invitations") => "fed:custominvite",
73
        _("Enable Silver Bullet") => "fed:silverbullet",
74
        _("Silver Bullet: Do not terminate EAP") => "fed:silverbullet-noterm",
75
        _("Silver Bullet: max users per profile") => "fed:silverbullet-maxusers",
76
    ];
77
78
    if (count(Config::$CONSORTIUM['ssid']) > 0) {
79
        $DisplayNames[_("Additional SSID")] = "media:SSID";
80
        $DisplayNames[_("Additional SSID (with WPA/TKIP)")] = "media:SSID_with_legacy";
81
    } else {
82
        $DisplayNames[_("SSID")] = "media:SSID";
83
        $DisplayNames[_("SSID (with WPA/TKIP)")] = "media:SSID_with_legacy";
84
    }
85
86
    if (!empty(Config::$CONSORTIUM['interworking-consortium-oi']) && count(Config::$CONSORTIUM['interworking-consortium-oi']) > 0) {
87
        $DisplayNames[_("Additional HS20 Consortium OI")] = "media:consortium_OI";
88
    } else {
89
        $DisplayNames[_("HS20 Consortium OI")] = "media:consortium_OI";
90
    }
91
92
    $find = array_search($input, $DisplayNames);
93
94
    if ($find === FALSE) { // sending back the original if we didn't find a better name
95
        $find = $input;
96
    }
97
    return $find;
98
}
99
100
function tooltip($input) {
101
    $descriptions = [];
102
    if (count(Config::$CONSORTIUM['ssid']) > 0) {
103
        $descriptions[sprintf(_("This attribute can be set if you want to configure an additional SSID besides the default SSIDs for %s. It is almost always a bad idea not to use the default SSIDs. The only exception is if you have premises with an overlap of the radio signal with another %s hotspot. Typical misconceptions about additional SSIDs include: I want to have a local SSID for my own users. It is much better to use the default SSID and separate user groups with VLANs. That approach has two advantages: 1) your users will configure %s properly because it is their everyday SSID; 2) if you use a custom name and advertise this one as extra secure, your users might at some point roam to another place which happens to have the same SSID name. They might then be misled to believe that they are connecting to an extra secure network while they are not."), Config::$CONSORTIUM['name'], Config::$CONSORTIUM['name'], Config::$CONSORTIUM['name'])] = "media:SSID";
104
    }
105
106
    $find = array_search($input, $descriptions);
107
108
    if ($find === FALSE) {
109
        return "";
110
    }
111
    return "<span class='tooltip' onclick='alert(\"" . $find . "\")'><img src='../resources/images/icons/question-mark-icon.png" . "'></span>";
112
}
113
114
function UI_message($level, $text = 0, $caption = 0, $omittabletags = FALSE) {
115
116
    $UI_messages = [
117
        L_OK => ['icon' => '../resources/images/icons/Quetto/check-icon.png', 'text' => _("OK")],
118
        L_REMARK => ['icon' => '../resources/images/icons/Quetto/info-icon.png', 'text' => _("Remark")],
119
        L_WARN => ['icon' => '../resources/images/icons/Quetto/danger-icon.png', 'text' => _("Warning!")],
120
        L_ERROR => ['icon' => '../resources/images/icons/Quetto/no-icon.png', 'text' => _("Error!")],
121
    ];
122
123
    $retval = "";
124
    if (!$omittabletags)
125
        $retval .= "<tr><td>";
126
    $caption = $caption !== 0 ? $caption : $UI_messages[$level]['text'];
127
    $retval .= "<img class='icon' src='" . $UI_messages[$level]['icon'] . "' alt='" . $caption . "' title='" . $caption . "'/>";
128
    if (!$omittabletags)
129
        $retval .= "</td><td>";
130
    if ($text !== 0)
131
        $retval .= $text;
132
    if (!$omittabletags)
133
        $retval .= "</td></tr>";
134
    return $retval;
135
}
136
137
function UI_okay($text = 0, $caption = 0, $omittabletags = FALSE) {
138
    return UI_message(L_OK, $text, $caption, $omittabletags);
139
}
140
141
function UI_remark($text = 0, $caption = 0, $omittabletags = FALSE) {
142
    return UI_message(L_REMARK, $text, $caption, $omittabletags);
143
}
144
145
function UI_warning($text = 0, $caption = 0, $omittabletags = FALSE) {
146
    return UI_message(L_WARN, $text, $caption, $omittabletags);
147
}
148
149
function UI_error($text = 0, $caption = 0, $omittabletags = FALSE) {
150
    return UI_message(L_ERROR, $text, $caption, $omittabletags);
151
}
152
153
function check_upload_sanity($optiontype, $filename) {
154
    switch ($optiontype) {
155
        case "general:logo_file":
156
        case "fed:logo_file":
157
        case "internal:logo_from_url":
158
            // we check logo_file with ImageMagick
159
            $image = new Imagick();
160
            try {
161
                $image->readImageBlob($filename);
162
            } catch (ImagickException $exception) {
163
                echo "Error" . $exception->getMessage();
164
                return FALSE;
165
            }
166
            // image survived the sanity check
167
            return TRUE;
168
        case "eap:ca_file":
169
            // echo "Checking $optiontype with file $filename";
170
            $cert = X509::processCertificate($filename);
171
            if ($cert) {
172
                return TRUE;
173
            }
174
            // echo "Error! The certificate seems broken!";
175
            return FALSE;
176
        case "support:info_file":
177
            $info = new finfo();
178
            $filetype = $info->buffer($filename, FILEINFO_MIME_TYPE);
179
180
            // we only take plain text files in UTF-8!
181
            if ($filetype == "text/plain" && iconv("UTF-8", "UTF-8", $filename) !== FALSE) {
182
                return TRUE;
183
            }
184
            return FALSE;
185
        default:
186
            return FALSE;
187
    }
188
}
189
190
function getBlobFromDB($ref, $checkpublic) {
191
192
    $reference = valid_DB_reference($ref);
193
194
    if ($reference == FALSE) {
195
        return;
196
    }
197
198
    // the data is either public (just give it away) or not; in this case, only
199
    // release if the data belongs to admin himself
200
    if ($checkpublic) {
201
        // we might be called without session context (filepreview) so get the
202
        // context if needed
203
        if (session_status() != PHP_SESSION_ACTIVE) {
204
            session_start();
205
        }
206
        $owners = DBConnection::isDataRestricted($reference["table"], $reference["rowindex"]);
207
208
        $owners_condensed = [];
209
210
        if ($owners !== FALSE) { // see if we're authenticated and owners of the data
211
            foreach ($owners as $oneowner) {
0 ignored issues
show
Bug introduced by
The expression $owners of type array|null is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
212
                $owners_condensed[] = $oneowner['ID'];
213
            }
214
            if (!isAuthenticated()) {
215
                return FALSE; // admin-only, but we are not an admin
216
            } elseif (array_search($_SESSION['user'], $owners_condensed) === FALSE) {
217
                return FALSE; // wrong guy
218
            } else {
0 ignored issues
show
Unused Code introduced by
This else statement is empty and can be removed.

This check looks for the else branches of if statements that have no statements or where all statements have been commented out. This may be the result of changes for debugging or the code may simply be obsolete.

These else branches can be removed.

if (rand(1, 6) > 3) {
print "Check failed";
} else {
    //print "Check succeeded";
}

could be turned into

if (rand(1, 6) > 3) {
    print "Check failed";
}

This is much more concise to read.

Loading history...
219
                // carry on and get the data
220
            }
221
        }
222
    }
223
224
    $blob = DBConnection::fetchRawDataByIndex($reference["table"], $reference["rowindex"]);
0 ignored issues
show
Documentation introduced by
$reference['table'] is of type string, but the function expects a object<Type>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
Documentation introduced by
$reference['rowindex'] is of type string, but the function expects a object<Type>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
225
    if (!$blob) {
226
        return FALSE;
227
    }
228
    return $blob;
229
}
230
231
function display_size($number) {
232
    if ($number > 1024 * 1024) {
233
        return round($number / 1024 / 1024, 2) . " MiB";
234
    }
235
    if ($number > 1024) {
236
        return round($number / 1024, 2) . " KiB";
237
    }
238
    return $number . " B";
239
}
240
241
function previewCAinHTML($ca_reference) {
242
    $found = preg_match("/^ROWID-.*/", $ca_reference);
243
    if (!$found) {
244
        return "<div>" . _("Error, ROWID expected.") . "</div>";
245
    }
246
247
    $ca_blob = base64_decode(getBlobFromDB($ca_reference, FALSE));
248
249
    $func = new X509;
250
    $details = $func->processCertificate($ca_blob);
0 ignored issues
show
Documentation introduced by
$ca_blob is of type string, but the function expects a object<blob>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
251
    if ($details === FALSE) {
252
        return _("There was an error processing the certificate!");
253
    }
254
255
    $details['name'] = preg_replace('/(.)\/(.)/', "$1<br/>$2", $details['name']);
256
    $details['name'] = preg_replace('/\//', "", $details['name']);
257
    $certstatus = ( $details['root'] == 1 ? "R" : "I");
258
    if ($details['ca'] == 0 && $details['root'] != 1) {
259
        return "<div class='ca-summary' style='background-color:red'><div style='position:absolute; right: 0px; width:20px; height:20px; background-color:maroon;  border-radius:10px; text-align: center;'><div style='padding-top:3px; font-weight:bold; color:#ffffff;'>S</div></div>" . _("This is a <strong>SERVER</strong> certificate!") . "<br/>" . $details['name'] . "</div>";
260
    }
261
    return "<div class='ca-summary'                                ><div style='position:absolute; right: 0px; width:20px; height:20px; background-color:#0000ff; border-radius:10px; text-align: center;'><div style='padding-top:3px; font-weight:bold; color:#ffffff;'>$certstatus</div></div>" . $details['name'] . "</div>";
262
}
263
264
function previewImageinHTML($image_reference) {
265
    $found = preg_match("/^ROWID-.*/", $image_reference);
266
    if (!$found) {
267
        return "<div>" . _("Error, ROWID expected.") . "</div>";
268
    }
269
    return "<img style='max-width:150px' src='inc/filepreview.php?id=" . $image_reference . "' alt='" . _("Preview of logo file") . "'/>";
270
}
271
272
function previewInfoFileinHTML($fileReference) {
273
    $found = preg_match("/^ROWID-.*/", $fileReference);
274
    if (!$found) {
275
        return _("<div>Error, ROWID expected, got $fileReference.</div>");
276
    }
277
278
    $fileBlob = unserialize(getBlobFromDB($fileReference, FALSE));
279
    $decodedFileBlob = base64_decode($fileBlob['content']);
280
    $fileinfo = new finfo();
281
    return "<div class='ca-summary'>" . _("File exists") . " (" . $fileinfo->buffer($decodedFileBlob, FILEINFO_MIME_TYPE) . ", " . display_size(strlen($decodedFileBlob)) . ")<br/><a href='inc/filepreview.php?id=$fileReference'>" . _("Preview") . "</a></div>";
282
}
283
284
function infoblock($optionlist, $class, $level) {
285
// echo "<pre>".print_r($optionlist)."</pre>";
0 ignored issues
show
Unused Code Comprehensibility introduced by
59% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
286
    $google_markers = [];
287
    $retval = "";
288
    $optioninfo = Options::instance();
289
290
    foreach ($optionlist as $option) {
291
        $type = $optioninfo->optionType($option['name']);
292
// echo "CLASS $class, OPTIONNAME ".$option['name']." LEVEL $level, TYPE ".$type['type']." FLAG ".$type['flag']."\n";
0 ignored issues
show
Unused Code Comprehensibility introduced by
70% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
293
        if (preg_match('/^' . $class . '/', $option['name']) && $option['level'] == "$level") {
294
            // all non-multilang attribs get this assignment ...
295
            $language = "";
296
            $content = $option['value'];
297
            // ... override them with multilang tags if needed
298
            if ($type["flag"] == "ML") {
299
                // echo "processing multi-lang ".$option['name']. "with value ".$option['value'];
0 ignored issues
show
Unused Code Comprehensibility introduced by
67% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
300
                $taggedarray = unserialize($option['value']);
301
                $language = _("default/other languages");
302 View Code Duplication
                if ($taggedarray['lang'] != 'C') {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
303
                    $language = Config::$LANGUAGES[$taggedarray['lang']]['display'];
304
                }
305
                $content = $taggedarray["content"];
306
            }
307
            
308
            switch ($type["type"]) {
309
                case "coordinates":
310
                    $coords = unserialize($option['value']);
311
                    $google_markers[] = $coords;
312
                    break;
313
                case "file":
314
                    $retval .= "<tr><td>" . display_name($option['name']) . "</td><td>$language</td><td>";
315
                    switch ($option['name']) {
316
                        case "general:logo_file":
317
                        case "fed:logo_file":
318
                            $retval .= previewImageinHTML('ROWID-' . $option['level'] . '-' . $option['row']);
319
                            break;
320
                        case "eap:ca_file":
321
                            $retval .= previewCAinHTML('ROWID-' . $option['level'] . '-' . $option['row']);
322
                            break;
323
                        case "support:info_file":
324
                            $retval .= previewInfoFileinHTML('ROWID-' . $option['level'] . '-' . $option['row']);
325
                            break;
326
                        default:
327
                    }
328
                    break;
329
                case "boolean":
330
                    $retval .= "<tr><td>" . display_name($option['name']) . "</td><td>$language</td><td><strong>" . ($content == "on" ? _("on") : _("off") ) . "</strong></td></tr>";
331
                    break;
332
                default:
333
                    $retval .= "<tr><td>" . display_name($option['name']) . "</td><td>$language</td><td><strong>$content</strong></td></tr>";
334
            }
335
        }
336
    }
337
    if (count($google_markers)) {
338
        $marker = '<markers>';
339
        $location_count = 0;
340
        foreach ($google_markers as $g) {
341
            $location_count++;
342
            $marker .= '<marker name="' . $location_count . '" lat="' . $g['lat'] . '" lng="' . $g['lon'] . '" />';
343
        }
344
        $marker .= '</markers>';
345
        $retval .= '<tr><td><script>markers=\'' . $marker . '\';</script></td><td></td><td></td></tr>';
346
    }
347
348
349
    return $retval;
350
}
351