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
|
|
|
/** |
24
|
|
|
* This is the collection of methods dedicated for the user GUI |
25
|
|
|
* @author Tomasz Wolniewicz <[email protected]> |
26
|
|
|
* @author Stefan Winter <[email protected]> |
27
|
|
|
* @package UserAPI |
28
|
|
|
* |
29
|
|
|
* Parts of this code are based on simpleSAMLPhp discojuice module. |
30
|
|
|
* This product includes GeoLite data created by MaxMind, available from |
31
|
|
|
* http://www.maxmind.com |
32
|
|
|
*/ |
33
|
|
|
|
34
|
|
|
namespace core; |
35
|
|
|
|
36
|
|
|
use \Exception; |
|
|
|
|
37
|
|
|
|
38
|
|
|
/** |
39
|
|
|
* The basic methoods for the user GUI |
40
|
|
|
* @package UserAPI |
41
|
|
|
* |
42
|
|
|
*/ |
43
|
|
|
class UserAPI extends CAT |
44
|
|
|
{ |
45
|
|
|
|
46
|
|
|
/** |
47
|
|
|
* nothing special to be done here. |
48
|
|
|
*/ |
49
|
|
|
public function __construct() |
50
|
|
|
{ |
51
|
|
|
parent::__construct(); |
52
|
|
|
} |
53
|
|
|
|
54
|
|
|
/** |
55
|
|
|
* Prepare the device module environment and send back the link |
56
|
|
|
* This method creates a device module instance via the {@link DeviceFactory} call, |
57
|
|
|
* then sets up the device module environment for the specific profile by calling |
58
|
|
|
* {@link DeviceConfig::setup()} method and finally, called the device writeInstaller method |
59
|
|
|
* passing the returned path name. |
60
|
|
|
* |
61
|
|
|
* @param string $device identifier as in {@link devices.php} |
62
|
|
|
* @param int $profileId profile identifier |
63
|
|
|
* @param string $generatedFor which download area does this pertain to |
64
|
|
|
* @param string $token for silverbullet: invitation token to consume |
65
|
|
|
* @param string $password for silverbull: import PIN for the future certificate |
66
|
|
|
* |
67
|
|
|
* @return array|NULL array with the following fields: |
68
|
|
|
* profile - the profile identifier; |
69
|
|
|
* device - the device identifier; |
70
|
|
|
* link - the path name of the resulting installer |
71
|
|
|
* mime - the mimetype of the installer |
72
|
|
|
*/ |
73
|
|
|
public function generateInstaller($device, $profileId, $generatedFor = "user", $openRoaming = 0, $token = NULL, $password = NULL) |
74
|
|
|
{ |
75
|
|
|
$this->loggerInstance->debug(4, "generateInstaller arguments:$device:$profileId:$openRoaming\n"); |
76
|
|
|
$validator = new \web\lib\common\InputValidation(); |
77
|
|
|
$profile = $validator->existingProfile($profileId); |
78
|
|
|
// test if the profile is production-ready and if not if the authenticated user is an owner |
79
|
|
|
if ($this->verifyDownloadAccess($profile) === FALSE) { |
80
|
|
|
return; |
81
|
|
|
} |
82
|
|
|
$installerProperties = []; |
83
|
|
|
$installerProperties['profile'] = $profileId; |
84
|
|
|
$installerProperties['device'] = $device; |
85
|
|
|
$cache = $this->getCache($device, $profile, $openRoaming); |
86
|
|
|
$this->installerPath = $cache['path']; |
87
|
|
|
if ($this->installerPath !== NULL && $token === NULL && $password === NULL) { |
88
|
|
|
$this->loggerInstance->debug(4, "Using cached installer for: $device\n"); |
89
|
|
|
$installerProperties['link'] = "user/API.php?action=downloadInstaller&lang=".$this->languageInstance->getLang()."&profile=$profileId&device=$device&generatedfor=$generatedFor&openroaming=$openRoaming"; |
90
|
|
|
$installerProperties['mime'] = $cache['mime']; |
91
|
|
|
} else { |
92
|
|
|
$myInstaller = $this->generateNewInstaller($device, $profile, $generatedFor, $openRoaming, $token, $password); |
93
|
|
|
if ($myInstaller['link'] !== 0) { |
94
|
|
|
$installerProperties['mime'] = $myInstaller['mime']; |
95
|
|
|
} |
96
|
|
|
$installerProperties['link'] = $myInstaller['link']; |
97
|
|
|
} |
98
|
|
|
return $installerProperties; |
99
|
|
|
} |
100
|
|
|
|
101
|
|
|
/** |
102
|
|
|
* checks whether the requested profile data is public, XOR was requested by |
103
|
|
|
* its own admin. |
104
|
|
|
* @param \core\AbstractProfile $profile the profile in question |
105
|
|
|
* @return boolean |
106
|
|
|
*/ |
107
|
|
|
private function verifyDownloadAccess($profile) |
108
|
|
|
{ |
109
|
|
|
$attribs = $profile->getCollapsedAttributes(); |
110
|
|
|
if (\core\common\Entity::getAttributeValue($attribs, 'profile:production', 0) !== 'on') { |
111
|
|
|
$this->loggerInstance->debug(4, "Attempt to download a non-production ready installer for profile: $profile->identifier\n"); |
112
|
|
|
$auth = new \web\lib\admin\Authentication(); |
113
|
|
|
if (!$auth->isAuthenticated()) { |
114
|
|
|
$this->loggerInstance->debug(2, "User NOT authenticated, rejecting request for a non-production installer\n"); |
115
|
|
|
header("HTTP/1.0 403 Not Authorized"); |
116
|
|
|
return FALSE; |
117
|
|
|
} |
118
|
|
|
$auth->authenticate(); |
119
|
|
|
$userObject = new User($_SESSION['user']); |
120
|
|
|
if (!$userObject->isIdPOwner($profile->institution)) { |
121
|
|
|
$this->loggerInstance->debug(2, "User not an owner of a non-production profile - access forbidden\n"); |
122
|
|
|
header("HTTP/1.0 403 Not Authorized"); |
123
|
|
|
return FALSE; |
124
|
|
|
} |
125
|
|
|
$this->loggerInstance->debug(4, "User is the owner - allowing access\n"); |
126
|
|
|
} |
127
|
|
|
return TRUE; |
128
|
|
|
} |
129
|
|
|
|
130
|
|
|
/** |
131
|
|
|
* This function tries to find a cached copy of an installer for a given |
132
|
|
|
* combination of Profile and device |
133
|
|
|
* |
134
|
|
|
* @param string $device the device for which the installer is searched in cache |
135
|
|
|
* @param AbstractProfile $profile the profile for which the installer is searched in cache |
136
|
|
|
* @return array containing path to the installer and mime type of the file, the path is set to NULL if no cache can be returned |
137
|
|
|
*/ |
138
|
|
|
private function getCache($device, $profile, $openRoaming) |
139
|
|
|
{ |
140
|
|
|
$deviceConfig = \devices\Devices::listDevices()[$device]; |
141
|
|
|
$noCache = (isset(\devices\Devices::$Options['no_cache']) && \devices\Devices::$Options['no_cache']) ? 1 : 0; |
142
|
|
|
if (isset($deviceConfig['options']['no_cache'])) { |
143
|
|
|
$noCache = $deviceConfig['options']['no_cache'] ? 1 : 0; |
144
|
|
|
} |
145
|
|
|
if ($noCache) { |
146
|
|
|
$this->loggerInstance->debug(5, "getCache: the no_cache option set for this device\n"); |
147
|
|
|
return ['path' => NULL, 'mime' => NULL]; |
148
|
|
|
} |
149
|
|
|
$this->loggerInstance->debug(5, "getCache: caching option set for this device\n"); |
150
|
|
|
$cache = $profile->testCache($device, $openRoaming); |
151
|
|
|
$iPath = $cache['cache']; |
152
|
|
|
if ($iPath && is_file($iPath)) { |
153
|
|
|
return ['path' => $iPath, 'mime' => $cache['mime']]; |
154
|
|
|
} |
155
|
|
|
return ['path' => NULL, 'mime' => NULL]; |
156
|
|
|
} |
157
|
|
|
|
158
|
|
|
/** |
159
|
|
|
* Generates a new installer for the given combination of device and Profile |
160
|
|
|
* |
161
|
|
|
* @param string $device the device for which we want an installer |
162
|
|
|
* @param AbstractProfile $profile the profile for which we want an installer |
163
|
|
|
* @param string $generatedFor type of download requested (admin/user/silverbullet) |
164
|
|
|
* @param int $openRoaming values 0 o 1 to indicate support for open roaming in the installer |
165
|
|
|
* @param string $token in case of silverbullet, the token that was used to trigger the generation |
166
|
|
|
* @param string $password in case of silverbullet, the import PIN for the future client certificate |
167
|
|
|
* @return array info about the new installer (mime and link) |
168
|
|
|
*/ |
169
|
|
|
private function generateNewInstaller($device, $profile, $generatedFor, $openRoaming, $token, $password) |
170
|
|
|
{ |
171
|
|
|
$this->loggerInstance->debug(5, "generateNewInstaller() - Enter"); |
172
|
|
|
$this->loggerInstance->debug(5, "generateNewInstaller:openRoaming:$openRoaming\n"); |
173
|
|
|
$factory = new DeviceFactory($device); |
174
|
|
|
$this->loggerInstance->debug(5, "generateNewInstaller() - created Device"); |
175
|
|
|
$dev = $factory->device; |
176
|
|
|
$out = []; |
177
|
|
|
if (isset($dev)) { |
178
|
|
|
$dev->setup($profile, $token, $password, $openRoaming); |
179
|
|
|
$this->loggerInstance->debug(5, "generateNewInstaller() - Device setup done"); |
180
|
|
|
$installer = $dev->writeInstaller(); |
181
|
|
|
$this->loggerInstance->debug(5, "generateNewInstaller() - writeInstaller complete"); |
182
|
|
|
$iPath = $dev->FPATH.'/tmp/'.$installer; |
183
|
|
|
if ($iPath && is_file($iPath)) { |
184
|
|
|
if (isset($dev->options['mime'])) { |
185
|
|
|
$out['mime'] = $dev->options['mime']; |
186
|
|
|
} else { |
187
|
|
|
$info = new \finfo(); |
188
|
|
|
$out['mime'] = $info->file($iPath, FILEINFO_MIME_TYPE); |
189
|
|
|
} |
190
|
|
|
$this->installerPath = $dev->FPATH.'/'.$installer; |
191
|
|
|
rename($iPath, $this->installerPath); |
192
|
|
|
$integerEap = (new \core\common\EAP($dev->selectedEap))->getIntegerRep(); |
193
|
|
|
$profile->updateCache($device, $this->installerPath, $out['mime'], $integerEap, $openRoaming); |
194
|
|
|
if (\config\Master::DEBUG_LEVEL < 4) { |
195
|
|
|
\core\common\Entity::rrmdir($dev->FPATH.'/tmp'); |
196
|
|
|
} |
197
|
|
|
$this->loggerInstance->debug(4, "Generated installer: ".$this->installerPath.": for: $device, EAP:".$integerEap.", openRoaming: $openRoaming\n"); |
198
|
|
|
$out['link'] = "user/API.php?action=downloadInstaller&lang=".$this->languageInstance->getLang()."&profile=".$profile->identifier."&device=$device&generatedfor=$generatedFor&openroaming=$openRoaming"; |
199
|
|
|
} else { |
200
|
|
|
$this->loggerInstance->debug(2, "Installer generation failed for: ".$profile->identifier.":$device:".$this->languageInstance->getLang()."openRoaming: $openRoaming\n"); |
201
|
|
|
$out['link'] = 0; |
202
|
|
|
} |
203
|
|
|
} |
204
|
|
|
return $out; |
205
|
|
|
} |
206
|
|
|
|
207
|
|
|
/** |
208
|
|
|
* interface to Devices::listDevices() |
209
|
|
|
* |
210
|
|
|
* @param int $showHidden whether or not hidden devices should be shown |
211
|
|
|
* @return array the list of devices |
212
|
|
|
* @throws Exception |
213
|
|
|
*/ |
214
|
|
|
public function listDevices($showHidden = 0) |
215
|
|
|
{ |
216
|
|
|
$returnList = []; |
217
|
|
|
$count = 0; |
218
|
|
|
if ($showHidden !== 0 && $showHidden != 1) { |
219
|
|
|
throw new Exception("show_hidden is only be allowed to be 0 or 1, but it is $showHidden!"); |
220
|
|
|
} |
221
|
|
|
foreach (\devices\Devices::listDevices() as $device => $deviceProperties) { |
222
|
|
|
$hidden = \core\common\Entity::getAttributeValue($deviceProperties, 'options', 'hidden'); |
223
|
|
|
if (($hidden === 1 || $hidden === 2) && $showHidden === 0) { |
224
|
|
|
continue; |
225
|
|
|
} |
226
|
|
|
$count++; |
227
|
|
|
$deviceProperties['device'] = $device; |
228
|
|
|
$group = isset($deviceProperties['group']) ? $deviceProperties['group'] : 'other'; |
229
|
|
|
if (!isset($returnList[$group])) { |
230
|
|
|
$returnList[$group] = []; |
231
|
|
|
} |
232
|
|
|
$returnList[$group][$device] = $deviceProperties; |
233
|
|
|
} |
234
|
|
|
return $returnList; |
235
|
|
|
} |
236
|
|
|
|
237
|
|
|
/** |
238
|
|
|
* |
239
|
|
|
* @param string $device identifier of the device |
240
|
|
|
* @param int $profileId identifier of the profile |
241
|
|
|
* @return void |
242
|
|
|
*/ |
243
|
|
|
public function deviceInfo($device, $profileId) |
244
|
|
|
{ |
245
|
|
|
$validator = new \web\lib\common\InputValidation(); |
246
|
|
|
$out = 0; |
247
|
|
|
$profile = $validator->existingProfile($profileId); |
248
|
|
|
$factory = new DeviceFactory($device); |
249
|
|
|
$dev = $factory->device; |
250
|
|
|
if (isset($dev)) { |
251
|
|
|
$dev->setup($profile); |
252
|
|
|
$out = $dev->writeDeviceInfo(); |
253
|
|
|
} |
254
|
|
|
echo $out; |
255
|
|
|
} |
256
|
|
|
|
257
|
|
|
/** |
258
|
|
|
* Prepare the support data for a given profile |
259
|
|
|
* |
260
|
|
|
* @param int $profId profile identifier |
261
|
|
|
* @return array |
262
|
|
|
* array with the following fields: |
263
|
|
|
* - local_email |
264
|
|
|
* - local_phone |
265
|
|
|
* - local_url |
266
|
|
|
* - description |
267
|
|
|
* - devices - an array of device names and their statuses (for a given profile) |
268
|
|
|
* - last_changed |
269
|
|
|
*/ |
270
|
|
|
public function profileAttributes($profId) |
271
|
|
|
{ |
272
|
|
|
$validator = new \web\lib\common\InputValidation(); |
273
|
|
|
$profile = $validator->existingProfile($profId); |
274
|
|
|
$attribs = $profile->getCollapsedAttributes(); |
275
|
|
|
$returnArray = []; |
276
|
|
|
$returnArray['silverbullet'] = $profile instanceof ProfileSilverbullet ? 1 : 0; |
277
|
|
|
if (isset($attribs['support:email'])) { |
278
|
|
|
$returnArray['local_email'] = $attribs['support:email'][0]; |
279
|
|
|
} |
280
|
|
|
if (isset($attribs['support:phone'])) { |
281
|
|
|
$returnArray['local_phone'] = $attribs['support:phone'][0]; |
282
|
|
|
} |
283
|
|
|
if (isset($attribs['support:url'])) { |
284
|
|
|
$returnArray['local_url'] = $attribs['support:url'][0]; |
285
|
|
|
} |
286
|
|
|
if (isset($attribs['profile:description'])) { |
287
|
|
|
$returnArray['description'] = $attribs['profile:description'][0]; |
288
|
|
|
} |
289
|
|
|
if (isset($attribs['media:openroaming'])) { |
290
|
|
|
$returnArray['openroaming'] = $attribs['media:openroaming'][0]; |
291
|
|
|
} else { |
292
|
|
|
$returnArray['openroaming'] = 'none'; |
293
|
|
|
} |
294
|
|
|
$returnArray['devices'] = $profile->listDevices(); |
295
|
|
|
$returnArray['last_changed'] = $profile->getFreshness(); |
296
|
|
|
return $returnArray; |
297
|
|
|
} |
298
|
|
|
|
299
|
|
|
/** |
300
|
|
|
* Generate and send the installer |
301
|
|
|
* |
302
|
|
|
* @param string $device identifier as in {@link devices.php} |
303
|
|
|
* @param int $prof_id profile identifier |
304
|
|
|
* @param string $generated_for which download area does this pertain to |
305
|
|
|
* @param string $token for silverbullet: invitation token to consume |
306
|
|
|
* @param string $password for silverbull: import PIN for the future certificate |
307
|
|
|
* @return string binary stream: installerFile |
308
|
|
|
*/ |
309
|
|
|
public function downloadInstaller($device, $prof_id, $generated_for = 'user', $openRoaming = 0, $token = NULL, $password = NULL) |
310
|
|
|
{ |
311
|
|
|
$this->loggerInstance->debug(4, "downloadInstaller arguments: $device,$prof_id,$generated_for, $openRoaming\n"); |
312
|
|
|
$output = $this->generateInstaller($device, $prof_id, $generated_for, $openRoaming, $token, $password); |
313
|
|
|
$this->loggerInstance->debug(4, "output from GUI::generateInstaller:"); |
314
|
|
|
$this->loggerInstance->debug(4, print_r($output, true)); |
315
|
|
|
if (empty($output['link']) || $output['link'] === 0) { |
316
|
|
|
header("HTTP/1.0 404 Not Found"); |
317
|
|
|
return; |
318
|
|
|
} |
319
|
|
|
$validator = new \web\lib\common\InputValidation(); |
320
|
|
|
$profile = $validator->existingProfile($prof_id); |
321
|
|
|
$profile->incrementDownloadStats($device, $generated_for, $openRoaming); |
322
|
|
|
$file = $this->installerPath; |
323
|
|
|
$filetype = $output['mime']; |
324
|
|
|
$this->loggerInstance->debug(4, "installer MIME type:$filetype\n"); |
325
|
|
|
header("Content-type: ".$filetype); |
326
|
|
|
if ($filetype !== "application/x-wifi-config") { // for those installers to work on Android, Content-Disposition MUST NOT be set |
327
|
|
|
header('Content-Disposition: inline; filename="'.basename($file).'"'); |
328
|
|
|
} else { |
329
|
|
|
header('Content-Transfer-Encoding: base64'); |
330
|
|
|
} |
331
|
|
|
header('Content-Length: '.filesize($file)); |
332
|
|
|
ob_clean(); |
333
|
|
|
flush(); |
334
|
|
|
readfile($file); |
335
|
|
|
} |
336
|
|
|
|
337
|
|
|
/** |
338
|
|
|
* resizes image files |
339
|
|
|
* |
340
|
|
|
* @param string $inputImage the image we want to process |
341
|
|
|
* @param string $destFile the output file for the processed image |
342
|
|
|
* @param int $width if resizing, the target width |
343
|
|
|
* @param int $height if resizing, the target height |
344
|
|
|
* @param bool $resize shall we do resizing? width and height are ignored otherwise |
345
|
|
|
* @return array |
346
|
|
|
*/ |
347
|
|
|
private function processImage($inputImage, $destFile, $width, $height, $resize) |
348
|
|
|
{ |
349
|
|
|
$info = new \finfo(); |
350
|
|
|
$filetype = $info->buffer($inputImage, FILEINFO_MIME_TYPE); |
351
|
|
|
$expiresString = $this->logoExpireTime(); |
352
|
|
|
$blob = $inputImage; |
353
|
|
|
|
354
|
|
|
if ($resize === TRUE) { |
355
|
|
|
if (class_exists('\\Gmagick')) { |
356
|
|
|
$image = new \Gmagick(); |
357
|
|
|
} else { |
358
|
|
|
$image = new \Imagick(); |
359
|
|
|
} |
360
|
|
|
$image->readImageBlob($inputImage); |
361
|
|
|
$image->setImageFormat('PNG'); |
362
|
|
|
$image->thumbnailImage($width, $height, 1); |
363
|
|
|
$blob = $image->getImageBlob(); |
|
|
|
|
364
|
|
|
$this->loggerInstance->debug(4, "Writing cached logo $destFile for IdP/Federation.\n"); |
365
|
|
|
file_put_contents($destFile, $blob); |
366
|
|
|
} |
367
|
|
|
|
368
|
|
|
return ["filetype" => $filetype, "expires" => $expiresString, "blob" => $blob]; |
369
|
|
|
} |
370
|
|
|
|
371
|
|
|
protected function logoExpireTime() |
372
|
|
|
{ |
373
|
|
|
$offset = 60 * 60 * 24 * 30; |
374
|
|
|
// gmdate cannot fail here - time() is its default argument (and integer), and we are adding an integer to it |
375
|
|
|
return("Expires: "./** @scrutinizer ignore-type */ gmdate("D, d M Y H:i:s", time() + $offset)." GMT"); |
376
|
|
|
} |
377
|
|
|
/** |
378
|
|
|
* Get and prepare logo file |
379
|
|
|
* |
380
|
|
|
* When called for DiscoJuice, first check if file cache exists |
381
|
|
|
* If not then generate the file and save it in the cache |
382
|
|
|
* @param int|string $identifier IdP or Federation identifier |
383
|
|
|
* @param string $type either 'idp' or 'federation' is allowed |
384
|
|
|
* @param integer $widthIn maximum width of the generated image - if 0 then it is treated as no upper bound |
385
|
|
|
* @param integer $heightIn maximum height of the generated image - if 0 then it is treated as no upper bound |
386
|
|
|
* @return array|null array with image information or NULL if there is no logo |
387
|
|
|
* @throws Exception |
388
|
|
|
*/ |
389
|
|
|
protected function getLogo($identifier, $type, $widthIn, $heightIn) |
390
|
|
|
{ |
391
|
|
|
$expiresString = ''; |
392
|
|
|
$attributeName = [ |
393
|
|
|
'federation' => "fed:logo_file", |
394
|
|
|
'federation_from_idp' => "fed:logo_file", |
395
|
|
|
'idp' => "general:logo_file", |
396
|
|
|
]; |
397
|
|
|
|
398
|
|
|
$logoFile = ""; |
399
|
|
|
$validator = new \web\lib\common\InputValidation(); |
400
|
|
|
switch ($type) { |
401
|
|
|
case "federation": |
402
|
|
|
$entity = $validator->existingFederation($identifier); |
403
|
|
|
break; |
404
|
|
|
case "idp": |
405
|
|
|
$entity = $validator->existingIdP($identifier); |
406
|
|
|
break; |
407
|
|
|
case "federation_from_idp": |
408
|
|
|
$idp = $validator->existingIdP($identifier); |
409
|
|
|
$entity = $validator->existingFederation($idp->federation); |
410
|
|
|
break; |
411
|
|
|
default: |
412
|
|
|
throw new Exception("Unknown type of logo requested!"); |
413
|
|
|
} |
414
|
|
|
$filetype = 'image/png'; // default, only one code path where it can become different |
415
|
|
|
list($width, $height, $resize) = $this->testForResize($widthIn, $heightIn); |
416
|
|
|
if ($resize) { |
417
|
|
|
$logoFile = ROOT.'/web/downloads/logos/'.$identifier.'_'.$width.'_'.$height.'.png'; |
418
|
|
|
} |
419
|
|
|
if (is_file($logoFile)) { // $logoFile could be an empty string but then we will get a FALSE |
420
|
|
|
$this->loggerInstance->debug(4, "Using cached logo $logoFile for: $identifier\n"); |
421
|
|
|
$blob = file_get_contents($logoFile); |
422
|
|
|
} else { |
423
|
|
|
$logoAttribute = $entity->getAttributes($attributeName[$type]); |
424
|
|
|
if (count($logoAttribute) == 0) { |
425
|
|
|
$blob = file_get_contents(ROOT.'/web/resources/images/empty.png'); |
426
|
|
|
$expiresString = $this->logoExpireTime(); |
427
|
|
|
} else { |
428
|
|
|
$this->loggerInstance->debug(4, "RESIZE:$width:$height\n"); |
429
|
|
|
$meta = $this->processImage($logoAttribute[0]['value'], $logoFile, $width, $height, $resize); |
430
|
|
|
$filetype = $meta['filetype']; |
431
|
|
|
$expiresString = $meta['expires']; |
432
|
|
|
$blob = $meta['blob']; |
433
|
|
|
} |
434
|
|
|
} |
435
|
|
|
return ["filetype" => $filetype, "expires" => $expiresString, "blob" => $blob]; |
436
|
|
|
} |
437
|
|
|
|
438
|
|
|
/** |
439
|
|
|
* see if we have to resize an image |
440
|
|
|
* |
441
|
|
|
* @param integer $width the desired max width (0 = unbounded) |
442
|
|
|
* @param integer $height the desired max height (0 = unbounded) |
443
|
|
|
* @return array |
444
|
|
|
*/ |
445
|
|
|
private function testForResize($width, $height) |
446
|
|
|
{ |
447
|
|
|
if (is_numeric($width) && is_numeric($height) && ($width > 0 || $height > 0)) { |
448
|
|
|
if ($height == 0) { |
449
|
|
|
$height = 10000; |
450
|
|
|
} |
451
|
|
|
if ($width == 0) { |
452
|
|
|
$width = 10000; |
453
|
|
|
} |
454
|
|
|
return [$width, $height, TRUE]; |
455
|
|
|
} |
456
|
|
|
return [0, 0, FALSE]; |
457
|
|
|
} |
458
|
|
|
|
459
|
|
|
/** |
460
|
|
|
* find out where the device is currently located |
461
|
|
|
* @return array |
462
|
|
|
*/ |
463
|
|
|
public function locateDevice() |
464
|
|
|
{ |
465
|
|
|
return \core\DeviceLocation::locateDevice(); |
466
|
|
|
} |
467
|
|
|
|
468
|
|
|
/** |
469
|
|
|
* Lists all identity providers in the database |
470
|
|
|
* adding information required by DiscoJuice. |
471
|
|
|
* |
472
|
|
|
* @param int $activeOnly if set to non-zero will cause listing of only those institutions which have some valid profiles defined. |
473
|
|
|
* @param string $country if set, only list IdPs in a specific country |
474
|
|
|
* @return array the list of identity providers |
475
|
|
|
* |
476
|
|
|
*/ |
477
|
|
|
public function listAllIdentityProviders($activeOnly = 0, $country = "") |
478
|
|
|
{ |
479
|
|
|
return IdPlist::listAllIdentityProviders($activeOnly, $country); |
480
|
|
|
} |
481
|
|
|
|
482
|
|
|
/** |
483
|
|
|
* Order active identity providers according to their distance and name |
484
|
|
|
* @param string $country NRO to work with |
485
|
|
|
* @param array $currentLocation current location |
486
|
|
|
* |
487
|
|
|
* @return array $IdPs - list of arrays ('id', 'name'); |
488
|
|
|
*/ |
489
|
|
|
public function orderIdentityProviders($country, $currentLocation) |
490
|
|
|
{ |
491
|
|
|
return IdPlist::orderIdentityProviders($country, $currentLocation); |
492
|
|
|
} |
493
|
|
|
|
494
|
|
|
/** |
495
|
|
|
* outputs a full list of IdPs containing the fllowing data: |
496
|
|
|
* institution_is, institution name in all available languages, |
497
|
|
|
* list of production profiles. |
498
|
|
|
* For eache profile the profile identifier, profile name in all languages |
499
|
|
|
* and redirect values (empty rediret value means that no redirect has been |
500
|
|
|
* set). |
501
|
|
|
* |
502
|
|
|
* @return array of identity providers with attributes |
503
|
|
|
*/ |
504
|
|
|
public function listIdentityProvidersWithProfiles() { |
505
|
|
|
return IdPlist::listIdentityProvidersWithProfiles(); |
506
|
|
|
} |
507
|
|
|
|
508
|
|
|
/** |
509
|
|
|
* Detect the best device driver form the browser |
510
|
|
|
* Detects the operating system and returns its id |
511
|
|
|
* display name and group membership (as in devices.php) |
512
|
|
|
* @return array|boolean OS information, indexed by 'id', 'display', 'group' |
513
|
|
|
*/ |
514
|
|
|
public function detectOS() |
515
|
|
|
{ |
516
|
|
|
$Dev = \devices\Devices::listDevices(); |
517
|
|
|
$devId = $this->deviceFromRequest(); |
518
|
|
|
if ($devId !== NULL) { |
519
|
|
|
$ret = $this->returnDevice($devId, $Dev[$devId]); |
520
|
|
|
if ($ret !== FALSE) { |
521
|
|
|
return $ret; |
522
|
|
|
} |
523
|
|
|
} |
524
|
|
|
// the device has not been specified or not specified correctly, try to detect if from the browser ID |
525
|
|
|
$browser = htmlspecialchars(strip_tags($_SERVER['HTTP_USER_AGENT']), ENT_QUOTES); |
526
|
|
|
$this->loggerInstance->debug(4, "HTTP_USER_AGENT=$browser\n"); |
527
|
|
|
foreach ($Dev as $devId => $device) { |
528
|
|
|
if (!isset($device['match'])) { |
529
|
|
|
continue; |
530
|
|
|
} |
531
|
|
|
if (preg_match('/'.$device['match'].'/', $browser)) { |
532
|
|
|
$this->loggerInstance->debug(5, "Matched: $devId\n".$device['match']."\n".$browser."\n"); |
533
|
|
|
return $this->returnDevice($devId, $device); |
534
|
|
|
} |
535
|
|
|
} |
536
|
|
|
$this->loggerInstance->debug(2, "Unrecognised system: $browser\n"); |
537
|
|
|
return FALSE; |
538
|
|
|
} |
539
|
|
|
|
540
|
|
|
/** |
541
|
|
|
* test if devise is defined and is not hidden. If all is fine return extracted information. |
542
|
|
|
* |
543
|
|
|
* @param string $devId device id as defined as index in Devices.php |
544
|
|
|
* @param array $device device info as defined in Devices.php |
545
|
|
|
* @return array|FALSE if the device has not been correctly specified |
546
|
|
|
*/ |
547
|
|
|
private function returnDevice($devId, $device) |
548
|
|
|
{ |
549
|
|
|
$hidden = \core\common\Entity::getAttributeValue($device, 'options', 'hidden'); |
550
|
|
|
if ($hidden !== 1 && $hidden !== 2) { |
551
|
|
|
$this->loggerInstance->debug(4, "Browser_id: $devId\n"); |
552
|
|
|
if (isset($device['options']['hs20']) && $device['options']['hs20'] === 1) { |
553
|
|
|
$hs20 = 1; |
554
|
|
|
} else { |
555
|
|
|
$hs20 = 0; |
556
|
|
|
} |
557
|
|
|
return ['device' => $devId, 'display' => $device['display'], 'group' => $device['group'], 'hs20' => $hs20]; |
558
|
|
|
} |
559
|
|
|
return FALSE; |
560
|
|
|
} |
561
|
|
|
|
562
|
|
|
/** |
563
|
|
|
* This method checks if the device has been specified as the HTTP parameters |
564
|
|
|
* |
565
|
|
|
* @return device id|NULL if correctly specified or FALSE otherwise |
566
|
|
|
*/ |
567
|
|
|
private function deviceFromRequest() |
568
|
|
|
{ |
569
|
|
|
$devId = NULL; |
570
|
|
|
if (isset($_GET['device'])) { |
571
|
|
|
$devId = htmlspecialchars(strip_tags($_GET['device'])); |
572
|
|
|
} elseif (isset($_POST['device'])) { |
573
|
|
|
$devId = htmlspecialchars(strip_tags($_POST['device'])); |
574
|
|
|
} |
575
|
|
|
if ($devId === NULL || $devId === FALSE) { |
576
|
|
|
$this->loggerInstance->debug(4, "Invalid device id provided\n"); |
577
|
|
|
return NULL; |
578
|
|
|
} |
579
|
|
|
if (!isset(\devices\Devices::listDevices()[$devId])) { |
580
|
|
|
$this->loggerInstance->debug(2, "Unrecognised system: $devId\n"); |
581
|
|
|
return NULL; |
582
|
|
|
} |
583
|
|
|
return $devId; |
|
|
|
|
584
|
|
|
} |
585
|
|
|
|
586
|
|
|
/** |
587
|
|
|
* finds all the user certificates that originated in a given token |
588
|
|
|
* |
589
|
|
|
* @param string $token the token for which we are fetching all associated user certs |
590
|
|
|
* @return array|boolean returns FALSE if a token is invalid, otherwise array of certs |
591
|
|
|
*/ |
592
|
|
|
public function getUserCerts($token) |
593
|
|
|
{ |
594
|
|
|
$validator = new \web\lib\common\InputValidation(); |
595
|
|
|
$cleanToken = $validator->token($token); |
596
|
|
|
if ($cleanToken) { |
597
|
|
|
// check status of this silverbullet token according to info in DB: |
598
|
|
|
// it can be VALID (exists and not redeemed, EXPIRED, REDEEMED or INVALID (non existent) |
599
|
|
|
$invitationObject = new \core\SilverbulletInvitation($cleanToken); |
600
|
|
|
} else { |
601
|
|
|
return false; |
602
|
|
|
} |
603
|
|
|
$profile = new \core\ProfileSilverbullet($invitationObject->profile, NULL); |
604
|
|
|
$userdata = $profile->userStatus($invitationObject->userId); |
605
|
|
|
$allcerts = []; |
606
|
|
|
foreach ($userdata as $content) { |
607
|
|
|
$allcerts = array_merge($allcerts, $content->associatedCertificates); |
608
|
|
|
} |
609
|
|
|
return $allcerts; |
610
|
|
|
} |
611
|
|
|
|
612
|
|
|
/** |
613
|
|
|
* device name |
614
|
|
|
* |
615
|
|
|
* @var string |
616
|
|
|
*/ |
617
|
|
|
public $device; |
618
|
|
|
|
619
|
|
|
/** |
620
|
|
|
* path to installer |
621
|
|
|
* |
622
|
|
|
* @var string |
623
|
|
|
*/ |
624
|
|
|
private $installerPath; |
625
|
|
|
|
626
|
|
|
/** |
627
|
|
|
* helper function to sort profiles by their name |
628
|
|
|
* @param \core\AbstractProfile $profile1 the first profile's information |
629
|
|
|
* @param \core\AbstractProfile $profile2 the second profile's information |
630
|
|
|
* @return int |
631
|
|
|
*/ |
632
|
|
|
private static function profileSort($profile1, $profile2) |
633
|
|
|
{ |
634
|
|
|
return strcasecmp($profile1->name, $profile2->name); |
635
|
|
|
} |
636
|
|
|
} |
637
|
|
|
|
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:For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths