Test Setup Failed
Push — master ( 5ab61a...be3a40 )
by Tomasz
05:15
created

UserAPI::downloadInstaller()   A

Complexity

Conditions 4
Paths 3

Size

Total Lines 26
Code Lines 22

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 22
dl 0
loc 26
rs 9.568
c 1
b 0
f 0
cc 4
nc 3
nop 6
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 devide writeInstaller meethod
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
            if (\core\common\Entity::getAttributeValue($deviceProperties, 'options', 'hidden') === 1 && $showHidden === 0) {
223
                continue;
224
            }
225
            $count++;
226
            $deviceProperties['device'] = $device;
227
            $group = isset($deviceProperties['group']) ? $deviceProperties['group'] : 'other';
228
            if (!isset($returnList[$group])) {
229
                $returnList[$group] = [];
230
            }
231
            $returnList[$group][$device] = $deviceProperties;
232
        }
233
        return $returnList;
234
    }
235
236
    /**
237
     * 
238
     * @param string $device    identifier of the device
239
     * @param int    $profileId identifier of the profile
240
     * @return void
241
     */
242
    public function deviceInfo($device, $profileId)
243
    {
244
        $validator = new \web\lib\common\InputValidation();
245
        $out = 0;
246
        $profile = $validator->existingProfile($profileId);
247
        $factory = new DeviceFactory($device);
248
        $dev = $factory->device;
249
        if (isset($dev)) {
250
            $dev->setup($profile);
251
            $out = $dev->writeDeviceInfo();
252
        }
253
        echo $out;
254
    }
255
256
    /**
257
     * Prepare the support data for a given profile
258
     *
259
     * @param int $profId profile identifier
260
     * @return array
261
     * array with the following fields:
262
     * - local_email
263
     * - local_phone
264
     * - local_url
265
     * - description
266
     * - devices - an array of device names and their statuses (for a given profile)
267
     * - last_changed
268
     */
269
    public function profileAttributes($profId)
270
    {
271
        $validator = new \web\lib\common\InputValidation();
272
        $profile = $validator->existingProfile($profId);
273
        $attribs = $profile->getCollapsedAttributes();
274
        $returnArray = [];
275
        $returnArray['silverbullet'] = $profile instanceof ProfileSilverbullet ? 1 : 0;
276
        if (isset($attribs['support:email'])) {
277
            $returnArray['local_email'] = $attribs['support:email'][0];
278
        }
279
        if (isset($attribs['support:phone'])) {
280
            $returnArray['local_phone'] = $attribs['support:phone'][0];
281
        }
282
        if (isset($attribs['support:url'])) {
283
            $returnArray['local_url'] = $attribs['support:url'][0];
284
        }
285
        if (isset($attribs['profile:description'])) {
286
            $returnArray['description'] = $attribs['profile:description'][0];
287
        }
288
        if (isset($attribs['media:openroaming'])) {
289
            $returnArray['openroaming'] = $attribs['media:openroaming'][0];
290
        } else {
291
            $returnArray['openroaming'] = 'none';
292
        }
293
        $returnArray['devices'] = $profile->listDevices();
294
        $returnArray['last_changed'] = $profile->getFreshness();
295
        return $returnArray;
296
    }
297
298
    /**
299
     * Generate and send the installer
300
     *
301
     * @param string $device        identifier as in {@link devices.php}
302
     * @param int    $prof_id       profile identifier
303
     * @param string $generated_for which download area does this pertain to
304
     * @param string $token         for silverbullet: invitation token to consume
305
     * @param string $password      for silverbull: import PIN for the future certificate
306
     * @return string binary stream: installerFile
307
     */
308
    public function downloadInstaller($device, $prof_id, $generated_for = 'user', $openRoaming = 0, $token = NULL, $password = NULL)
