Completed
Push — master ( cc9aa9...547d73 )
by
unknown
04:54
created

DeviceConfig::translateFile()   C

Complexity

Conditions 8
Paths 72

Size

Total Lines 27
Code Lines 24

Duplication

Lines 2
Ratio 7.41 %

Importance

Changes 0
Metric Value
cc 8
eloc 24
nc 72
nop 3
dl 2
loc 27
rs 5.3846
c 0
b 0
f 0
1
<?php
2
/* *********************************************************************************
3
 * (c) 2011-15 GÉANT on behalf of the GN3, GN3plus and GN4 consortia
4
 * License: see the LICENSE file in the root directory
5
 ***********************************************************************************/
6
?>
7
<?php
8
/**
9
  * This file defines the abstract Device class
10
  *
11
  * @package ModuleWriting
12
  */
13
14
/**
15
 * 
16
 */
17
require_once('Helper.php');
18
require_once('CAT.php');
19
require_once('Profile.php');
20
require_once('X509.php');
21
require_once('EAP.php');
22
include_once("devices/devices.php");
23
24
25
/**
26
 * This class defines the API for CAT module writers.
27
 *
28
 * A device is a fairly abstract notion. In most cases it represents
29
 * a particular operating system or a set of operationg systems
30
 * like MS Windows Vista and newer.
31
 *
32
 * The purpose of this class is to preapare a setup for the device configurator,
33
 * collect all necessary information from the database, taking into account
34
 * limitations, that a given device may present (like a set of supported EAP methods).
35
 *
36
 * All that is required from the device module is to produce a conigurator
37
 * file and pass its name back to the API.
38
 *
39
 * 
40
 * @author Tomasz Wolniewicz <[email protected]>
41
 *
42
 * @license see LICENSE file in root directory
43
 * 
44
 * @package ModuleWriting
45
 * @abstract
46
 */
