Total Complexity | 84 |
Total Lines | 723 |
Duplicated Lines | 0 % |
Changes | 12 | ||
Bugs | 0 | Features | 0 |
Complex classes like UIElements often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
While breaking up the class, it is a good idea to analyze how other classes use UIElements, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
32 | class UIElements extends \core\common\Entity { |
||
33 | |||
34 | /** |
||
35 | * the custom displayable variant of the term 'federation' |
||
36 | * |
||
37 | * @var string |
||
38 | */ |
||
39 | public $nomenclatureFed; |
||
40 | |||
41 | /** |
||
42 | * the custom displayable variant of the term 'institution' |
||
43 | * |
||
44 | * @var string |
||
45 | */ |
||
46 | public $nomenclatureIdP; |
||
47 | |||
48 | /** |
||
49 | * the custom displayable variant of the term 'hotspot' |
||
50 | * |
||
51 | * @var string |
||
52 | */ |
||
53 | public $nomenclatureHotspot; |
||
54 | |||
55 | /** |
||
56 | * the custom displayable variant of the term 'hotspot' |
||
57 | * |
||
58 | * @var string |
||
59 | */ |
||
60 | public $nomenclatureParticipant; |
||
61 | |||
62 | /** |
||
63 | * Initialises the class. |
||
64 | * |
||
65 | * Mainly fetches various nomenclature from the config and attempts to translate those into local language. Needs pre-loading some terms. |
||
66 | */ |
||
67 | public function __construct() { |
||
75 | } |
||
76 | |||
77 | /** |
||
78 | * provides human-readable text for the various option names as stored in DB. |
||
79 | * |
||
80 | * @param string $input raw text in need of a human-readable display variant |
||
81 | * @return string the human-readable variant |
||
82 | * @throws \Exception |
||
83 | */ |
||
84 | public function displayName($input, $fullDisplay = false) { |
||
85 | \core\common\Entity::intoThePotatoes(); |
||
86 | $ssidText = _("SSID"); |
||
87 | $passpointOiText = _("HS20 Consortium OI"); |
||
88 | |||
89 | if (!empty(\config\ConfAssistant::CONSORTIUM['interworking-consortium-oi']) && count(\config\ConfAssistant::CONSORTIUM['interworking-consortium-oi']) > 0) { |
||
90 | $passpointOiText = _("Additional HS20 Consortium OI"); |
||
91 | } |
||
92 | |||
93 | $displayNames = [ |
||
94 | "support:url" => ['display' => _("Support: Web"), 'help' => ""], |
||
95 | "support:eap_types" => ['display' => _("Support: EAP Types"), 'help' => ""], |
||
96 | "support:phone" => ['display' => _("Support: Phone"), 'help' => ""], |
||
97 | "support:email" => ['display' => _("Support: E-Mail"), 'help' => ""], |
||
98 | "general:instname" => ['display' => _("Organisation Name"), 'help' => ""], |
||
99 | "general:instshortname" => ['display' => _("Organisation Acronym"), 'help' => ""], |
||
100 | "general:instaltname" => ['display' => _("Organisation Alt Name"), 'help' => ""], |
||
101 | "general:geo_coordinates" => ['display' => _("Location"), 'help' => ""], |
||
102 | "general:logo_url" => ['display' => _("Logo URL"), 'help' => ""], |
||
103 | "general:logo_file" => ['display' => _("Logo image"), 'help' => ""], |
||
104 | "media:wired" => ['display' => _("Configure Wired Ethernet"), 'help' => ""], |
||
105 | "eap:server_name" => ['display' => _("Name (CN) of Authentication Server"), 'help' => ""], |
||
106 | "eap:ca_vailduntil" => ['display' => _("Valid until"), 'help' => ""], |
||
107 | "eap:enable_nea" => ['display' => _("Enable device assessment"), 'help' => ""], |
||
108 | "support:info_file" => ['display' => _("Terms of Use"), 'help' => ""], |
||
109 | "eap:ca_url" => ['display' => _("CA Certificate URL"), 'help' => ""], |
||
110 | "eap:ca_file" => ['display' => _("CA Certificate File"), 'help' => ""], |
||
111 | "profile:name" => ['display' => _("Profile Display Name"), 'help' => ""], |
||
112 | "profile:production" => ['display' => _("Production-Ready"), 'help' => ""], |
||
113 | "hiddenprofile:tou_accepted" => ['display' => _("Admin Accepted IdP Terms of Use"), 'help' => ""], |
||
114 | "hiddenmanagedsp:tou_accepted" => ['display' => _("Admin Accepted SP Terms of Use"), 'help' => ""], |
||
115 | "device-specific:customtext" => ['display' => _("Extra text on downloadpage for device"), 'help' => ""], |
||
116 | "device-specific:redirect" => ['display' => _("Redirection Target"), 'help' => ""], |
||
117 | "eap-specific:customtext" => ['display' => _("Extra text on downloadpage for device"), 'help' => ""], |
||
118 | "eap-specific:tls_use_other_id" => ['display' => _("Turn on selection of EAP-TLS User-Name"), 'help' => ""], |
||
119 | "device-specific:geantlink" => ['display' => _("Use GEANTlink for TTLS (Windows 8 and 10)"), 'help' => ""], |
||
120 | "device-specific:geteduroam" => ['display' => _("Show the dedicated geteduroam download page for this device"), 'help' => ""], |
||
121 | "profile:description" => ['display' => _("Profile Description"), 'help' => ""], |
||
122 | "profile:customsuffix" => ['display' => _("Custom Installer Name Suffix"), 'help' => ""], |
||
123 | "media:openroaming" => ['display' => _("OpenRoaming"), 'help' => ""], |
||
124 | "user:fedadmin" => ['display' => sprintf(_("%s Administrator"), $this->nomenclatureFed), 'help' => ""], |
||
125 | "user:realname" => ['display' => _("Real Name"), 'help' => ""], |
||
126 | "user:email" => ['display' => _("E-Mail Address"), 'help' => ""], |
||
127 | "media:remove_SSID" => ['display' => _("Remove/Disable SSID"), 'help' => ""], |
||
128 | "media:force_proxy" => ['display' => _("Mandatory Content Filtering Proxy"), 'help' => ""], |
||
129 | "fed:css_file" => ['display' => _("Custom CSS file for User Area"), 'help' => "not available"], |
||
130 | "fed:logo_file" => [ |
||
131 | 'display' => sprintf(_("%s Logo"), $this->nomenclatureFed), |
||
132 | 'help' => _("Your federation logo to be shown on CAT download pages and also on Windows installers if" |
||
133 | . " the option to include branding in installers is set as well.")], |
||
134 | "fed:desired_skin" => ['display' => _("Preferred Skin for User Area"), 'help' => "not available"], |
||
135 | "fed:include_logo_installers" => [ |
||
136 | 'display' => sprintf(_("Include %s branding in installers"), $this->nomenclatureFed), |
||
137 | 'help' => _("Add your federation logo to Windows installers.")], |
||
138 | "fed:realname" => [ |
||
139 | 'display' => sprintf(_("%s Name"), $this->nomenclatureFed), |
||
140 | 'help' => "The name of your federation."], |
||
141 | "fed:url" => ['display' => sprintf(_("%s Homepage"), $this->nomenclatureFed), 'help' => ""], |
||
142 | "fed:custominvite" => [ |
||
143 | 'display' => sprintf(_("Custom text in %s Invitations"), $this->nomenclatureParticipant), |
||
144 | 'help' => _("Your text in invitation mails sent for new IdP")], |
||
145 | "fed:silverbullet" => ['display' => sprintf(_("Enable %s"), \config\ConfAssistant::SILVERBULLET['product_name']), 'help' => ""], |
||
146 | "fed:silverbullet-noterm" => ['display' => sprintf(_("%s: Do not terminate EAP"), \core\ProfileSilverbullet::PRODUCTNAME), 'help' => ""], |
||
147 | "fed:silverbullet-maxusers" => ['display' => sprintf(_("%s: max users per profile"), \core\ProfileSilverbullet::PRODUCTNAME), 'help' => ""], |
||
148 | "fed:minted_ca_file" => [ |
||
149 | 'display' => sprintf(_("Mint %s with CA on creation"), $this->nomenclatureIdP), |
||
150 | 'help' => _("Set of default CAs to add to new IdPs on signup")], |
||
151 | "fed:openroaming" => [ |
||
152 | 'display' => sprintf(_("OpenRoaming: Allow %s Opt-In"),$this->nomenclatureParticipant), |
||
153 | 'help' => _("Allow IdP to set OpenRoaming support for its users.")], |
||
154 | "fed:openroaming_customtarget" => ['display' => _("OpenRoaming: Custom NAPTR Target"), 'help' => "If you want your IdPs to use your own OpenRoaming → eduroam proxy then you can configure the hostname here; the realm check feature for IdPs will then warn them if the OpenRoaming destination server is not yours. This attribute does not need to be set, and the realm checks default to checking for the OpenRoaming → eduroam proxy operated by eduroam OT."], |
||
155 | "fed:autoregister-synced" => [ |
||
156 | 'display' => _("Self registration from eduroam DB: add listed admins to CAT institutions"), |
||
157 | 'help' => sprintf(_("With this option turned on if a CAT institution is synced to the eduroam DB it is possible to have automatic enlisting of CAT institution admins under some conditions described <a href='%s'>here</a>."), "https://wiki.eduroam.org/")], |
||
158 | "fed:autoregister-new-inst" => [ |
||
159 | 'display' => _("Self registration from eduroam DB: allow creating new institutions"), |
||
160 | 'help' => sprintf(_("Turn this on and eduroam DB listed institution admins will be allowed to create new institutions under some conditions described <a href='%s'>here</a>."), "https://wiki.eduroam.org/")], |
||
161 | "fed:autoregister-entitlement" => [ |
||
162 | 'display' => _("Self registration based on entitlement: add admins to CAT institutions"), |
||
163 | 'help' => _("With this option turned on the system will verify the eduGAIN login of the potential administrator and propose taking control over institutions which use the realm within the scope defined in the user's pairwise-id attribute.") |
||
164 | ], |
||
165 | "fed:entitlement-attr" => [ |
||
166 | 'display' => _("Custom entitlement value for self-registration"), |
||
167 | 'help' => _("If you want to use the SAML eduPersonEntitlement based self-registration you may define a value that will be used in your federation for institutions admins. When this is not set the default value geant:eduroam:inst:admin will be used. This option makes sense only if you have 'Self registration based on entitlement' set") |
||
168 | ], |
||
169 | "fed:max-inactivity" => [ |
||
170 | 'display' => _("Custom number of days of allowed admin inactivity"), |
||
171 | 'help' => sprintf(_("You can override the default value of %d days after which an inactivity warning will be displayed on the NRO admin page."), \config\ConfAssistant::ADMIN_LOGINS['allowed_inactivity_days']), |
||
172 | ], |
||
173 | "fed:hide-admin-warnings" => [ |
||
174 | 'display' => _("Do not show any warnings about missing/inactive admins"), |
||
175 | 'help' => _("You can block any warnings on missing/inactive admins. The default is to show them.") |
||
176 | ], |
||
177 | "media:SSID" => ['display' => $ssidText, 'help' => ""], |
||
178 | "media:consortium_OI" => ['display' => $passpointOiText, 'help' => ""], |
||
179 | "managedsp:guest_vlan" => ['display' => _("VLAN for guests"), 'help' => ""], |
||
180 | "managedsp:vlan" => ['display' => _("VLAN for own users"), 'help' => ""], |
||
181 | "managedsp:realmforvlan" => ['display' => _("Realm to be considered own users"), 'help' => ""], |
||
182 | "managedsp:operatorname" => ['display' => _("Custom Operator-Name attribute"), 'help' => ""], |
||
183 | ]; |
||
184 | |||
185 | if (!isset($displayNames[$input])) { // this is an error! throw an Exception |
||
186 | throw new \Exception("The translation of an option name was requested, but the option is not known to the system: " . htmlentities($input)); |
||
187 | } |
||
188 | \core\common\Entity::outOfThePotatoes(); |
||
189 | // none of the strings have HTML in them, only translators can provide own text for it -> no threat, but complained about by the security review |
||
190 | if ($fullDisplay) { |
||
191 | return ['display' => htmlspecialchars($displayNames[$input]['display']), 'help' => $displayNames[$input]['help']]; |
||
|
|||
192 | } else { |
||
193 | return htmlspecialchars($displayNames[$input]['display']); |
||
194 | } |
||
195 | } |
||
196 | |||
197 | /** |
||
198 | * creates an HTML information block with a list of options from a given category and level |
||
199 | * @param array $optionlist list of options |
||
200 | * @param string $class option class of interest |
||
201 | * @param string $level option level of interest |
||
202 | * @return string HTML code |
||
203 | */ |
||
204 | public function infoblock(array $optionlist, string $class, string $level) { |
||
205 | \core\common\Entity::intoThePotatoes(); |
||
206 | $locationMarkers = []; |
||
207 | $retval = ""; |
||
208 | $optioninfo = \core\Options::instance(); |
||
209 | |||
210 | foreach ($optionlist as $option) { |
||
211 | $type = $optioninfo->optionType($option['name']); |
||
212 | if (preg_match('/^' . $class . '/', $option['name']) && $option['level'] == "$level") { |
||
213 | // all non-multilang attribs get this assignment ... |
||
214 | $language = ""; |
||
215 | $content = $option['value']; |
||
216 | // ... override them with multilang tags if needed |
||
217 | if ($type["flag"] == "ML") { |
||
218 | $language = _("default/other languages"); |
||
219 | if ($option['lang'] != 'C') { |
||
220 | $language = \config\Master::LANGUAGES[$option['lang']]['display'] ?? "(unsupported language)"; |
||
221 | } |
||
222 | } |
||
223 | |||
224 | switch ($type["type"]) { |
||
225 | case "coordinates": |
||
226 | $coords = json_decode($option['value'], true); |
||
227 | $locationMarkers[] = $coords; |
||
228 | break; |
||
229 | case "file": |
||
230 | $retval .= "<tr><td>" . $this->displayName($option['name']) . "</td><td>$language</td><td>"; |
||
231 | switch ($option['name']) { |
||
232 | case "general:logo_file": |
||
233 | case "fed:logo_file": |
||
234 | $retval .= $this->previewImageinHTML('ROWID-' . $option['level'] . '-' . $option['row_id']); |
||
235 | break; |
||
236 | case "eap:ca_file": |
||
237 | // fall-through intended: display both the same way |
||
238 | case "fed:minted_ca_file": |
||
239 | $retval .= $this->previewCAinHTML('ROWID-' . $option['level'] . '-' . $option['row_id']); |
||
240 | break; |
||
241 | case "support:info_file": |
||
242 | $retval .= $this->previewInfoFileinHTML('ROWID-' . $option['level'] . '-' . $option['row_id']); |
||
243 | break; |
||
244 | default: |
||
245 | } |
||
246 | break; |
||
247 | case "boolean": |
||
248 | if ($option['name'] == "fed:silverbullet" && \config\Master::FUNCTIONALITY_LOCATIONS['CONFASSISTANT_SILVERBULLET'] == "LOCAL" && \config\Master::FUNCTIONALITY_LOCATIONS['CONFASSISTANT_RADIUS'] != "LOCAL") { |
||
249 | // do not display the option at all; it gets auto-set by the ProfileSilverbullet constructor and doesn't have to be seen |
||
250 | break; |
||
251 | } |
||
252 | $retval .= "<tr><td>" . $this->displayName($option['name']) . "</td><td>$language</td><td><strong>" . ($content == "on" ? _("on") : _("off") ) . "</strong></td></tr>"; |
||
253 | break; |
||
254 | default: |
||
255 | $retval .= "<tr><td>" . $this->displayName($option['name']) . "</td><td>$language</td><td><strong>$content</strong></td></tr>"; |
||
256 | } |
||
257 | } |
||
258 | } |
||
259 | if (count($locationMarkers)) { |
||
260 | $marker = '<markers>'; |
||
261 | $locationCount = 0; |
||
262 | foreach ($locationMarkers as $g) { |
||
263 | $locationCount++; |
||
264 | $marker .= '<marker name="' . $locationCount . '" lat="' . $g['lat'] . '" lng="' . $g['lon'] . '" />'; |
||
265 | } |
||
266 | $marker .= '<\/markers>'; // some validator says this should be escaped |
||
267 | $jMarker = json_encode($locationMarkers); |
||
268 | $retval .= '<tr><td><script>markers=\'' . $marker . '\'; jmarkers = \'' . $jMarker . '\';</script></td><td></td><td></td></tr>'; |
||
269 | } |
||
270 | \core\common\Entity::outOfThePotatoes(); |
||
271 | return $retval; |
||
272 | } |
||
273 | |||
274 | /** |
||
275 | * creates HTML code to display all information boxes for an IdP |
||
276 | * |
||
277 | * @param \core\IdP $myInst the IdP in question |
||
278 | * @return string HTML code |
||
279 | */ |
||
280 | public function instLevelInfoBoxes(\core\IdP $myInst) { |
||
281 | \core\common\Entity::intoThePotatoes(); |
||
282 | $idpoptions = $myInst->getAttributes(); |
||
283 | $retval = "<div class='infobox'> |
||
284 | <h2>" . sprintf(_("General %s details"), $this->nomenclatureParticipant) . "</h2> |
||
285 | <table> |
||
286 | <tr> |
||
287 | <td> |
||
288 | " . _("Country:") . " |
||
289 | </td> |
||
290 | <td> |
||
291 | </td> |
||
292 | <td> |
||
293 | <strong>"; |
||
294 | $myFed = new \core\Federation($myInst->federation); |
||
295 | $retval .= $myFed->name; |
||
296 | $retval .= "</strong> |
||
297 | </td> |
||
298 | </tr>" . $this->infoblock($idpoptions, "general", "IdP") . " |
||
299 | </table> |
||
300 | </div>"; |
||
301 | $blocks = [["support", _("Global Helpdesk Details")]]; |
||
302 | if ($myInst->type != "SP") { |
||
303 | $blocks [] = ["media", _("Media Properties")]; |
||
304 | } |
||
305 | foreach ($blocks as $block) { |
||
306 | $retval .= "<div class='infobox'> |
||
307 | <h2>" . $block[1] . "</h2> |
||
308 | <table>" . |
||
309 | $this->infoblock($idpoptions, $block[0], "IdP") . |
||
310 | "</table> |
||
311 | </div>"; |
||
312 | } |
||
313 | \core\common\Entity::outOfThePotatoes(); |
||
314 | return $retval; |
||
315 | } |
||
316 | |||
317 | /** |
||
318 | * pretty-prints a file size number in SI "bi" units |
||
319 | * @param int $number the size of the file |
||
320 | * @return string the pretty-print representation of the file size |
||
321 | */ |
||
322 | private function displaySize(int $number) { |
||
323 | if ($number > 1024 * 1024) { |
||
324 | return round($number / 1024 / 1024, 2) . " MiB"; |
||
325 | } |
||
326 | if ($number > 1024) { |
||
327 | return round($number / 1024, 2) . " KiB"; |
||
328 | } |
||
329 | return $number . " B"; |
||
330 | } |
||
331 | |||
332 | /** |
||
333 | * |
||
334 | * @param string $table the database table |
||
335 | * @param integer $rowindex the database row_id |
||
336 | * @param boolean $checkpublic should we check if the requested piece of data is public? |
||
337 | * @return string|boolean the requested data, or FALSE if something went wrong |
||
338 | */ |
||
339 | public static function getBlobFromDB($table, $rowindex, $checkpublic) { |
||
340 | // the data is either public (just give it away) or not; in this case, only |
||
341 | // release if the data belongs to admin himself |
||
342 | if ($checkpublic) { |
||
343 | |||
344 | $owners = \core\EntityWithDBProperties::isDataRestricted($table, $rowindex); |
||
345 | |||
346 | $ownersCondensed = []; |
||
347 | |||
348 | if ($owners !== FALSE) { // restricted data, see if we're authenticated and owners of the data |
||
349 | $auth = new \web\lib\admin\Authentication(); |
||
350 | if (!$auth->isAuthenticated()) { |
||
351 | return FALSE; // admin-only, but we are not an admin |
||
352 | } |
||
353 | // we might be called without session context (filepreview) so get the |
||
354 | // context if needed |
||
355 | \core\CAT::sessionStart(); |
||
356 | |||
357 | foreach ($owners as $oneowner) { |
||
358 | $ownersCondensed[] = $oneowner['ID']; |
||
359 | } |
||
360 | if (array_search($_SESSION['user'], $ownersCondensed) === FALSE) { |
||
361 | return FALSE; // wrong guy |
||
362 | } |
||
363 | // carry on and get the data |
||
364 | } |
||
365 | } |
||
366 | |||
367 | $blob = \core\EntityWithDBProperties::fetchRawDataByIndex($table, $rowindex); |
||
368 | return $blob; // this means we might return FALSE here if something was wrong with the original requested reference |
||
369 | } |
||
370 | |||
371 | /** |
||
372 | * creates HTML code to display a nice UI representation of a CA |
||
373 | * |
||
374 | * @param string $cAReference ROWID pointer to the CA to display |
||
375 | * @return string HTML code |
||
376 | */ |
||
377 | public function previewCAinHTML($cAReference) { |
||
378 | \core\common\Entity::intoThePotatoes(); |
||
379 | $validator = new \web\lib\common\InputValidation(); |
||
380 | $ref = $validator->databaseReference($cAReference); |
||
381 | $caExpiryTrashhold = \config\ConfAssistant::CERT_WARNINGS['expiry_warning']; |
||
382 | $rawResult = UIElements::getBlobFromDB($ref['table'], $ref['rowindex'], FALSE); |
||
383 | if (is_bool($rawResult)) { // we didn't actually get a CA! |
||
384 | $retval = "<div class='ca-summary'>" . _("There was an error while retrieving the certificate from the database!") . "</div>"; |
||
385 | \core\common\Entity::outOfThePotatoes(); |
||
386 | return $retval; |
||
387 | } |
||
388 | $cAblob = base64_decode($rawResult); |
||
389 | |||
390 | $func = new \core\common\X509; |
||
391 | $details = $func->processCertificate($cAblob); |
||
392 | if ($details === FALSE) { |
||
393 | $retval = _("There was an error processing the certificate!"); |
||
394 | \core\common\Entity::outOfThePotatoes(); |
||
395 | return $retval; |
||
396 | } |
||
397 | |||
398 | $details['name'] = preg_replace('/(.)\/(.)/', "$1<br/>$2", $details['name']); |
||
399 | $details['name'] = preg_replace('/\//', "", $details['name']); |
||
400 | $certstatus = ( $details['root'] == 1 ? "R" : "I"); |
||
401 | $certTooltip = ( $details['root'] == 1 ? _("Root CA") : _("Intermediate CA")); |
||
402 | $innerbgColor = "#0000ff"; |
||
403 | $leftBorderColor = "#00ff00"; |
||
404 | $message = ""; |
||
405 | if ($details['ca'] == 0 && $details['root'] != 1) { |
||
406 | $leftBorderColor = "red"; |
||
407 | $message = _("This is a <strong>SERVER</strong> certificate!"); |
||
408 | if (\config\ConfAssistant::CERT_GUIDELINES !== '') { |
||
409 | $message .= "<br/><a target='_blank' href='".\config\ConfAssistant::CERT_GUIDELINES."'>". _("more info")."</a>"; |
||
410 | } |
||
411 | $message .= "<br/>"; |
||
412 | $retval = "<div class='ca-summary' style='border-left-color: $leftBorderColor'><div style='position:absolute; right: -15px; width:20px; height:20px; background-color:$innerbgColor; border-radius:10px; text-align: center;'><div style='padding-top:3px; font-weight:bold; color:#ffffff;'>S</div></div>" . $message . $details['name'] . "</div>"; |
||
413 | \core\common\Entity::outOfThePotatoes(); |
||
414 | return $retval; |
||
415 | } |
||
416 | $now = time(); |
||
417 | if ($now + \config\ConfAssistant::CERT_WARNINGS['expiry_critical'] > $details['full_details']['validTo_time_t']) { |
||
418 | $leftBorderColor = "red"; |
||
419 | $message = _("Certificate expired!") . "<br>"; |
||
420 | } elseif($now + \config\ConfAssistant::CERT_WARNINGS['expiry_warning'] > $details['full_details']['validTo_time_t'] - $caExpiryTrashhold) { |
||
421 | if ($leftBorderColor == "#00ff00") { |
||
422 | $leftBorderColor = "yellow"; |
||
423 | } |
||
424 | $message = _("Certificate close to expiry!") . "<br/>"; |
||
425 | } |
||
426 | |||
427 | if ($details['root'] == 1 && $details['basicconstraints_set'] == 0) { |
||
428 | if ($leftBorderColor == "#00ff00") { |
||
429 | $leftBorderColor = "yellow"; |
||
430 | } |
||
431 | $message .= "<div style='max-width: 25em'><strong>" . _("Improper root certificate, required critical CA extension missing, will not reliably install!") . "</strong>"; |
||
432 | if (\config\ConfAssistant::CERT_GUIDELINES !== '') { |
||
433 | $message .= "<br/><a target='_blank' href='".\config\ConfAssistant::CERT_GUIDELINES."'>". _("more info")."</a>"; |
||
434 | } |
||
435 | $message .= "</div><br/>"; |
||
436 | } |
||
437 | $retval = "<div class='ca-summary' style='border-left-color: $leftBorderColor'><div style='position:absolute; right: -15px; width:20px; height:20px; background-color:$innerbgColor; border-radius:10px; text-align: center;'><div title='$certTooltip' style='padding-top:3px; font-weight:bold; color:#ffffff;'>$certstatus</div></div>" . $message . $details['name'] . "<br>" . $this->displayName('eap:ca_vailduntil') . " " . gmdate('Y-m-d H:i:s', $details['full_details']['validTo_time_t']) . " UTC</div>"; |
||
438 | \core\common\Entity::outOfThePotatoes(); |
||
439 | return $retval; |
||
440 | } |
||
441 | |||
442 | /** |
||
443 | * creates HTML code to display a nice UI representation of an image |
||
444 | * |
||
445 | * @param string $imageReference ROWID pointer to the image to display |
||
446 | * @return string HTML code |
||
447 | */ |
||
448 | public function previewImageinHTML($imageReference) { |
||
449 | \core\common\Entity::intoThePotatoes(); |
||
450 | $retval = "<img style='max-width:150px' src='inc/filepreview.php?id=" . $imageReference . "' alt='" . _("Preview of logo file") . "'/>"; |
||
451 | \core\common\Entity::outOfThePotatoes(); |
||
452 | return $retval; |
||
453 | } |
||
454 | |||
455 | /** |
||
456 | * creates HTML code to display a nice UI representation of a TermsOfUse file |
||
457 | * |
||
458 | * @param string $fileReference ROWID pointer to the file to display |
||
459 | * @return string HTML code |
||
460 | */ |
||
461 | public function previewInfoFileinHTML($fileReference) { |
||
476 | } |
||
477 | |||
478 | /** |
||
479 | * creates HTML code for a UI element which informs the user about something. |
||
480 | * |
||
481 | * @param int $level what kind of information is to be displayed? |
||
482 | * @param string $text the text to display |
||
483 | * @param string $caption the caption to display |
||
484 | * @param bool $omittabletags the output usually has tr/td table tags, this option suppresses them |
||
485 | * @return string |
||
486 | */ |
||
487 | public function boxFlexible(int $level, string $text = NULL, string $caption = NULL, bool $omittabletags = FALSE) { |
||
488 | \core\common\Entity::intoThePotatoes(); |
||
489 | $uiMessages = [ |
||
490 | \core\common\Entity::L_OK => ['img' => 'Tabler/square-rounded-check-filled-green.svg', 'text' => _("OK")], |
||
491 | \core\common\Entity::L_REMARK => ['img' => 'Tabler/info-square-rounded-filled-blue.svg', 'text' => _("Remark")], |
||
492 | \core\common\Entity::L_WARN => ['img' => 'Tabler/alert-square-rounded-filled-yellow.svg', 'text' => _("Warning!")], |
||
493 | \core\common\Entity::L_ERROR => ['img' => 'Tabler/square-rounded-x-filled-red.svg', 'text' => _("Error!")], |
||
494 | \core\common\Entity::L_CERT_OK => ['img' => 'Tabler/certificate-green.svg', 'text' => _("OK")], |
||
495 | \core\common\Entity::L_CERT_WARN => ['img' => 'Tabler/certificate-red.svg', 'text' => _("Warning!")], |
||
496 | \core\common\Entity::L_CERT_ERROR => ['img' => 'Tabler/certificate-off.svg', 'text' => _("Warning!")], |
||
497 | ]; |
||
498 | |||
499 | $retval = ""; |
||
500 | if (!$omittabletags) { |
||
501 | $retval .= "<tr><td>"; |
||
502 | } |
||
503 | // $finalCaption = ($caption !== NULL ? $caption : $uiMessages[$level]['text']); |
||
504 | // $retval .= "<img class='icon cat-icon' src='" . $uiMessages[$level]['icon'] . "' alt='" . $finalCaption . "' title='" . $finalCaption . "'/>"; |
||
505 | $iconData = $uiMessages[$level]; |
||
506 | if ($caption !== NULL) { |
||
507 | $iconData['text'] = $caption; |
||
508 | } |
||
509 | |||
510 | |||
511 | $retval .= $this->catIcon($iconData); |
||
512 | |||
513 | if (!$omittabletags) { |
||
514 | $retval .= "</td><td>"; |
||
515 | } |
||
516 | if ($text !== NULL) { |
||
517 | $retval .= $text; |
||
518 | } |
||
519 | if (!$omittabletags) { |
||
520 | $retval .= "</td></tr>"; |
||
521 | } |
||
522 | \core\common\Entity::outOfThePotatoes(); |
||
523 | return $retval; |
||
524 | } |
||
525 | |||
526 | /** |
||
527 | * creates HTML code to display an "all is okay" message |
||
528 | * |
||
529 | * @param string $text the text to display |
||
530 | * @param string $caption the caption to display |
||
531 | * @param bool $omittabletags the output usually has tr/td table tags, this option suppresses them |
||
532 | * @return string HTML: the box |
||
533 | */ |
||
534 | public function boxOkay(string $text = NULL, string $caption = NULL, bool $omittabletags = FALSE) { |
||
535 | return $this->boxFlexible(\core\common\Entity::L_OK, $text, $caption, $omittabletags); |
||
536 | } |
||
537 | |||
538 | /** |
||
539 | * creates HTML code to display a "smartass comment" message |
||
540 | * |
||
541 | * @param string $text the text to display |
||
542 | * @param string $caption the caption to display |
||
543 | * @param bool $omittabletags the output usually has tr/td table tags, this option suppresses them |
||
544 | * @return string HTML: the box |
||
545 | */ |
||
546 | public function boxRemark(string $text = NULL, string $caption = NULL, bool $omittabletags = FALSE) { |
||
547 | return $this->boxFlexible(\core\common\Entity::L_REMARK, $text, $caption, $omittabletags); |
||
548 | } |
||
549 | |||
550 | /** |
||
551 | * creates HTML code to display a "something's a bit wrong" message |
||
552 | * |
||
553 | * @param string $text the text to display |
||
554 | * @param string $caption the caption to display |
||
555 | * @param bool $omittabletags the output usually has tr/td table tags, this option suppresses them |
||
556 | * @return string HTML: the box |
||
557 | */ |
||
558 | public function boxWarning(string $text = NULL, string $caption = NULL, bool $omittabletags = FALSE) { |
||
559 | return $this->boxFlexible(\core\common\Entity::L_WARN, $text, $caption, $omittabletags); |
||
560 | } |
||
561 | |||
562 | /** |
||
563 | * creates HTML code to display a "Whoa! Danger, Will Robinson!" message |
||
564 | * |
||
565 | * @param string $text the text to display |
||
566 | * @param string $caption the caption to display |
||
567 | * @param bool $omittabletags the output usually has tr/td table tags, this option suppresses them |
||
568 | * @return string HTML: the box |
||
569 | */ |
||
570 | public function boxError(string $text = NULL, string $caption = NULL, bool $omittabletags = FALSE) { |
||
572 | } |
||
573 | |||
574 | /** |
||
575 | * creates HTML code to display a "All fine" message |
||
576 | * |
||
577 | * @param string $text the text to display |
||
578 | * @param string $caption the caption to display |
||
579 | * @param bool $omittabletags the output usually has tr/td table tags, this option suppresses them |
||
580 | * @return string HTML: the box |
||
581 | */ |
||
582 | public function boxCertOK(string $text = NULL, string $caption = NULL, bool $omittabletags = FALSE) { |
||
583 | return $this->boxFlexible(\core\common\Entity::L_CERT_OK, $text, $caption, $omittabletags); |
||
584 | } |
||
585 | |||
586 | /** |
||
587 | * creates HTML code to display a "A certificate close to expiry" message |
||
588 | * |
||
589 | * @param string $text the text to display |
||
590 | * @param string $caption the caption to display |
||
591 | * @param bool $omittabletags the output usually has tr/td table tags, this option suppresses them |
||
592 | * @return string HTML: the box |
||
593 | */ |
||
594 | public function boxCertWarning(string $text = NULL, string $caption = NULL, bool $omittabletags = FALSE) { |
||
595 | return $this->boxFlexible(\core\common\Entity::L_CERT_WARN, $text, $caption, $omittabletags); |
||
596 | } |
||
597 | /** |
||
598 | * creates HTML code to display a "A certificate expired or dangerously close to expiry" message |
||
599 | * |
||
600 | * @param string $text the text to display |
||
601 | * @param string $caption the caption to display |
||
602 | * @param bool $omittabletags the output usually has tr/td table tags, this option suppresses them |
||
603 | * @return string HTML: the box |
||
604 | */ |
||
605 | public function boxCertError(string $text = NULL, string $caption = NULL, bool $omittabletags = FALSE) { |
||
606 | return $this->boxFlexible(\core\common\Entity::L_CERT_ERROR, $text, $caption, $omittabletags); |
||
607 | } |
||
608 | |||
609 | |||
610 | const QRCODE_PIXELS_PER_SYMBOL = 12; |
||
611 | |||
612 | /** |
||
613 | * Injects the consortium logo in the middle of a given PNG. |
||
614 | * |
||
615 | * Usually used on QR code PNGs - the parameters inform about the structure of |
||
616 | * the QR code so that the logo does not prevent parsing of the QR code. |
||
617 | * |
||
618 | * @param string $inputpngstring the PNG to edit |
||
619 | * @param int $symbolsize size in pixels of one QR "pixel" |
||
620 | * @param int $marginsymbols size in pixels of border around the actual QR |
||
621 | * @return string the image with logo centered in the middle |
||
622 | */ |
||
623 | public function pngInjectConsortiumLogo(string $inputpngstring, int $symbolsize, int $marginsymbols = 4) { |
||
624 | $loggerInstance = new \core\common\Logging(); |
||
625 | $inputgd = imagecreatefromstring($inputpngstring); |
||
626 | if ($inputgd === FALSE) { // source image is bogus; don't do anything |
||
627 | return ""; |
||
628 | } |
||
629 | |||
630 | $loggerInstance->debug(4, "Consortium logo is at: " . ROOT . "/web/resources/images/consortium_logo_large.png"); |
||
631 | $logogd = imagecreatefrompng(ROOT . "/web/resources/images/consortium_logo_large.png"); |
||
632 | if ($logogd === FALSE) { // consortium logo is bogus; don't do anything |
||
633 | return ""; |
||
634 | } |
||
635 | $sizeinput = [imagesx($inputgd), imagesy($inputgd)]; |
||
636 | $sizelogo = [imagesx($logogd), imagesy($logogd)]; |
||
637 | // Q level QR-codes can sustain 25% "damage" |
||
638 | // make our logo cover approx 15% of area to be sure; mind that there's a $symbolsize * $marginsymbols pixel white border around each edge |
||
639 | $totalpixels = ($sizeinput[0] - $symbolsize * $marginsymbols) * ($sizeinput[1] - $symbolsize * $marginsymbols); |
||
640 | $totallogopixels = ($sizelogo[0]) * ($sizelogo[1]); |
||
641 | $maxoccupy = $totalpixels * 0.04; |
||
642 | // find out how much we have to scale down logo to reach 10% QR estate |
||
643 | $scale = sqrt($maxoccupy / $totallogopixels); |
||
644 | $loggerInstance->debug(4, "Scaling info: $scale, $maxoccupy, $totallogopixels\n"); |
||
645 | // determine final pixel size - round to multitude of $symbolsize to match exact symbol boundary |
||
646 | $targetwidth = (int) ($symbolsize * round($sizelogo[0] * $scale / $symbolsize)); |
||
647 | $targetheight = (int) ($symbolsize * round($sizelogo[1] * $scale / $symbolsize)); |
||
648 | // paint white below the logo, in case it has transparencies (looks bad) |
||
649 | // have one symbol in each direction extra white space |
||
650 | $whiteimage = imagecreate($targetwidth + 2 * $symbolsize, $targetheight + 2 * $symbolsize); |
||
651 | if ($whiteimage === FALSE) { // we can't create an empty canvas. Weird. Stop processing. |
||
652 | return ""; |
||
653 | } |
||
654 | imagecolorallocate($whiteimage, 255, 255, 255); |
||
655 | // also make sure the initial placement is a multitude of 12; otherwise "two half" symbols might be affected |
||
656 | $targetplacementx = (int) ($symbolsize * round(($sizeinput[0] / 2 - ($targetwidth - $symbolsize + 1) / 2) / $symbolsize)); |
||
657 | $targetplacementy = (int) ($symbolsize * round(($sizeinput[1] / 2 - ($targetheight - $symbolsize + 1 ) / 2) / $symbolsize)); |
||
658 | imagecopyresized($inputgd, $whiteimage, $targetplacementx - $symbolsize, $targetplacementy - $symbolsize, 0, 0, $targetwidth + 2 * $symbolsize, $targetheight + 2 * $symbolsize, $targetwidth + 2 * $symbolsize, $targetheight + 2 * $symbolsize); |
||
659 | imagecopyresized($inputgd, $logogd, $targetplacementx, $targetplacementy, 0, 0, $targetwidth, $targetheight, $sizelogo[0], $sizelogo[1]); |
||
660 | ob_start(); |
||
661 | imagepng($inputgd); |
||
662 | return ob_get_clean(); |
||
663 | } |
||
664 | |||
665 | /** |
||
666 | * Something went wrong. We display the error cause and then throw an Exception. |
||
667 | * |
||
668 | * @param string $headerDisplay error to put in the page header |
||
669 | * @param string $uiDisplay error string to display |
||
670 | * @return void direct output |
||
671 | * @throws Exception |
||
672 | */ |
||
673 | public function errorPage($headerDisplay, $uiDisplay) { |
||
674 | $decoObject = new PageDecoration(); |
||
675 | echo $decoObject->pageheader($headerDisplay, "ADMIN-IDP"); |
||
676 | echo "<h1>$uiDisplay</h1>"; |
||
677 | echo $decoObject->footer(); |
||
678 | throw new Exception("Error page raised: $headerDisplay - $uiDisplay."); |
||
679 | } |
||
680 | |||
681 | /** |
||
682 | * creates the HTML code displaying the result of a test that was run previously |
||
683 | * |
||
684 | * @param \core\SanityTests $test the test that was run |
||
685 | * @return string |
||
686 | * @throws Exception |
||
687 | */ |
||
688 | public function sanityTestResultHTML($test) { |
||
689 | $out = ''; |
||
690 | switch ($test->test_result['global']) { |
||
691 | case \core\common\Entity::L_OK: |
||
692 | $message = "Your configuration appears to be fine."; |
||
693 | break; |
||
694 | case \core\common\Entity::L_WARN: |
||
695 | $message = "There were some warnings, but your configuration should work."; |
||
696 | break; |
||
697 | case \core\common\Entity::L_ERROR: |
||
698 | $message = "Your configuration appears to be broken, please fix the errors."; |
||
699 | if ($test->fatalError) { |
||
700 | $message .= "<br>Some of the errors prevented running additional tests so rerun after fixing."; |
||
701 | } |
||
702 | break; |
||
703 | case \core\common\Entity::L_REMARK: |
||
704 | $message = "Your configuration appears to be fine."; |
||
705 | break; |
||
706 | default: |
||
707 | throw new Exception("The result code level " . $test->test_result['global'] . " is not defined!"); |
||
708 | } |
||
709 | $out .= $this->boxFlexible($test->test_result['global'], "<br><strong>Test Summary</strong><br>" . $message . "<br>See below for details<br><hr>"); |
||
710 | foreach ($test->out as $testValue) { |
||
711 | foreach ($testValue as $o) { |
||
712 | $out .= $this->boxFlexible($o['level'], $o['message']); |
||
713 | } |
||
714 | } |
||
715 | return($out); |
||
716 | } |
||
717 | /** |
||
718 | * prepares data for icons |
||
719 | * |
||
720 | * @param string $index |
||
721 | * @return array |
||
722 | */ |
||
723 | public function iconData($index) { |
||
724 | \core\common\Entity::intoThePotatoes(); |
||
725 | $icons = [ |
||
726 | 'CERT_STATUS_OK' => ['img' => 'Tabler/certificate-green.svg', 'text' => _("All certificates are valid long enough")], |
||
727 | 'CERT_STATUS_WARN' => ['img' => 'Tabler/certificate-red.svg', 'text' => _("At least one certificate is close to expiry")], |
||
728 | 'CERT_STATUS_ERROR' => ['img' => 'Tabler/certificate-off.svg', 'text' => _("At least one certificate either has expired or is very close to expiry")], |
||
729 | 'OVERALL_OPENROAMING_LEVEL_GOOD' => ['img' => 'Tabler/square-rounded-check-green.svg', 'text' => _("OpenRoaming appears to be configured properly")], |
||
730 | 'OVERALL_OPENROAMING_LEVEL_NOTE' => ['img' => 'Tabler/info-square-rounded-blue.svg', 'text' => _("There are some minor OpenRoaming configuration issues")], |
||
731 | 'OVERALL_OPENROAMING_LEVEL_WARN' => ['img' => 'Tabler/info-square-rounded-blue.svg', 'text' => _("There are some average level OpenRoaming configuration issues")], |
||
732 | 'OVERALL_OPENROAMING_LEVEL_ERROR' => ['img' => 'Tabler/alert-square-rounded-red.svg', 'text' => _("There are some critical OpenRoaming configuration issues")], |
||
733 | 'PROFILES_SHOWTIME' => ['img' => 'Tabler/checks-green.svg', 'text' => _("At least one profile is fully configured and visible in the user interface")], |
||
734 | 'PROFILES_CONFIGURED' => ['img' => 'Tabler/check-green.svg', 'text' => _("At least one profile is fully configured but none are set as production-ready therefore the institution is not visible in the user interface")], |
||
735 | 'PROFILES_INCOMPLETE' => ['img' => 'Tabler/access-point-off-red.svg', 'text' => _("No configured profiles")], |
||
736 | 'PROFILES_REDIRECTED' => ['img' => 'Tabler/external-link.svg', 'text' => _("All active profiles redirected")], |
||
737 | 'IDP_LINKED' => ['img' => 'Tabler/database-green.svg', 'text' => _("Linked")], |
||
738 | 'IDP_NOT_LINKED' => ['img' => 'Tabler/database-off-red.svg', 'text' => _("NOT linked")], |
||
739 | 'CERTS_NOT_SHOWN' => ['img' => 'Tabler/question-mark-blue.svg', 'text' => _("Not showing cert info if no profiles are visible")], |
||
740 | 'ADMINS_INACTIVE' => ['img' => 'Tabler/alert-square-rounded-filled-red-small.svg', 'text' => _("Some of the admins have not been seen for a long time")], |
||
741 | 'ADMINS_OK' => ['img' => 'Tabler/check-green-small.svg', 'text' => _("All admins are active")], |
||
742 | 'ADMINS_MISSING' => ['img' => 'Tabler/alert-square-rounded-filled-yellow-small.svg', 'text' => _("No admins registered")], |
||
743 | ]; |
||
744 | \core\common\Entity::outOfThePotatoes(); |
||
745 | return($icons[$index]); |
||
746 | } |
||
747 | |||
748 | /** |
||
749 | * the HTML img element produced 0n the basis of a simple [src,title] array |
||
750 | * @param type array |
||
751 | * @return string the img element |
||
752 | */ |
||
753 | public function catIcon($data) { |
||
755 | } |
||
756 | } |
||
757 |