Completed
Push — master ( af3ce8...b4d558 )
by Stefan
12:25
created

Device_Chromebook::zipInstaller()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 4
nc 1
nop 1
dl 0
loc 5
rs 9.4285
c 0
b 0
f 0
1
<?php
2
3
/* * ********************************************************************************
4
 * (c) 2011-15 GÉANT on behalf of the GN3, GN3plus and GN4 consortia
5
 * License: see the LICENSE file in the root directory
6
 * ********************************************************************************* */
7
?>
8
<?php
9
10
/**
11
 * This file contains the TestModule class
12
 *
13
 * This is a very basic example of using the CAT API.  
14
 *
15
 * The module contains two files
16
 * in the Files directory. They will illustrate the use of the {@link DeviceConfig::copyFile()} method.
17
 * One fille will be coppied without the name change, for the second we will provide a new name.
18
 * The API also contains a similar {@link DeviceConfig::translateFile()} method, which is special to Windows installers and not used in this example.
19
 *
20
 * This module will collect all certificate files stored in the database for a given profile and will copy them to the working directory.
21
 *
22
 * If, for the given profile, an information file is available, this will also be copied to the working directory.
23
 *
24
 * The installer will collect all available configuration attributes and save them to a file in the form of the PHP print_r output.
25
 *
26
 * Finally, the installer will create a zip archive containing all above files and this file 
27
 * will be sent to the user as the configurator file.
28
 *
29
 * Go to the {@link Device_TestModule} and {@link DeviceConfig} class definitions to learn more.
30
 *  
31
 * @package ModuleWriting
32
 */
33
/**
34
 * this array holds the list of EAP methods supported by this device
35
 */
36
/**
37
 * 
38
 */
39
require_once('DeviceConfig.php');
40
require_once('EAP.php');
41
42
/**
43
 * This is the main implementation class of the module
44
 *
45
 * The name of the class must the the 'Device_' followed by the name of the module file
46
 * (without the '.php' extension), so in this case the file is "TestModule.php" and
47
 * the class is Device_TestModule.
48
 *
49
 * The class MUST define the constructor method and one additional 
50
 * public method: {@link writeInstaller()}.
51
 *
52
 * All other methods and properties should be private. This example sets zipInstaller method to protected, so that it can be seen in the documentation.
53
 *
54
 * It is important to understand how the device module fits into the whole picture, so here is s short descrption.
55
 * An external caller (for instance {@link GUI::generateInstaller()}) creates the module device instance and prepares
56
 * its environment for a given user profile by calling {@link DeviceConfig::setup()} method.
57
 *      this will:
58
 *       - create the temporary directory and save its path as $this->FPATH
59
 *       - process the CA certificates and store results in $this->attributes['internal:CAs'][0]
60
 *            $this->attributes['internal:CAs'][0] is an array of processed CA certificates
61
 *            a processed certifincate is an array 
62
 *               'pem' points to pem feromat certificate
63
 *               'der' points to der format certificate
64
 *               'md5' points to md5 fingerprint
65
 *               'sha1' points to sha1 fingerprint
66
 *               'name' points to the certificate subject
67
 *               'root' can be 1 for self-signed certificate or 0 otherwise
68
 *       - save the info_file (if exists) and put the name in $this->attributes['internal:info_file_name'][0]
69
 * Finally, the module {@link DeviceConfig::writeInstaller ()} is called and the returned path name is used for user download.
70
 *
71
 * @package ModuleWriting
72
 */