47
48
abstract class DeviceConfig {
49
   /**
50
    * stores the path to the temporary working directory for a module instance
51
    * @var string $FPATH
52
    */
53
    public $FPATH;
54
55
    /**
56
     * array of specialities - will be displayed on the admin download as "footnote"
57
     * @var array specialities
58
     */
59
    public $specialities;
60
61
   /**
62
     * device module constructor should be defined by each module, but if it is not, then here is a default one
63
     */
64
65
      public function __construct() {
66
      $this->supportedEapMethods  = [EAP::$TLS, EAP::$PEAP_MSCHAP2, EAP::$TTLS_PAP];
0 ignored issues
show
Bug introduced by
The property supportedEapMethods does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
67
      debug(4,"This device supports the following EAP methods: ");
68
      debug(4,$this->supportedEapMethods);
69
    }
70
71
72
   /**
73
    * Set up working environment for a device module
74
    *
75
    * Sets up the device module environment taking into account the actual profile
76
    * selected by the user in the GUI. The selected profile is passed as the
77
    * Profile $profile argumant.
78
    *
79
    * This method needs to be called after the device instance has been created (the GUI class does that)
80
    *
81
    * setup performs the following tasks:
82
    * - collect profile attributes and pass them as the attributes property;
83
    * - create the temporary working directory
84
    * - process CA certificates and store them as 'internal:CAs' attribute
85
    * - process and save optional info files and store references to them in
86
    *   'internal:info_file' attribute
87
    * @param Profile $profile the profile object which will be passed by the caller
88
    * @final not to be redefined
89
    */
90
    final public function setup(Profile $profile) {
91
       debug(4,"module setup start\n");
92
       if(! $profile instanceof Profile) {
0 ignored issues
show
Bug introduced by
The class Profile does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
93
          debug(2,"No profile has been set\n");
94
          error("No profile has been set");
95
          exit;
96
       }
97
       $this->attributes = $this->getProfileAttributes($profile);
0 ignored issues
show
Documentation Bug introduced by
It seems like $this->getProfileAttributes($profile) can also be of type false. However, the property $attributes is declared as type array. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
98
       if(! $this->selected_eap) {
99
          error("No EAP type specified.");
100
          exit;
101
       }
102
       // create temporary directory, its full path will be saved in $this->FPATH;
103
       $T = createTemporaryDirectory('installer');
104
       $this->FPATH = $T['dir'];
105
       mkdir($T['dir'].'/tmp');
106
       chdir($T['dir'].'/tmp');
107
       $CAs = [];
108
       if(isset($this->attributes['eap:ca_file'])) {
109
       foreach ($this->attributes['eap:ca_file'] as $ca) {
110
          if($c = X509::processCertificate($ca))
111
             $CAs[] = $c;
112
          }
113
          $this->attributes['internal:CAs'][0]=$CAs;
114
       }
115
       if(isset($this->attributes['support:info_file'])) {
116
          $this->attributes['internal:info_file'][0] = 
117
             $this->saveInfoFile($this->attributes['support:info_file'][0]);
118
       }
119
       if(isset($this->attributes['general:logo_file']))
120
          $this->attributes['internal:logo_file'] = 
121
             $this->saveLogoFile($this->attributes['general:logo_file']);
122
       $this->attributes['internal:SSID'] = $this->getSSIDs()['add'];;
123
       $this->attributes['internal:remove_SSID'] = $this->getSSIDs()['del'];;
124
       $this->attributes['internal:consortia'] = $this->getConsortia();
125
       $this->lang_index = CAT::get_lang();
126
       // phpMD says the below is not needed. Wow.
127
       // $idp = new IdP($profile->institution);
0 ignored issues
show
Unused Code Comprehensibility introduced by
50% of this comment could be valid code. Did you maybe forget this after debugging?

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

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

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

Loading history...
128
       $olddomain = CAT::set_locale("core");
129
       $this->support_email_substitute = sprintf(_("your local %s support"),Config::$CONSORTIUM['name']);
130
       $this->support_url_substitute = sprintf(_("your local %s support page"),Config::$CONSORTIUM['name']);
131
       CAT::set_locale($olddomain);
132
133
       if($this->signer && $this->options['sign'])
134
         $this->sign = CAT::$root . '/signer/'. $this->signer;
135
       $this->installerBasename = $this->getInstallerBasename();
136
    }
137
138
  /**
139
    * Selects the preferred eap method based on profile EAP configuration and device EAP capabilities
140
    *
141
    * @param array eap_array an array of eap methods supported by a given device
142
    * @return the best matching EAP type for the profile; or 0 if no match was found
143
    */   
144
   public function getPreferredEapType($eap_array) {
145
     foreach ($eap_array as $eap) {
146
         if(in_array($eap,$this->supportedEapMethods)) {
147
            $this->selected_eap = $eap;
148
            debug(4,"Selected EAP:");
149
            debug(4,$eap);
150
            return($eap);
151
         }
152
     }
153
     return(0);
0 ignored issues
show
Bug Best Practice introduced by
The return type of return 0; (integer) is incompatible with the return type documented by DeviceConfig::getPreferredEapType of type the.

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:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
154
   }
155
  /**
156
    * prepare usage information for the installer
157
    * every device module should override this method
158
    *
159
    * @return String HTML text to be displayed
160
    */ 
161
   public function writeDeviceInfo() {
162
     return _("Sorry, this should not happen - no additional information is available");
163
   }
164
165
  /**
166
    *  Copy a file from the module location to the temporary directory.
167
    *
168
    * If the second argument is provided then the file will be saved under the name 
169
    * taken form this argument. If only one parameter is given, source and destination
170
    * filenames are the same
171
    * Source file can be located either in the Files subdirectory or in the sibdirectory of Files
172
    * named the same as device_id. The second option takes precedence.
173
    *
174
    * @param string $source_name The source file name
175
    * @param string $output_name The destination file name
176
    *
177
    * @return bool result of the copy operation
178
    * @final not to be redefined
179
    */
180
   final protected function copyFile($source_name, $output_name = 0) {
181
      if  ( $output_name === 0)
182
        $output_name = $source_name;
183
184
      debug(4,"fileCopy($source_name, $output_name)\n");
185
      if(is_file($this->module_path.'/Files/'.$this->device_id.'/'.$source_name))
186
         $source = $this->module_path.'/Files/'.$this->device_id.'/'.$source_name;
187 View Code Duplication
      elseif(is_file($this->module_path.'/Files/'.$source_name))
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
188
         $source = $this->module_path.'/Files/'.$source_name;
189
      else {
190
        debug(2,"fileCopy:reqested file $source_name does not exist\n");
191
        return(FALSE);
192
      }
193
      debug(4,"Copying $source to $output_name\n");
194
      $result = copy($source,"$output_name");
195
      if(! $result )
196
        debug(2,"fileCopy($source_name, $output_name) failed\n");
197
      return($result); 
198
   }
199
200
201
  /**
202
    *  Copy a file from the module location to the temporary directory aplying transcoding.
203
    *
204
    * Transcoding is only required for Windows installers, and no Unicode support
205
    * in NSIS (NSIS version below 3)
206
    * Trancoding is only applied if the third optional parameter is set and nonzero
207
    * If Config::$NSIS_VERSION is set to 3 or more, no transcoding will be applied
208
    * regardless of the third parameter value.
209
    * If the second argument is provided and is not equal to 0, then the file will be
210
    * saved under the name taken from this argument.
211
    * If only one parameter is given or the second is equal to 0, source and destination
212
    * filenames are the same.
213
    * The third optional parameter, if nonzero, should be the character set understood by iconv
214
    * This is required by the Windows installer and is expected to go away in the future.
215
    * Source file can be located either in the Files subdirectory or in the sibdirectory of Files
216
    * named the same as device_id. The second option takes precedence.
217
    *
218
    * @param string $source_name The source file name
219
    * @param string $output_name The destination file name
220
    * @param int $use_win_cp Set Windows charset if non-zero
221
    *
0 ignored issues
show
Bug introduced by
There is no parameter named $use_win_cp. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
222
    * @final not to be redefined
223
    */
224
225
   final protected function translateFile($source_name, $output_name = 0, $encoding = 0) {
226
      if(Config::$NSIS_VERSION >= 3)
227
        $encoding = 0;
228
      if  ( $output_name === 0)
229
        $output_name = $source_name;
230
231
      debug(4,"translateFile($source_name, $output_name, $encoding)\n");
232
      ob_start();
233
      debug(4,$this->module_path.'/Files/'.$this->device_id.'/'.$source_name."\n");
234
      if(is_file($this->module_path.'/Files/'.$this->device_id.'/'.$source_name))
235
         $source = $this->module_path.'/Files/'.$this->device_id.'/'.$source_name;
236 View Code Duplication
      elseif(is_file($this->module_path.'/Files/'.$source_name))
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
237
         $source = $this->module_path.'/Files/'.$source_name;
238
      include($source);
0 ignored issues
show
Bug introduced by
The variable $source does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
239
      $output = ob_get_clean();
240
      if($encoding) {
241
        $output_c = iconv('UTF-8',$encoding.'//TRANSLIT',$output);
242
        if($output_c)
243
           $output = $output_c;
244
      }
245
      $f = fopen("$output_name","w");
246
      if(! $f)
247
         debug(2,"translateFile($source, $output_name, $encoding) failed\n");
248
      fwrite($f,$output);
249
      fclose($f);
250
      debug(4,"translateFile($source, $output_name, $encoding) end\n");
251
   }
252
253
254
  /**
255
    * Transcode a string adding double quotes escaping
256
    *
257
    * Transcoding is only required for Windows installers, and no Unicode support
258
    * in NSIS (NSIS version below 3)
259
    * Trancoding is only applied if the third optional parameter is set and nonzero
260
    * If Config::$NSIS_VERSION is set to 3 or more, no transcoding will be applied
261
    * regardless of the second parameter value.
262
    * The second optional parameter, if nonzero, should be the character set understood by iconv
263
    * This is required by the Windows installer and is expected to go away in the future.
264
    *
265
    * @param string $source_name The source file name
266
    * @param int $use_win_cp Set Windows charset if non-zero
0 ignored issues
show
Bug introduced by
There is no parameter named $source_name. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
267
    *
0 ignored issues
show
Bug introduced by
There is no parameter named $use_win_cp. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
268
    * @final not to be redefined
269
    */
270
271
   final protected function translateString($source_string,$encoding = 0) {
272
      if(Config::$NSIS_VERSION >= 3)
273
        $encoding = 0;
274
      if($encoding)
275
        $output_c = iconv('UTF-8',$encoding.'//TRANSLIT',$source_string);
276
      else
277
        $output_c = $source_string;
278
      if($output_c) 
279
         $source_string  = str_replace('"','$\\"',$output_c);
280
      else
281
         debug(2,"Failed to convert string $source_string\n");
282
      return $source_string;
283
   }
284
285
286
  /**
287
   * Save certificate files in either DER or PEM format
288
   *
289
   * Certificate files will be saved in the module working directory.
290
   * @param string $format  only "der" and "pem" are currently allowed
291
   * @return array an array of arrays or FALSE on error
292
   * saved certificate file names are avalable under the 'file' index
293
   * additional array entries are indexed as 'sha1', 'md5', and 'root'.
294
   * sha1 and md5 are correcponding certificate hashes
295
   * root is set to 1 for the CA roor certicicate and 0 otherwise
296
  */ 
297
   final protected function saveCertificateFiles($format) {
298
     if($format == 'der' || $format == 'pam') {
299
       $i = 0;
300
       $CA_files = [];
301
       $ca_array = $this->attributes['internal:CAs'][0];
302
       if(! $ca_array)
303
         return(FALSE);
304
       foreach ($ca_array as $CA) {
305
         $f = fopen("cert-$i.crt","w");
306
         if(! $f) die("problem opening the file\n");
307
         if($format == "pem")
308
            fwrite($f,$CA['pem']);
309
         else
310
            fwrite($f,$CA['der']);
311
         fclose($f);
312
         $C = [];
313
         $C['file'] = "cert-$i.crt";
314
         $C['sha1'] = $CA['sha1'];
315
         $C['md5'] = $CA['md5'];
316
         $C['root'] = $CA['root'];
317
         $CA_files[] = $C;
318
         $i++;
319
       }
320
       return($CA_files);
321
     } else {
322
       debug(2, 'incorrect format value specified');
323
       return(FALSE);
324
     }
325
      
326
   }
327
328
   /**
329
    * Generate installer filename base.
330
    * Device module should use this name adding an extension.
331
    * Normally the device identifier follows the Consortium name.
332
    * The sting taken for the device identifier equals (by default) to the index in the listDevices array,
333
    * but can be overriden with the 'device_id' device option.
334
    */
335
   private function getInstallerBasename() {
336
      $replace_pattern = '/[ ()\/\'"]+/';
337
      $lang_pointer = Config::$LANGUAGES[$this->lang_index]['latin_based'] == TRUE ? 0 : 1;
338
      debug(4,"getInstallerBasename1:".$this->attributes['general:instname'][$lang_pointer]."\n");
339
      $inst = iconv("UTF-8", "US-ASCII//TRANSLIT", preg_replace($replace_pattern, '_', $this->attributes['general:instname'][$lang_pointer]));
340
      debug(4,"getInstallerBasename2:$inst\n");
341
      $Inst_a = explode('_',$inst);
342
      if(count($Inst_a) > 2) {
343
         $inst = '';
344
         foreach($Inst_a as $i)
345
           $inst .= $i[0];
346
      }   
347
      $c_name = iconv("UTF-8", "US-ASCII//TRANSLIT", preg_replace($replace_pattern, '_', Config::$CONSORTIUM['name']));
348
      if($this->attributes['internal:profile_count'][0] > 1) {
349
         if(!empty($this->attributes['profile:name']) && ! empty($this->attributes['profile:name'][$lang_pointer])) {
350
             $prof = iconv("UTF-8", "US-ASCII//TRANSLIT", preg_replace($replace_pattern, '_', $this->attributes['profile:name'][$lang_pointer]));
351
             $prof = preg_replace('/_+$/','',$prof);
352
             return $c_name. '-'. $this->getDeviceId() . $inst .'-'. $prof;
353
         }
354
      }
355
      return $c_name. '-'. $this->getDeviceId() . $inst;
356
  }
357
358
  private function getDeviceId() {
359
    $d_id = $this->device_id;
360
    if(isset($this->options['device_id'])) 
361
      $d_id = $this->options['device_id'];
362
    if($d_id !== '')
363
      $d_id .= '-';
364
    return $d_id;
365
  }
366
367
368
  private function getSSIDs() {
369
    $S['add']=[];
0 ignored issues
show
Coding Style Comprehensibility introduced by
$S was never initialized. Although not strictly required by PHP, it is generally a good practice to add $S = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
370
    $S['del']=[];
371
    if (isset(Config::$CONSORTIUM['ssid'])) {
372
       foreach (Config::$CONSORTIUM['ssid'] as $ssid) {
373
        if(isset(Config::$CONSORTIUM['tkipsupport']) && Config::$CONSORTIUM['tkipsupport'] == TRUE)
374
          $S['add'][$ssid] = 'TKIP';
375
        else {
376
          $S['add'][$ssid] = 'AES';
377
          $S['del'][$ssid] = 'TKIP';
378
        }
379
       }
380
    }
381 View Code Duplication
    if(isset($this->attributes['media:SSID'])) {
1 ignored issue
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
382
      $SSID = $this->attributes['media:SSID'];
383
384
      foreach($SSID as $ssid)
385
         $S['add'][$ssid] = 'AES';
386
      }
387 View Code Duplication
    if(isset($this->attributes['media:SSID_with_legacy'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
388
      $SSID = $this->attributes['media:SSID_with_legacy'];
389
      foreach($SSID as $ssid)
390
         $S['add'][$ssid] = 'TKIP';
391
    }
392 View Code Duplication
    if(isset($this->attributes['media:remove_SSID'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
393
      $SSID = $this->attributes['media:remove_SSID'];
394
      foreach($SSID as $ssid)
395
         $S['del'][$ssid] = 'DEL';
396
    }
397
    return $S;
398
  }
399
400
  private function getConsortia() {
401
      $OIs = [];
402
      $OIs = array_merge($OIs, Config::$CONSORTIUM['interworking-consortium-oi']);
403
      if (isset($this->attributes['media:consortium_OI']))
404
          foreach ($this->attributes['media:consortium_OI'] as $new_oi)
405
            $OIs[] = $new_oi;
406
      return $OIs;
407
  }
408
  
409
  /**
410
   * An array with shorthand definitions for MIME types
411
   * @var array
412
   */
413
  private $mime_extensions = [
414
     'text/plain' => 'txt',
415
     'text/rtf' => 'rtf',
416
     'application/pdf' =>'pdf',
417
  ];
418
419
  private function saveLogoFile($Logos) {
420
    $i=0;
421
    $returnarray= [];
422
    foreach ($Logos as $blob) {
423
      $finfo = new finfo(FILEINFO_MIME_TYPE);
424
      $mime = $finfo->buffer($blob);
425
      if(preg_match('/^image\/(.*)/',$mime,$m))
426
        $ext = $m[1];
427
      else
428
        $ext = 'unsupported';
429
      debug(4,"saveLogoFile: $mime : $ext\n");
430
      $f_name = 'logo-'.$i.'.'.$ext;
431
      $f = fopen($f_name,"w");
432
      if(! $f) {
433
          debug(2,"saveLogoFile failed for: $f_name\n");
434
          die("problem opening the file\n");
435
      }
436
      fwrite($f,$blob);
437
      fclose($f);
438
      $returnarray[]= ['name'=>$f_name,'mime'=>$ext];
439
      $i++;
440
    }
441
    return($returnarray);
442
  }
443
444
445
  private function saveInfoFile($blob) {
446
    $finfo = new finfo(FILEINFO_MIME_TYPE);
447
    $mime = $finfo->buffer($blob);
448
    $ext = isset($this->mime_extensions[$mime]) ? $this->mime_extensions[$mime] : 'usupported';
449
    debug(4,"saveInfoFile: $mime : $ext\n");
450
    $f = fopen('local-info.'.$ext,"w");
451
    if(! $f) die("problem opening the file\n");
452
    fwrite($f,$blob);
453
    fclose($f);
454
    return(['name'=>'local-info.'.$ext,'mime'=>$ext]);
455
  }
456
457
  private function getProfileAttributes(Profile $profile) {
458
     $eaps = $profile->getEapMethodsinOrderOfPreference(1);
459
     if($eap = $this->getPreferredEapType($eaps)) {
460
          $a = $profile->getCollapsedAttributes($eap);
461
          $a['eap'] = $eap;
462
          $a['all_eaps'] = $eaps;
463
          return($a);
464
     } else {
465
       error("No supported eap types found for this profile.");
466
       return(FALSE);
467
  }
468
  }
469
/**
470
  * dumps attributes for debugging purposes
471
  *
472
  * dumpAttibutes method is supplied for debuging purposes, it simply dumps the attribute array
473
  * to a file with name passed in the attribute.
474
  * @param string $file the output file name
475
  */
476
  protected function dumpAttibutes($file) {
477
        ob_start();
478
        print_r($this->attributes);
479
        $output = ob_get_clean();
480
        $f = fopen($file,"w");
481
        fwrite($f,$output);
482
        fclose($f);
483
  }
484
/** 
485
 * placeholder for the main device method
486
 *
487
 */
488
489
  protected function writeInstaller() {
490
     return("download path");
491
  }
492
493
/**
494
 * Array passing all options to the device module.
495
 *
496
 * $attrbutes array contains option values defined for the institution and a particular
497
 * profile (possibly overriding one another) ready for the device module to consume.
498
 * 
499
 * For each of the options the value is another array of vales (even if only one value is present).
500
 * Some attributes may be missing if they have not been configured for a viven institution or profile.
501
 *
502
 * The following attributes are meant to be used by device modules:
503
 * - <b>general:geo_coordinates</b> -  geographical coordinates of the institution or a campus
504
 * - <b>support:info_file</b>  -  consent file displayed to the users                                                         
505
 * - <b>general:logo_file</b>  -  file data containing institution logo                                                      
506
 * - <b>support:eap_types</b>  -  URL to a local support page for a specific eap methiod, not to be confused with general:url 
507
 * - <b>support:email</b>      -  email for users to contact for local instructions                                           
508
 * - <b>support:phone</b>      -  telephone number for users to contact for local instructions                                
509
 * - <b>support:url</b>        -  URL where the user will find local instructions       
510
 * - <b>internal:info_file</b> -  the pathname of the info_file saved in the working directory
511
 * - <b>internal:logo_file</b>  -  array of pathnames of logo_files saved in the working directory
512
 * - <b>internal:CAs</b> - the value is an array produced by X509::processCertificate() with the following filds
513
 * - <b>internal:SSID</b> - an array indexed by SSID strings with values either TKIP or AES; if TKIP is set the both WPA/TKIP and WPA2/AES should be set if AES is set the this is a WPA2/AES only SSID; the consortium's defined SSIDs are always set as the first array elements.
514
 * -<b>internal:profile_count</b> - the number of profiles for the associated IdP
515
 *
516
 *
517
 * these attributes are available and can be used, but the "internal" attributes are better suited for modules
518
 * -  eap:ca_file    -      certificate of the CA signing the RADIUS server key                                         
519
 * - <b>media:SSID</b>       -  additional SSID to configure, WPA2/AES only (device modules should use internal:SSID)
520
 * - <b>media:SSID_with_legacy</b> -  additional SSID to configure, WPA2/AES and WPA/TKIP (device modules should use internal:SSID)
521
 *
522
 * @see X509::processCertificate()
523
 * @var array $attributes
524
 */
525
  public $attributes;
526
/**
527
  * stores the path to the module source location and is used 
528
  * by copyFile and translateFile
529
  * the only reason for it to be a public variable ies that it is set by the DeviceFactory class
530
  * module_path should not be used by module drivers.
531
  * @var string 
532
  */
533
  public $module_path;
534
535
/**
536
 * The optimal EAP type
537
 *
538
 */ 
539
/**
540
  * optimal EAP method selected given profile and device
541
  * @var EAP::constant
542
  */
543
  public $selected_eap;
544
/**
545
  * the path to the profile signing program
546
  * device modules which require signing should use this property to exec the signer
547
  * the signer program must accept two arguments - input and output file names
548
  * the signer program mus operate in the local directory and filenames are relative to this
549
  * directory
550
  *
551
  *@var string
552
  */
553
  public $sign;
554
  public $signer;
555
/**
556
 * the string referencing the language (index ot the Config::$LANGUAGES array).
557
 * It is set to the current language and may be used by the device module to
558
 * set its language
559
 *
560
 *@var string
561
 */
562
  public $lang_index;
563
  /**
564
   * The string identifier of the device (don't show this to users)
565
   * @var string
566
   */
567
  public $device_id;
568
569
  /**
570
   * See devices-template.php for a list of available options
571
   * @var array
572
   */
573
  public $options;
574
575
  /**
576
   * This string will be shown if no support email was configured by the admin
577
   * 
578
   * @var string 
579
   */
580
  public static $support_email_substitute;
581
582
  /**
583
   * This string will be shown if no support URL was configured by the admin
584
   * 
585
   * @var string 
586
   */
587
  public static $support_url_substitute;
588
589
  /**
590
   * This string should be used by all installer modules to set the 
591
   * installer file basename.
592
   *
593
   * @var string 
594
   */
595
  public static $installerBasename;
596
}
597