309
    {
310
        $this->loggerInstance->debug(4, "downloadInstaller arguments: $device,$prof_id,$generated_for, $openRoaming\n");
311
        $output = $this->generateInstaller($device, $prof_id, $generated_for, $openRoaming, $token, $password);
312
        $this->loggerInstance->debug(4, "output from GUI::generateInstaller:");
313
        $this->loggerInstance->debug(4, print_r($output, true));
314
        if (empty($output['link']) || $output['link'] === 0) {
315
            header("HTTP/1.0 404 Not Found");
316
            return;
317
        }
318
        $validator = new \web\lib\common\InputValidation();
319
        $profile = $validator->existingProfile($prof_id);
320
        $profile->incrementDownloadStats($device, $generated_for, $openRoaming);
321
        $file = $this->installerPath;
322
        $filetype = $output['mime'];
323
        $this->loggerInstance->debug(4, "installer MIME type:$filetype\n");
324
        header("Content-type: ".$filetype);
325
        if ($filetype !== "application/x-wifi-config") { // for those installers to work on Android, Content-Disposition MUST NOT be set
326
            header('Content-Disposition: inline; filename="'.basename($file).'"');
327
        } else {
328
            header('Content-Transfer-Encoding: base64');
329
        }
330
        header('Content-Length: '.filesize($file));
331
        ob_clean();
332
        flush();
333
        readfile($file);
334
    }
335
336
    /**
337
     * resizes image files
338
     * 
339
     * @param string $inputImage the image we want to process
340
     * @param string $destFile   the output file for the processed image
341
     * @param int    $width      if resizing, the target width
342
     * @param int    $height     if resizing, the target height
343
     * @param bool   $resize     shall we do resizing? width and height are ignored otherwise
344
     * @return array
345
     */
346
    private function processImage($inputImage, $destFile, $width, $height, $resize)
347
    {
348
        $info = new \finfo();
349
        $filetype = $info->buffer($inputImage, FILEINFO_MIME_TYPE);
350
        $expiresString = $this->logoExpireTime();
351
        $blob = $inputImage;
352
353
        if ($resize === TRUE) {
354
            $image = new \Imagick();
355
            $image->readImageBlob($inputImage);
356
            $image->setImageFormat('PNG');
357
            $image->thumbnailImage($width, $height, 1);
358
            $blob = $image->getImageBlob();
359
            $this->loggerInstance->debug(4, "Writing cached logo $destFile for IdP/Federation.\n");
360
            file_put_contents($destFile, $blob);
361
        }
362
363
        return ["filetype" => $filetype, "expires" => $expiresString, "blob" => $blob];
364
    }
365
366
    protected function logoExpireTime()
367
    {
368
        $offset = 60 * 60 * 24 * 30;
369
        // gmdate cannot fail here - time() is its default argument (and integer), and we are adding an integer to it
370
        return("Expires: "./** @scrutinizer ignore-type */ gmdate("D, d M Y H:i:s", time() + $offset)." GMT");
371
    }
372
    /**
373
     * Get and prepare logo file 
374
     *
375
     * When called for DiscoJuice, first check if file cache exists
376
     * If not then generate the file and save it in the cache
377
     * @param int|string $identifier IdP or Federation identifier
378
     * @param string     $type       either 'idp' or 'federation' is allowed 
379
     * @param integer    $widthIn    maximum width of the generated image - if 0 then it is treated as no upper bound
380
     * @param integer    $heightIn   maximum height of the generated image - if 0 then it is treated as no upper bound
381
     * @return array|null array with image information or NULL if there is no logo
382
     * @throws Exception
383
     */
384
    protected function getLogo($identifier, $type, $widthIn, $heightIn)