73
class Device_Chromebook extends DeviceConfig {
74
75
    /**
76
     * Constructs a Device object.
77
     *
78
     * It is CRUTCIAL that the constructor sets $this->supportedEapMethods to an array of methods
79
     * available for the particular device.
80
     * {@source}
81
     * @param string $device a pointer to a device module, which must
0 ignored issues
show
Bug introduced by
There is no parameter named $device. 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...
82
     * be an index of one of the devices defined in the {@link Devices}
83
     * array in {@link devices.php}.
84
     * @final not to be redefined
85
     */
86
    final public function __construct() {
87
        $this->supportedEapMethods = [EAP::$PEAP_MSCHAP2, EAP::$TTLS_PAP, EAP::$TTLS_MSCHAP2, EAP::$TLS];
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...
88
        debug(4, "This device supports the following EAP methods: ");
89
        debug(4, $this->supportedEapMethods);
90
    }
91
92
    /**
93
     * prepare a ONC file
94
     *
95
     * {@source}
96
     * @return string installer path name
97
     */
98
    public function writeInstaller() {
99
        debug(4, "Chromebook Installer start\n");
100
        $caRefs = [];
101
        // we don't do per-user encrypted containers
102
        $jsonArray = ["Type" => "UnencryptedConfiguration"];
103
104
        foreach ($this->attributes['internal:CAs'][0] as $ca) {
105
            $caRefs[] = "{" . $ca['uuid'] . "}";
106
        }
107
        // construct outer id, if anonymity is desired
108
        $outerId = 0;
109 View Code Duplication
        if (isset($this->attributes['internal:use_anon_outer']) && $this->attributes['internal:use_anon_outer'][0] == "1" && isset($this->attributes['internal:realm'])) {
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...
110
            $outerId = "@" . $this->attributes['internal:realm'][0];
111
            if (isset($this->attributes['internal:anon_local_value']))
112
                $outerId = $this->attributes['internal:anon_local_value'][0] . $outerId;
113
        }
114
        
115
        // define networks
116
        foreach ($this->attributes['internal:SSID'] as $ssid => $cryptolevel) {
117
            $networkUuid = uuid($prefix, $ssid);
0 ignored issues
show
Bug introduced by
The variable $prefix does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
118
            $eapPrettyprint = EAP::eapDisplayName($this->selected_eap);
119
            // ONC has its own enums, and guess what, they don't always match
120 View Code Duplication
            if ($eapPrettyprint["OUTER"] == "PEAP" && $eapPrettyprint["INNER"] == "MSCHAPV2")
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...
121
                // the dictionary entry EAP-MSCHAPv2 does not work. Setting MSCHAPv2 does. (ChromeOS 50)
122
                $eapPrettyprint["INNER"] = "MSCHAPv2";
123 View Code Duplication
            if ($eapPrettyprint["OUTER"] == "TTLS" && $eapPrettyprint["INNER"] == "MSCHAPV2") {
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...
124
                $eapPrettyprint["OUTER"] = "EAP-TTLS";
125
                $eapPrettyprint["INNER"] = "MSCHAPv2";
126
            }
127
            if ($eapPrettyprint["OUTER"] == "TLS")
128
                $eapPrettyprint["OUTER"] = "EAP-TLS";
129
            // define EAP properties
130
131
            $eaparray = array("Outer" => $eapPrettyprint["OUTER"]);
132
            if ($eapPrettyprint["INNER"] == "MSCHAPv2")
133
                $eaparray["Inner"] = $eapPrettyprint["INNER"];
134
            $eaparray["SaveCredentials"] = true;
135
            $eaparray["ServerCARefs"] = $caRefs; // maybe takes just one CA?
136
            $eaparray["UseSystemCAs"] = false;
137
                    
138
            if ($outerId)
139
                $eaparray["AnonymousIdentity"] = "$outerId";
140
            
141
            $jsonArray["NetworkConfigurations"][] = [
142
                "GUID" => $networkUuid,
143
                "Name" => "$ssid",
144
                "Type" => "WiFi",
145
                "WiFi" => [
146
                    "AutoConnect" => true,
147
                    "EAP" => $eaparray,
148
                    "HiddenSSID" => false,
149
                    "SSID" => $ssid,
150
                    "Security" => "WPA-EAP",
151
                ],
152
                "ProxySettings" => ["Type" => "WPAD"],
153
            ];
154
        };
155
        // are we also configuring wired?
156
        if (isset($this->attributes['media:wired'])) {
157
            $networkUuid = "{" . uuid($prefix, "wired-dot1x-ethernet") . "}";
158
            $jsonArray["NetworkConfigurations"][] = [
159
                "GUID" => $networkUuid,
160
                "Name" => "eduroam configuration (wired network)",
161
                "Type" => "Ethernet",
162
                "Ethernet" => [
163
                    "Authentication" => "8021X",
164
                    "EAP" => $eaparray,
0 ignored issues
show
Bug introduced by
The variable $eaparray 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...
165
                ],
166
                "ProxySettings" => ["Type" => "WPAD"],
167
            ];
168
        };
169
170
        // define CA certificates
171
        foreach ($this->attributes['internal:CAs'][0] as $ca) {
172
            // strip -----BEGIN CERTIFICATE----- and -----END CERTIFICATE-----
173
            debug(2,$ca['pem']);
174
            $caSanitized = substr($ca['pem'], 27, strlen($ca['pem']) - 27 - 25 - 1);
175
            debug(2,$caSanitized."\n");
176
            // remove \n
177
            $caSanitized = str_replace("\n", "", $caSanitized);
178
            $jsonArray["Certificates"][] = ["GUID" => "{" . $ca['uuid'] . "}", "Type" => "Authority", "X509" => $caSanitized];
179
            debug(2,$caSanitized."\n");
180
        }
181
                
182
        $outputJson = json_encode($jsonArray, JSON_PRETTY_PRINT);
183
        $outputFile = fopen('installer_profile', 'w');
184
        fwrite($outputFile, $outputJson);
185
        fclose($outputFile);
186
187
        $fileName = $this->installerBasename . '.onc';
188
//        if ($this->sign) {
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...
189
//            $o = system($this->sign . " installer_profile '$e' > /dev/null");
190
//           if ($o === FALSE)
191
//                debug(2, "Signing the mobileconfig installer $e FAILED!\n");
192
//        } else
193
        rename("installer_profile", $fileName);
194
        return $fileName;
195
    }
196
197
    /**
198
     * prepare module desctiption and usage information
199
     * {@source}
200
     * @return string HTML text to be displayed in the information window
201
     */
202
    public function writeDeviceInfo() {
203
        $out = "<p>";
204
        $out .= _("This installer is an example only. It produces a zip file containig the IdP certificates, info and logo files (if such have been defined by the IdP administrator) and a dump of all available attributes.");
205
        return $out;
206
    }
207
}
208