1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
/* |
4
|
|
|
* ****************************************************************************** |
5
|
|
|
* Copyright 2011-2017 DANTE Ltd. and GÉANT on behalf of the GN3, GN3+, GN4-1 |
6
|
|
|
* and GN4-2 consortia |
7
|
|
|
* |
8
|
|
|
* License: see the web/copyright.php file in the file structure |
9
|
|
|
* ****************************************************************************** |
10
|
|
|
*/ |
11
|
|
|
|
12
|
|
|
/** |
13
|
|
|
* This is the collection of methods dedicated for the user GUI |
14
|
|
|
* @author Tomasz Wolniewicz <[email protected]> |
15
|
|
|
* @author Stefan Winter <[email protected]> |
16
|
|
|
* @package UserAPI |
17
|
|
|
* |
18
|
|
|
* Parts of this code are based on simpleSAMLPhp discojuice module. |
19
|
|
|
* This product includes GeoLite data created by MaxMind, available from |
20
|
|
|
* http://www.maxmind.com |
21
|
|
|
*/ |
22
|
|
|
|
23
|
|
|
namespace core; |
24
|
|
|
|
25
|
|
|
use \Exception; |
26
|
|
|
|
27
|
|
|
/** |
28
|
|
|
* The basic methoods for the user GUI |
29
|
|
|
* @package UserAPI |
30
|
|
|
* |
31
|
|
|
*/ |
32
|
|
|
class UserAPI extends CAT { |
33
|
|
|
|
34
|
|
|
/** |
35
|
|
|
* nothing special to be done here. |
36
|
|
|
*/ |
37
|
|
|
public function __construct() { |
38
|
|
|
parent::__construct(); |
39
|
|
|
} |
40
|
|
|
|
41
|
|
|
/** |
42
|
|
|
* Prepare the device module environment and send back the link |
43
|
|
|
* This method creates a device module instance via the {@link DeviceFactory} call, |
44
|
|
|
* then sets up the device module environment for the specific profile by calling |
45
|
|
|
* {@link DeviceConfig::setup()} method and finally, called the devide writeInstaller meethod |
46
|
|
|
* passing the returned path name. |
47
|
|
|
* |
48
|
|
|
* @param string $device identifier as in {@link devices.php} |
49
|
|
|
* @param int $profileId profile identifier |
50
|
|
|
* |
51
|
|
|
* @return array |
52
|
|
|
* array with the following fields: |
53
|
|
|
* profile - the profile identifier; |
54
|
|
|
* device - the device identifier; |
55
|
|
|
* link - the path name of the resulting installer |
56
|
|
|
* mime - the mimetype of the installer |
57
|
|
|
*/ |
58
|
|
|
public function generateInstaller($device, $profileId, $generatedFor = "user", $token = NULL, $password = NULL) { |
59
|
|
|
$this->languageInstance->setTextDomain("devices"); |
60
|
|
|
$this->loggerInstance->debug(4, "installer:$device:$profileId\n"); |
61
|
|
|
$validator = new \web\lib\common\InputValidation(); |
62
|
|
|
$profile = $validator->Profile($profileId); |
63
|
|
|
// test if the profile is production-ready and if not if the authenticated user is an owner |
64
|
|
|
if ($this->verifyDownloadAccess($profile) === FALSE) { |
65
|
|
|
return; |
66
|
|
|
} |
67
|
|
|
$installerProperties = []; |
68
|
|
|
$installerProperties['profile'] = $profileId; |
69
|
|
|
$installerProperties['device'] = $device; |
70
|
|
|
$cache = $this->getCache($device, $profile); |
71
|
|
|
$this->installerPath = $cache['path']; |
72
|
|
|
if ($this->installerPath && $token == NULL && $password == NULL) { |
73
|
|
|
$this->loggerInstance->debug(4, "Using cached installer for: $device\n"); |
74
|
|
|
$installerProperties['link'] = "API.php?action=downloadInstaller&lang=" . $this->languageInstance->getLang() . "&profile=$profileId&device=$device&generatedfor=$generatedFor"; |
75
|
|
|
$installerProperties['mime'] = $cache['mime']; |
76
|
|
|
} else { |
77
|
|
|
$myInstaller = $this->generateNewInstaller($device, $profile, $generatedFor, $token, $password); |
78
|
|
|
if ($myInstaller['link'] !== 0) { |
79
|
|
|
$installerProperties['mime'] = $myInstaller['mime']; |
80
|
|
|
} |
81
|
|
|
$installerProperties['link'] = $myInstaller['link']; |
82
|
|
|
} |
83
|
|
|
$this->languageInstance->setTextDomain("web_user"); |
84
|
|
|
return($installerProperties); |
85
|
|
|
} |
86
|
|
|
|
87
|
|
|
private function verifyDownloadAccess($profile) { |
88
|
|
|
$attribs = $profile->getCollapsedAttributes(); |
89
|
|
|
if (\core\common\Entity::getAttributeValue($attribs, 'profile:production', 0) !== 'on') { |
90
|
|
|
$this->loggerInstance->debug(4, "Attempt to download a non-production ready installer for profile: $profile->identifier\n"); |
91
|
|
|
$auth = new \web\lib\admin\Authentication(); |
92
|
|
|
if (!$auth->isAuthenticated()) { |
93
|
|
|
$this->loggerInstance->debug(2, "User NOT authenticated, rejecting request for a non-production installer\n"); |
94
|
|
|
header("HTTP/1.0 403 Not Authorized"); |
95
|
|
|
return(FALSE); |
96
|
|
|
} |
97
|
|
|
$userObject = new User($_SESSION['user']); |
98
|
|
|
if (!$userObject->isIdPOwner($profile->institution)) { |
99
|
|
|
$this->loggerInstance->debug(2, "User not an owner of a non-production profile - access forbidden\n"); |
100
|
|
|
header("HTTP/1.0 403 Not Authorized"); |
101
|
|
|
return(FALSE); |
102
|
|
|
} |
103
|
|
|
$this->loggerInstance->debug(4, "User is the owner - allowing access\n"); |
104
|
|
|
} |
105
|
|
|
return(TRUE); |
106
|
|
|
} |
107
|
|
|
|
108
|
|
|
/** |
109
|
|
|
* This function tries to find a cached copy of an installer for a given |
110
|
|
|
* combination of Profile and device |
111
|
|
|
* @param string $device |
112
|
|
|
* @param AbstractProfile $profile |
113
|
|
|
* @return boolean|string the string with the path to the cached copy, or FALSE if no cached copy exists |
114
|
|
|
*/ |
115
|
|
|
private function getCache($device, $profile) { |
116
|
|
|
$deviceList = \devices\Devices::listDevices(); |
117
|
|
|
$deviceConfig = $deviceList[$device]; |
118
|
|
|
$noCache = (isset(\devices\Devices::$Options['no_cache']) && \devices\Devices::$Options['no_cache']) ? 1 : 0; |
119
|
|
|
if (isset($deviceConfig['options']['no_cache'])) { |
120
|
|
|
$noCache = $deviceConfig['options']['no_cache'] ? 1 : 0; |
121
|
|
|
} |
122
|
|
|
if ($noCache) { |
123
|
|
|
$this->loggerInstance->debug(5, "getCache: the no_cache option set for this device\n"); |
124
|
|
|
return(FALSE); |
125
|
|
|
} |
126
|
|
|
$this->loggerInstance->debug(5, "getCache: caching option set for this device\n"); |
127
|
|
|
$cache = $profile->testCache($device); |
128
|
|
|
$iPath = $cache['cache']; |
129
|
|
|
if ($iPath && is_file($iPath)) { |
130
|
|
|
return(['path' => $iPath, 'mime' => $cache['mime']]); |
131
|
|
|
} |
132
|
|
|
return(FALSE); |
133
|
|
|
} |
134
|
|
|
|
135
|
|
|
/** |
136
|
|
|
* Generates a new installer for the given combination of device and Profile |
137
|
|
|
* |
138
|
|
|
* @param string $device |
139
|
|
|
* @param AbstractProfile $profile |
140
|
|
|
* @return array info about the new installer (mime and link) |
141
|
|
|
*/ |
142
|
|
|
private function generateNewInstaller($device, $profile, $generatedFor, $token, $password) { |
143
|
|
|
$this->loggerInstance->debug(5, "generateNewInstaller() - Enter"); |
144
|
|
|
$factory = new DeviceFactory($device); |
145
|
|
|
$this->loggerInstance->debug(5, "generateNewInstaller() - created Device"); |
146
|
|
|
$dev = $factory->device; |
147
|
|
|
$out = []; |
148
|
|
|
if (isset($dev)) { |
149
|
|
|
$dev->setup($profile, $token, $password); |
150
|
|
|
$this->loggerInstance->debug(5, "generateNewInstaller() - Device setup done"); |
151
|
|
|
$installer = $dev->writeInstaller(); |
152
|
|
|
$this->loggerInstance->debug(5, "generateNewInstaller() - writeInstaller complete"); |
153
|
|
|
$iPath = $dev->FPATH . '/tmp/' . $installer; |
154
|
|
|
if ($iPath && is_file($iPath)) { |
155
|
|
|
if (isset($dev->options['mime'])) { |
156
|
|
|
$out['mime'] = $dev->options['mime']; |
157
|
|
|
} else { |
158
|
|
|
$info = new \finfo(); |
159
|
|
|
$out['mime'] = $info->file($iPath, FILEINFO_MIME_TYPE); |
160
|
|
|
} |
161
|
|
|
$this->installerPath = $dev->FPATH . '/' . $installer; |
162
|
|
|
rename($iPath, $this->installerPath); |
163
|
|
|
$integerEap = (new \core\common\EAP($dev->selectedEap))->getIntegerRep(); |
164
|
|
|
$profile->updateCache($device, $this->installerPath, $out['mime'], $integerEap); |
165
|
|
|
if (CONFIG['DEBUG_LEVEL'] < 4) { |
166
|
|
|
\core\common\Entity::rrmdir($dev->FPATH . '/tmp'); |
167
|
|
|
} |
168
|
|
|
$this->loggerInstance->debug(4, "Generated installer: " . $this->installerPath . ": for: $device, EAP:" . $integerEap . "\n"); |
169
|
|
|
$out['link'] = "API.php?action=downloadInstaller&lang=" . $this->languageInstance->getLang() . "&profile=" . $profile->identifier . "&device=$device&generatedfor=$generatedFor"; |
170
|
|
|
} else { |
171
|
|
|
$this->loggerInstance->debug(2, "Installer generation failed for: " . $profile->identifier . ":$device:" . $this->languageInstance->getLang() . "\n"); |
172
|
|
|
$out['link'] = 0; |
173
|
|
|
} |
174
|
|
|
} |
175
|
|
|
return($out); |
176
|
|
|
} |
177
|
|
|
|
178
|
|
|
/** |
179
|
|
|
* interface to Devices::listDevices() |
180
|
|
|
*/ |
181
|
|
|
public function listDevices($showHidden = 0) { |
182
|
|
|
$dev = \devices\Devices::listDevices(); |
183
|
|
|
$returnList = []; |
184
|
|
|
$count = 0; |
185
|
|
|
if ($showHidden !== 0 && $showHidden != 1) { |
186
|
|
|
throw new Exception("show_hidden is only be allowed to be 0 or 1, but it is $showHidden!"); |
187
|
|
|
} |
188
|
|
|
foreach ($dev as $device => $deviceProperties) { |
189
|
|
|
if (\core\common\Entity::getAttributeValue($deviceProperties, 'options', 'hidden') === 1 && $showHidden === 0) { |
190
|
|
|
continue; |
191
|
|
|
} |
192
|
|
|
$count++; |
193
|
|
|
$deviceProperties['device'] = $device; |
194
|
|
|
$group = isset($deviceProperties['group']) ? $deviceProperties['group'] : 'other'; |
195
|
|
|
if (!isset($returnList[$group])) { |
196
|
|
|
$returnList[$group] = []; |
197
|
|
|
} |
198
|
|
|
$returnList[$group][$device] = $deviceProperties; |
199
|
|
|
} |
200
|
|
|
return $returnList; |
201
|
|
|
} |
202
|
|
|
|
203
|
|
|
/** |
204
|
|
|
* |
205
|
|
|
* @param string $device |
206
|
|
|
* @param int $profileId |
207
|
|
|
*/ |
208
|
|
|
public function deviceInfo($device, $profileId) { |
209
|
|
|
$this->languageInstance->setTextDomain("devices"); |
210
|
|
|
$validator = new \web\lib\common\InputValidation(); |
211
|
|
|
$out = 0; |
212
|
|
|
$profile = $validator->Profile($profileId); |
213
|
|
|
$factory = new DeviceFactory($device); |
214
|
|
|
$dev = $factory->device; |
215
|
|
|
if (isset($dev)) { |
216
|
|
|
$dev->setup($profile); |
217
|
|
|
$out = $dev->writeDeviceInfo(); |
218
|
|
|
} |
219
|
|
|
$this->languageInstance->setTextDomain("web_user"); |
220
|
|
|
echo $out; |
221
|
|
|
} |
222
|
|
|
|
223
|
|
|
/** |
224
|
|
|
* Prepare the support data for a given profile |
225
|
|
|
* |
226
|
|
|
* @param int $profId profile identifier |
227
|
|
|
* @return array |
228
|
|
|
* array with the following fields: |
229
|
|
|
* - local_email |
230
|
|
|
* - local_phone |
231
|
|
|
* - local_url |
232
|
|
|
* - description |
233
|
|
|
* - devices - an array of device names and their statuses (for a given profile) |
234
|
|
|
*/ |
235
|
|
|
public function profileAttributes($profId) { |
236
|
|
|
$this->languageInstance->setTextDomain("devices"); |
237
|
|
|
$validator = new \web\lib\common\InputValidation(); |
238
|
|
|
$profile = $validator->Profile($profId); |
239
|
|
|
$attribs = $profile->getCollapsedAttributes(); |
240
|
|
|
$returnArray = []; |
241
|
|
|
$returnArray['silverbullet'] = $profile instanceof ProfileSilverbullet ? 1 : 0; |
242
|
|
|
if (isset($attribs['support:email'])) { |
243
|
|
|
$returnArray['local_email'] = $attribs['support:email'][0]; |
244
|
|
|
} |
245
|
|
|
if (isset($attribs['support:phone'])) { |
246
|
|
|
$returnArray['local_phone'] = $attribs['support:phone'][0]; |
247
|
|
|
} |
248
|
|
|
if (isset($attribs['support:url'])) { |
249
|
|
|
$returnArray['local_url'] = $attribs['support:url'][0]; |
250
|
|
|
} |
251
|
|
|
if (isset($attribs['profile:description'])) { |
252
|
|
|
$returnArray['description'] = $attribs['profile:description'][0]; |
253
|
|
|
} |
254
|
|
|
$returnArray['devices'] = $profile->listDevices(); |
255
|
|
|
$this->languageInstance->setTextDomain("web_user"); |
256
|
|
|
return($returnArray); |
257
|
|
|
} |
258
|
|
|
|
259
|
|
|
/** |
260
|
|
|
* Generate and send the installer |
261
|
|
|
* |
262
|
|
|
* @param string $device identifier as in {@link devices.php} |
263
|
|
|
* @param int $prof_id profile identifier |
264
|
|
|
* @return string binary stream: installerFile |
265
|
|
|
*/ |
266
|
|
|
public function downloadInstaller($device, $prof_id, $generated_for = 'user', $token = NULL, $password = NULL) { |
267
|
|
|
$this->loggerInstance->debug(4, "downloadInstaller arguments: $device,$prof_id,$generated_for\n"); |
268
|
|
|
$output = $this->generateInstaller($device, $prof_id, $generated_for, $token, $password); |
269
|
|
|
$this->loggerInstance->debug(4, "output from GUI::generateInstaller:"); |
270
|
|
|
$this->loggerInstance->debug(4, print_r($output, true)); |
271
|
|
|
if (empty($output['link']) || $output['link'] === 0) { |
272
|
|
|
header("HTTP/1.0 404 Not Found"); |
273
|
|
|
return; |
274
|
|
|
} |
275
|
|
|
$validator = new \web\lib\common\InputValidation(); |
276
|
|
|
$profile = $validator->Profile($prof_id); |
277
|
|
|
$profile->incrementDownloadStats($device, $generated_for); |
278
|
|
|
$file = $this->installerPath; |
279
|
|
|
$filetype = $output['mime']; |
280
|
|
|
$this->loggerInstance->debug(4, "installer MIME type:$filetype\n"); |
281
|
|
|
header("Content-type: " . $filetype); |
282
|
|
|
header('Content-Disposition: inline; filename="' . basename($file) . '"'); |
283
|
|
|
header('Content-Length: ' . filesize($file)); |
284
|
|
|
ob_clean(); |
285
|
|
|
flush(); |
286
|
|
|
readfile($file); |
287
|
|
|
} |
288
|
|
|
|
289
|
|
|
/** |
290
|
|
|
* resizes image files |
291
|
|
|
* |
292
|
|
|
* @param string $inputImage |
293
|
|
|
* @param string $destFile |
294
|
|
|
* @param int $width |
295
|
|
|
* @param int $height |
296
|
|
|
* @param bool $resize shall we do resizing? width and height are ignored otherwise |
297
|
|
|
* @return array |
298
|
|
|
*/ |
299
|
|
|
private function processImage($inputImage, $destFile, $width, $height, $resize) { |
300
|
|
|
$info = new \finfo(); |
301
|
|
|
$filetype = $info->buffer($inputImage, FILEINFO_MIME_TYPE); |
302
|
|
|
$offset = 60 * 60 * 24 * 30; |
303
|
|
|
// gmdate cannot fail here - time() is its default argument (and integer), and we are adding an integer to it |
304
|
|
|
$expiresString = "Expires: " . /** @scrutinizer ignore-type */ gmdate("D, d M Y H:i:s", time() + $offset) . " GMT"; |
305
|
|
|
$blob = $inputImage; |
306
|
|
|
|
307
|
|
|
if ($resize === TRUE) { |
308
|
|
|
$image = new \Imagick(); |
309
|
|
|
$image->readImageBlob($inputImage); |
310
|
|
|
$image->setImageFormat('PNG'); |
311
|
|
|
$image->thumbnailImage($width, $height, 1); |
312
|
|
|
$blob = $image->getImageBlob(); |
313
|
|
|
$this->loggerInstance->debug(4, "Writing cached logo $destFile for IdP/Federation.\n"); |
314
|
|
|
file_put_contents($destFile, $blob); |
315
|
|
|
} |
316
|
|
|
|
317
|
|
|
return ["filetype" => $filetype, "expires" => $expiresString, "blob" => $blob]; |
318
|
|
|
} |
319
|
|
|
|
320
|
|
|
/** |
321
|
|
|
* Get and prepare logo file |
322
|
|
|
* |
323
|
|
|
* When called for DiscoJuice, first check if file cache exists |
324
|
|
|
* If not then generate the file and save it in the cache |
325
|
|
|
* @param int $identifier IdP of Federation identifier |
326
|
|
|
* @param string either 'idp' or 'federation' is allowed |
327
|
|
|
* @param int $width maximum width of the generated image - if 0 then it is treated as no upper bound |
328
|
|
|
* @param int $height maximum height of the generated image - if 0 then it is treated as no upper bound |
329
|
|
|
* @return array|null array with image information or NULL if there is no logo |
330
|
|
|
*/ |
331
|
|
|
protected function getLogo($identifier, $type, $width = 0, $height = 0) { |
332
|
|
|
$expiresString = ''; |
333
|
|
|
$resize = FALSE; |
334
|
|
|
$attributeName = [ |
335
|
|
|
'federation' => "fed:logo_file", |
336
|
|
|
'idp' => "general:logo_file", |
337
|
|
|
]; |
338
|
|
|
|
339
|
|
|
$logoFile = ""; |
340
|
|
|
$validator = new \web\lib\common\InputValidation(); |
341
|
|
|
switch ($type) { |
342
|
|
|
case "federation": |
343
|
|
|
$entity = $validator->Federation($identifier); |
344
|
|
|
break; |
345
|
|
|
case "idp": |
346
|
|
|
$entity = $validator->IdP($identifier); |
347
|
|
|
break; |
348
|
|
|
default: |
349
|
|
|
throw new Exception("Unknown type of logo requested!"); |
350
|
|
|
} |
351
|
|
|
$filetype = 'image/png'; // default, only one code path where it can become different |
352
|
|
|
list($width, $height, $resize) = $this->testForResize($width, $height); |
353
|
|
|
if ($resize) { |
354
|
|
|
$logoFile = ROOT . '/web/downloads/logos/' . $identifier . '_' . $width . '_' . $height . '.png'; |
355
|
|
|
} |
356
|
|
|
if (is_file($logoFile)) { // $logoFile could be an empty string but then we will get a FALSE |
357
|
|
|
$this->loggerInstance->debug(4, "Using cached logo $logoFile for: $identifier\n"); |
358
|
|
|
$blob = file_get_contents($logoFile); |
359
|
|
|
} else { |
360
|
|
|
$logoAttribute = $entity->getAttributes($attributeName[$type]); |
361
|
|
|
if (count($logoAttribute) == 0) { |
362
|
|
|
return(NULL); |
363
|
|
|
} |
364
|
|
|
$this->loggerInstance->debug(4,"RESIZE:$width:$height\n"); |
365
|
|
|
$meta = $this->processImage($logoAttribute[0]['value'], $logoFile, $width, $height, $resize); |
366
|
|
|
$filetype = $meta['filetype']; |
367
|
|
|
$expiresString = $meta['expires']; |
368
|
|
|
$blob = $meta['blob']; |
369
|
|
|
} |
370
|
|
|
return ["filetype" => $filetype, "expires" => $expiresString, "blob" => $blob]; |
371
|
|
|
} |
372
|
|
|
|
373
|
|
|
private function testForResize($width, $height) { |
374
|
|
|
if (is_numeric($width) && is_numeric($height) && ($width > 0 || $height > 0)) { |
375
|
|
|
if ($height == 0) { |
376
|
|
|
$height = 10000; |
377
|
|
|
} |
378
|
|
|
if ($width == 0) { |
379
|
|
|
$width = 10000; |
380
|
|
|
} |
381
|
|
|
$resize = TRUE; |
382
|
|
|
} else { |
383
|
|
|
$width = 0; |
384
|
|
|
$height = 0; |
385
|
|
|
$resize = FALSE; |
386
|
|
|
} |
387
|
|
|
return ([$width, $height, $resize]); |
388
|
|
|
} |
389
|
|
|
|
390
|
|
|
/** |
391
|
|
|
* find out where the user is currently located |
392
|
|
|
* @return array |
393
|
|
|
*/ |
394
|
|
|
public function locateUser() { |
395
|
|
|
$loc = new \core\UserLocation(); |
396
|
|
|
return($loc->location); |
397
|
|
|
} |
398
|
|
|
|
399
|
|
|
|
400
|
|
|
/** |
401
|
|
|
* Calculate the distance in km between two points given their |
402
|
|
|
* geo coordinates. |
403
|
|
|
* @param array $point1 - first point as an 'lat', 'lon' array |
404
|
|
|
* @param array $profile1 - second point as an 'lat', 'lon' array |
405
|
|
|
* @return float distance in km |
406
|
|
|
*/ |
407
|
|
|
private function geoDistance($point1, $profile1) { |
408
|
|
|
|
409
|
|
|
$distIntermediate = sin(deg2rad($point1['lat'])) * sin(deg2rad($profile1['lat'])) + |
410
|
|
|
cos(deg2rad($point1['lat'])) * cos(deg2rad($profile1['lat'])) * cos(deg2rad($point1['lon'] - $profile1['lon'])); |
411
|
|
|
$dist = rad2deg(acos($distIntermediate)) * 60 * 1.1852; |
412
|
|
|
return(round($dist)); |
413
|
|
|
} |
414
|
|
|
|
415
|
|
|
/** |
416
|
|
|
* Order active identity providers according to their distance and name |
417
|
|
|
* @param array $currentLocation - current location |
418
|
|
|
* @return array $IdPs - list of arrays ('id', 'name'); |
419
|
|
|
*/ |
420
|
|
|
public function orderIdentityProviders($country, $currentLocation = NULL) { |
421
|
|
|
$idps = $this->listAllIdentityProviders(1, $country); |
422
|
|
|
$here = $this->setCurrentLocation($currentLocation); |
423
|
|
|
$idpTitle = []; |
424
|
|
|
$resultSet = []; |
425
|
|
|
foreach ($idps as $idp) { |
426
|
|
|
$idpTitle[$idp['entityID']] = $idp['title']; |
427
|
|
|
$d = $this->getIdpDistance($idp, $here); |
428
|
|
|
$resultSet[$idp['entityID']] = $d . " " . $idp['title']; |
429
|
|
|
} |
430
|
|
|
asort($resultSet); |
431
|
|
|
$outarray = []; |
432
|
|
|
foreach (array_keys($resultSet) as $r) { |
433
|
|
|
$outarray[] = ['idp' => $r, 'title' => $idpTitle[$r]]; |
434
|
|
|
} |
435
|
|
|
return($outarray); |
436
|
|
|
} |
437
|
|
|
|
438
|
|
|
private function setCurrentLocation($currentLocation) { |
439
|
|
|
if (is_null($currentLocation)) { |
440
|
|
|
$currentLocation = ['lat' => "90", 'lon' => "0"]; |
441
|
|
|
$userLocation = $this->locateUser(); |
442
|
|
|
if ($userLocation['status'] == 'ok') { |
443
|
|
|
$currentLocation = $userLocation['geo']; |
444
|
|
|
} |
445
|
|
|
} |
446
|
|
|
return($currentLocation); |
447
|
|
|
} |
448
|
|
|
|
449
|
|
|
private function getIdpDistance($idp, $location) { |
450
|
|
|
$dist = 10000; |
451
|
|
|
if (isset($idp['geo'])) { |
452
|
|
|
$G = $idp['geo']; |
453
|
|
|
if (isset($G['lon'])) { |
454
|
|
|
$d1 = $this->geoDistance($location, $G); |
455
|
|
|
if ($d1 < $dist) { |
456
|
|
|
$dist = $d1; |
457
|
|
|
} |
458
|
|
|
} else { |
459
|
|
|
foreach ($G as $g) { |
460
|
|
|
$d1 = $this->geoDistance($location, $g); |
461
|
|
|
if ($d1 < $dist) { |
462
|
|
|
$dist = $d1; |
463
|
|
|
} |
464
|
|
|
} |
465
|
|
|
} |
466
|
|
|
} |
467
|
|
|
if ($dist > 100) { |
468
|
|
|
$dist = 10000; |
469
|
|
|
} |
470
|
|
|
return(sprintf("%06d", $dist)); |
471
|
|
|
} |
472
|
|
|
|
473
|
|
|
/** |
474
|
|
|
* Detect the best device driver form the browser |
475
|
|
|
* Detects the operating system and returns its id |
476
|
|
|
* display name and group membership (as in devices.php) |
477
|
|
|
* @return array|FALSE OS information, indexed by 'id', 'display', 'group' |
478
|
|
|
*/ |
479
|
|
|
public function detectOS() { |
480
|
|
|
$oldDomain = $this->languageInstance->setTextDomain("devices"); |
481
|
|
|
$Dev = \devices\Devices::listDevices(); |
482
|
|
|
$this->languageInstance->setTextDomain($oldDomain); |
483
|
|
|
$devId = $this->deviceFromRequest(); |
484
|
|
|
if ($devId !== FALSE) { |
485
|
|
|
$ret = $this->returnDevice($devId, $Dev[$devId]); |
486
|
|
|
if ($ret !== FALSE) { |
487
|
|
|
return($ret); |
488
|
|
|
} |
489
|
|
|
} |
490
|
|
|
// the device has not been specified or not specified correctly, try to detect if from the browser ID |
491
|
|
|
$browser = filter_input(INPUT_SERVER, 'HTTP_USER_AGENT', FILTER_SANITIZE_STRING); |
492
|
|
|
$this->loggerInstance->debug(4, "HTTP_USER_AGENT=$browser\n"); |
493
|
|
|
foreach ($Dev as $devId => $device) { |
494
|
|
|
if (!isset($device['match'])) { |
495
|
|
|
continue; |
496
|
|
|
} |
497
|
|
|
if (preg_match('/' . $device['match'] . '/', $browser)) { |
498
|
|
|
return ($this->returnDevice($devId, $device)); |
499
|
|
|
} |
500
|
|
|
} |
501
|
|
|
$this->loggerInstance->debug(2, "Unrecognised system: $browser\n"); |
502
|
|
|
return(false); |
503
|
|
|
} |
504
|
|
|
|
505
|
|
|
/* |
506
|
|
|
* test if devise is defined and is not hidden. If all is fine return extracted information. |
507
|
|
|
* Return FALSE if the device has not been correctly specified |
508
|
|
|
*/ |
509
|
|
|
private function returnDevice($devId, $device) { |
510
|
|
|
if (\core\common\Entity::getAttributeValue($device, 'options', 'hidden') !== 1) { |
511
|
|
|
$this->loggerInstance->debug(4, "Browser_id: $devId\n"); |
512
|
|
|
return(['device' => $devId, 'display' => $device['display'], 'group' => $device['group']]); |
513
|
|
|
} |
514
|
|
|
return(FALSE); |
515
|
|
|
} |
516
|
|
|
|
517
|
|
|
/** |
518
|
|
|
* This methods cheks if the devide has been specified as the HTTP parameters |
519
|
|
|
* @return device id|FALSE if correcty specified or FALSE otherwise |
520
|
|
|
*/ |
521
|
|
|
private function deviceFromRequest() { |
522
|
|
|
$devId = filter_input(INPUT_GET, 'device', FILTER_SANITIZE_STRING) ?? filter_input(INPUT_POST, 'device', FILTER_SANITIZE_STRING); |
523
|
|
|
if ($devId === NULL || $devId === FALSE) { |
524
|
|
|
$this->loggerInstance->debug(2, "Invalid device id provided\n"); |
525
|
|
|
return(FALSE); |
|
|
|
|
526
|
|
|
} |
527
|
|
|
$Dev = \devices\Devices::listDevices(); |
528
|
|
|
if (!isset($Dev['$devId'])) { |
529
|
|
|
$this->loggerInstance->debug(2, "Unrecognised system: $devId\n"); |
530
|
|
|
return(FALSE); |
|
|
|
|
531
|
|
|
} |
532
|
|
|
return($devId); |
533
|
|
|
} |
534
|
|
|
|
535
|
|
|
/** |
536
|
|
|
* finds all the user certificates that originated in a given token |
537
|
|
|
* @param string $token |
538
|
|
|
* @return array|false returns FALSE if a token is invalid, otherwise array of certs |
539
|
|
|
*/ |
540
|
|
|
public function getUserCerts($token) { |
541
|
|
|
$validator = new \web\lib\common\InputValidation(); |
542
|
|
|
$cleanToken = $validator->token($token); |
543
|
|
|
if ($cleanToken) { |
544
|
|
|
// check status of this silverbullet token according to info in DB: |
545
|
|
|
// it can be VALID (exists and not redeemed, EXPIRED, REDEEMED or INVALID (non existent) |
546
|
|
|
$invitationObject = new \core\SilverbulletInvitation($cleanToken); |
547
|
|
|
} else { |
548
|
|
|
return false; |
549
|
|
|
} |
550
|
|
|
$profile = new \core\ProfileSilverbullet($invitationObject->profile, NULL); |
551
|
|
|
$userdata = $profile->userStatus($invitationObject->userId); |
552
|
|
|
$allcerts = []; |
553
|
|
|
foreach ($userdata as $content) { |
554
|
|
|
$allcerts = array_merge($allcerts, $content->associatedCertificates); |
555
|
|
|
} |
556
|
|
|
return $allcerts; |
557
|
|
|
} |
558
|
|
|
|
559
|
|
|
public $device; |
560
|
|
|
private $installerPath; |
561
|
|
|
|
562
|
|
|
/** |
563
|
|
|
* helper function to sort profiles by their name |
564
|
|
|
* @param \core\AbstractProfile $profile1 the first profile's information |
565
|
|
|
* @param \core\AbstractProfile $profile2 the second profile's information |
566
|
|
|
* @return int |
567
|
|
|
*/ |
568
|
|
|
private static function profileSort($profile1, $profile2) { |
|
|
|
|
569
|
|
|
return strcasecmp($profile1->name, $profile2->name); |
570
|
|
|
} |
571
|
|
|
|
572
|
|
|
} |
573
|
|
|
|
If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.
Let’s take a look at an example:
Our function
my_function
expects aPost
object, and outputs the author of the post. The base classPost
returns a simple string and outputting a simple string will work just fine. However, the child classBlogPost
which is a sub-type ofPost
instead decided to return anobject
, and is therefore violating the SOLID principles. If aBlogPost
were passed tomy_function
, PHP would not complain, but ultimately fail when executing thestrtoupper
call in its body.