385
    {
386
        $expiresString = '';
387
        $attributeName = [
388
            'federation' => "fed:logo_file",
389
            'federation_from_idp' => "fed:logo_file",
390
            'idp' => "general:logo_file",
391
        ];
392
393
        $logoFile = "";
394
        $validator = new \web\lib\common\InputValidation();
395
        switch ($type) {
396
            case "federation":
397
                $entity = $validator->existingFederation($identifier);
398
                break;
399
            case "idp":
400
                $entity = $validator->existingIdP($identifier);
401
                break;
402
            case "federation_from_idp":
403
                $idp = $validator->existingIdP($identifier);
404
                $entity = $validator->existingFederation($idp->federation);
405
                break;
406
            default:
407
                throw new Exception("Unknown type of logo requested!");
408
        }
409
        $filetype = 'image/png'; // default, only one code path where it can become different
410
        list($width, $height, $resize) = $this->testForResize($widthIn, $heightIn);
411
        if ($resize) {
412
            $logoFile = ROOT.'/web/downloads/logos/'.$identifier.'_'.$width.'_'.$height.'.png';
413
        }
414
        if (is_file($logoFile)) { // $logoFile could be an empty string but then we will get a FALSE
415
            $this->loggerInstance->debug(4, "Using cached logo $logoFile for: $identifier\n");
416
            $blob = file_get_contents($logoFile);
417
        } else {
418
            $logoAttribute = $entity->getAttributes($attributeName[$type]);
419
            if (count($logoAttribute) == 0) {
420
                $blob = file_get_contents(ROOT . '/web/resources/images/empty.png');
421
                $expiresString = $this->logoExpireTime();
422
            } else {
423
                $this->loggerInstance->debug(4, "RESIZE:$width:$height\n");
424
                $meta = $this->processImage($logoAttribute[0]['value'], $logoFile, $width, $height, $resize);
425
                $filetype = $meta['filetype'];
426
                $expiresString = $meta['expires'];
427
                $blob = $meta['blob'];
428
            }
429
        }
430
        return ["filetype" => $filetype, "expires" => $expiresString, "blob" => $blob];
431
    }
432
433
    /**
434
     * see if we have to resize an image
435
     * 
436
     * @param integer $width  the desired max width (0 = unbounded)
437
     * @param integer $height the desired max height (0 = unbounded)
438
     * @return array
439
     */
440
    private function testForResize($width, $height)
441
    {
442
        if (is_numeric($width) && is_numeric($height) && ($width > 0 || $height > 0)) {
443
            if ($height == 0) {
444
                $height = 10000;
445
            }
446
            if ($width == 0) {
447
                $width = 10000;
448
            }
449
            return [$width, $height, TRUE];
450
        }
451
        return [0, 0, FALSE];
452
    }
453
454
    /**
455
     * find out where the device is currently located
456
     * @return array
457
     */
458
    public function locateDevice()
459
    {
460
        return \core\DeviceLocation::locateDevice();
461
    }
462
463
    /**
464
     * Lists all identity providers in the database
465
     * adding information required by DiscoJuice.
466
     * 
467
     * @param int    $activeOnly if set to non-zero will cause listing of only those institutions which have some valid profiles defined.
468
     * @param string $country    if set, only list IdPs in a specific country
469
     * @return array the list of identity providers
470
     *
471
     */
472
    public function listAllIdentityProviders($activeOnly = 0, $country = "")
473
    {
474
        return IdPlist::listAllIdentityProviders($activeOnly, $country);
475
    }
476
477
    /**
478
     * Order active identity providers according to their distance and name
479
     * @param string $country         NRO to work with
480
     * @param array  $currentLocation current location
481
     *
482
     * @return array $IdPs -  list of arrays ('id', 'name');
483
     */
484
    public function orderIdentityProviders($country, $currentLocation)
485
    {
486
        return IdPlist::orderIdentityProviders($country, $currentLocation);
487
    }
488
    
489
    /**
490
     * outputs a full list of IdPs containing the fllowing data:
491
     * institution_is, institution name in all available languages,
492
     * list of production profiles.
493
     * For eache profile the profile identifier, profile name in all languages
494
     * and redirect values (empty rediret value means that no redirect has been
495
     * set).
496
     * 
497
     * @return array of identity providers with attributes
498
     */
499
    public function listIdentityProvidersWithProfiles() {
500
        return IdPlist::listIdentityProvidersWithProfiles();
501
    }
502
    
503
    /**
504
     * Detect the best device driver form the browser
505
     * Detects the operating system and returns its id 
506
     * display name and group membership (as in devices.php)
507
     * @return array|boolean OS information, indexed by 'id', 'display', 'group'
508
     */
509
    public function detectOS()
510
    {
511
        $Dev = \devices\Devices::listDevices();
512
        $devId = $this->deviceFromRequest();
513
        if ($devId !== NULL) {
514
            $ret = $this->returnDevice($devId, $Dev[$devId]);
515
            if ($ret !== FALSE) {
516
                return $ret;
517
            }
518
        }
519
// the device has not been specified or not specified correctly, try to detect if from the browser ID
520
        $browser = filter_input(INPUT_SERVER, 'HTTP_USER_AGENT', FILTER_SANITIZE_STRING);
521
        $this->loggerInstance->debug(4, "HTTP_USER_AGENT=$browser\n");
522
        foreach ($Dev as $devId => $device) {
523
            if (!isset($device['match'])) {
524
                continue;
525
            }
526
            if (preg_match('/'.$device['match'].'/', $browser)) {
527
                return $this->returnDevice($devId, $device);
528
            }
529
        }
530
        $this->loggerInstance->debug(2, "Unrecognised system: $browser\n");
531
        return FALSE;
532
    }
533
534
    /**
535
     * test if devise is defined and is not hidden. If all is fine return extracted information.
536
     * 
537
     * @param string $devId  device id as defined as index in Devices.php
538
     * @param array  $device device info as defined in Devices.php
539
     * @return array|FALSE if the device has not been correctly specified
540
     */
541
    private function returnDevice($devId, $device)
542
    {
543
        if (\core\common\Entity::getAttributeValue($device, 'options', 'hidden') !== 1) {
544
            $this->loggerInstance->debug(4, "Browser_id: $devId\n");
545
            if (isset($device['options']['hs20']) && $device['options']['hs20'] === 1) {
546
                $hs20 = 1;
547
            } else {
548
                $hs20 = 0;
549
            }
550
            return ['device' => $devId, 'display' => $device['display'], 'group' => $device['group'], 'hs20' => $hs20];
551
        }
552
        return FALSE;
553
    }
554
555
    /**
556
     * This methods cheks if the devide has been specified as the HTTP parameters
557
     * 
558
     * @return device id|NULL if correcty specified or FALSE otherwise
559
     */
560
    private function deviceFromRequest()
561
    {
562
        $devId = filter_input(INPUT_GET, 'device', FILTER_SANITIZE_STRING) ?? filter_input(INPUT_POST, 'device', FILTER_SANITIZE_STRING);
563
        if ($devId === NULL || $devId === FALSE) {
564
            $this->loggerInstance->debug(2, "Invalid device id provided\n");
565
            return NULL;
566
        }
567
        if (!isset(\devices\Devices::listDevices()[$devId])) {
568
            $this->loggerInstance->debug(2, "Unrecognised system: $devId\n");
569
            return NULL;
570
        }
571
        return $devId;
572
    }
573
574
    /**
575
     * finds all the user certificates that originated in a given token
576
     * 
577
     * @param string $token the token for which we are fetching all associated user certs
578
     * @return array|boolean returns FALSE if a token is invalid, otherwise array of certs
579
     */
580
    public function getUserCerts($token)
581
    {
582
        $validator = new \web\lib\common\InputValidation();
583
        $cleanToken = $validator->token($token);
584
        if ($cleanToken) {
585
            // check status of this silverbullet token according to info in DB:
586
            // it can be VALID (exists and not redeemed, EXPIRED, REDEEMED or INVALID (non existent)
587
            $invitationObject = new \core\SilverbulletInvitation($cleanToken);
588
        } else {
589
            return false;
590
        }
591
        $profile = new \core\ProfileSilverbullet($invitationObject->profile, NULL);
592
        $userdata = $profile->userStatus($invitationObject->userId);
593
        $allcerts = [];
594
        foreach ($userdata as $content) {
595
            $allcerts = array_merge($allcerts, $content->associatedCertificates);
596
        }
597
        return $allcerts;
598
    }
599
600
    /**
601
     * device name
602
     * 
603
     * @var string
604
     */
605
    public $device;
606
607
    /**
608
     * path to installer
609
     * 
610
     * @var string
611
     */
612
    private $installerPath;
613
614
    /**
615
     * helper function to sort profiles by their name
616
     * @param \core\AbstractProfile $profile1 the first profile's information
617
     * @param \core\AbstractProfile $profile2 the second profile's information
618
     * @return int
619
     */
620
    private static function profileSort($profile1, $profile2)
621
    {
622
        return strcasecmp($profile1->name, $profile2->name);
623
    }
624
}