Test Failed
Push — master ( dfcfa3...dad7bc )
by Tomasz
24:34
created

DeviceW8W10::writeInstaller()   C

Complexity

Conditions 10
Paths 240

Size

Total Lines 44
Code Lines 35

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
eloc 35
c 2
b 0
f 0
dl 0
loc 44
rs 6.3333
cc 10
nc 240
nop 0

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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 file creates MS Windows 8 and 10 installers
25
 * It supports EAP-TLS, TTLS (both native and GEANTLink), PEAP.
26
 * Other EAP methods could be added.
27
 * 
28
 * The file is an interface between the global CAT system and individual EAP
29
 * methods modules. It also performs global operations like preparing
30
 * and saving cerificates and generating the installers.
31
 * 
32
 * Adding a new EAP handler requres defining an extension of the MsEapProfile
33
 * class. Such an extension is required to define a public getConfig method
34
 * returning a valid Windows XML <Config> element.
35
 * Extensions to Files/common.inc will also be required.
36
 * 
37
 * @author Tomasz Wolniewicz <[email protected]>
38
 *
39
 * @package ModuleWriting
40
 */
41
42
namespace devices\ms;
43
use Exception;
44
//require_once dirname(__FILE__) . '/DeviceXMLmain.php';
45
46
class DeviceW8W10 extends \devices\ms\WindowsCommon
47
{
48
    public function __construct()
49
    {
50
        parent::__construct();
51
        \core\common\Entity::intoThePotatoes();
52
        $this->setSupportedEapMethods([
53
            \core\common\EAP::EAPTYPE_TLS,
54
            \core\common\EAP::EAPTYPE_PEAP_MSCHAP2,
55
            \core\common\EAP::EAPTYPE_TTLS_PAP,
56
            \core\common\EAP::EAPTYPE_TTLS_MSCHAP2,
57
            \core\common\EAP::EAPTYPE_SILVERBULLET
58
        ]);
59
        $this->profileNames = [];
60
        $this->specialities['internal:use_anon_outer'][serialize(\core\common\EAP::EAPTYPE_PEAP_MSCHAP2)] = _("Anonymous identities do not use the realm as specified in the profile - it is derived from the suffix of the user's username input instead.");
61
        $this->specialities['media:openroaming'] = _("While OpenRoaming can be configured, it is possible that the Wi-Fi hardware does not support it; then the network definition is ignored.");
62
        $this->specialities['media:consortium_OI'] = _("While Passpoint networks can be configured, it is possible that the Wi-Fi hardware does not support it; then the network definition is ignored.");
63
        \core\common\Entity::outOfThePotatoes();
64
    } 
65
    
66
    /**
67
     * create the actual installer executable
68
     * 
69
     * @return string filename of the generated installer
70
     *
71
     */  
72
    public function writeInstaller()
73
    {
74
        \core\common\Entity::intoThePotatoes();
75
        $this->prepareInstallerLang();
76
        $this->setupEapConfig();
77
        $setWired = isset($this->attributes['media:wired'][0]) && $this->attributes['media:wired'][0] == 'on' ? 1 : 0;
78
        $this->iterator = 0;
79
        $fcontentsProfile = '';
80
        $this->createProfileDir();
81
        foreach ($this->attributes['internal:networks'] as $networkName => $oneNetwork) {
82
            if ($this::separateHS20profiles === true) {
83
                $fcontentsProfile .= $this->saveNetworkProfileSeparateHS($networkName, $oneNetwork);
84
            } else {
85
                $fcontentsProfile .= $this->saveNetworkProfileJoinedHS($networkName, $oneNetwork);
86
            }
87
        }
88
        file_put_contents('profiles.nsh', $fcontentsProfile);
89
        $delSSIDs = $this->attributes['internal:remove_SSID'];
90
        $delProfiles = [];
91
        foreach ($delSSIDs as $ssid => $cipher) {
92
            if ($cipher == 'DEL') {
93
                $delProfiles[] = $ssid;
94
            }
95
            if ($cipher == 'TKIP') {
96
                $delProfiles[] = $ssid.' (TKIP)';
97
            }
98
        }
99
        $this->writeAdditionalDeletes($delProfiles);
100
        if ($setWired) {
101
            $this->loggerInstance->debug(4, "Saving LAN profile\n");
102
            $windowsProfile = $this->generateLANprofile();
103
            $this->saveProfile($windowsProfile);
104
        }
105
        $this->saveCerts();
106
        if ($this->selectedEap == \core\common\EAP::EAPTYPE_SILVERBULLET) {
107
            $this->writeClientP12File();
108
        }
109
        $this->copyFiles($this->selectedEap);
110
        $this->saveLogo();
111
        $this->writeMainNSH($this->selectedEap, $this->attributes);
112
        $this->compileNSIS();
113
        $installerPath = $this->signInstaller();
114
        \core\common\Entity::outOfThePotatoes();
115
        return $installerPath;
116
    }
117
    
118
    private function createProfileDir()
119
    {
120
        if (!is_dir('profiles')) {
121
            mkdir('profiles');
122
        }
123
    }
124
    
125
    /**
126
     * If separateHS20profiles is true then we should be saving OID and SSID
127
     * profiles separately. OID profiles should be considered optionl, i.e.
128
     * the installer should not report installation failure (??). If we decide
129
     * that such installation failures should be silent then it is enough if
130
     * these profiles are marked as hs20 and no "nohs" profiles are created
131
     */
132
    
133
    private function saveNetworkProfileSeparateHS($profileName, $network)
134
    {
135
        $out = '';
136
        if (!empty($network['ssid'])) {
137
            $windowsProfileSSID = $this->generateWlanProfile($profileName, $network['ssid'], 'WPA2', 'AES', [], false);
138
            $this->saveProfile($windowsProfileSSID, $this->iterator, true);
139
            $out = "!insertmacro define_wlan_profile \"$profileName\" \"AES\" 0\n";
140
            $this->iterator ++;
141
            $profileName .= " via partner";
142
        }
143
        if (!empty($network['oi'])) {
144
            $windowsProfileHS = $this->generateWlanProfile($profileName, ['cat-passpoint-profile'], 'WPA2', 'AES', $network['oi'], true);
145
            $this->saveProfile($windowsProfileHS, $this->iterator, true);
146
            $out .= "!insertmacro define_wlan_profile \"$profileName\" \"AES\" 1\n";
147
            $this->iterator ++;
148
        }
149
        return($out);
150
    }
151
    
152
    /**
153
     * If separateHS20profiles is false then we should be saving a hs20 profile
154
     * containing both OIDs and SSIDs. In addiotion we should also be saving
155
     * a nohs_... profile. When  the installer runs it first tries the normal
156
     * profile and if this fails it will try the nohs (if one exists)
157
     */
158
    
159
    private function saveNetworkProfileJoinedHS($profileName, $network)
160
    {
161
        $oiOnly = false;
162
        if ($network['ssid'] == []) {
163
            $oiOnly = true;
164
            $network['ssid'] = ['cat-passpoint-profile'];
165
        }
166
        $windowsProfile = $this->generateWlanProfile($profileName, $network['ssid'], 'WPA2', 'AES', $network['oi'], true);
167
        $this->saveProfile($windowsProfile, $this->iterator, true);
168
        if (!$oiOnly) {
169
            $windowsProfile = $this->generateWlanProfile($profileName, $network['ssid'], 'WPA2', 'AES', [], false);
170
            $this->saveProfile($windowsProfile, $this->iterator, false);
171
        }
172
        $this->iterator ++;
173
        return("!insertmacro define_wlan_profile \"$profileName\" \"AES\" 1\n");
174
    }
175
176
    private function saveLogo()
177
    {
178
        $fedLogo = $this->attributes['fed:logo_file'] ?? NULL;
179
        $idpLogo = $this->attributes['internal:logo_file'] ?? NULL;
180
        $this->combineLogo($idpLogo, $fedLogo);
181
    }
182
183
    private function writeMainNSH($eap, $attr)
184
    {
185
        $this->loggerInstance->debug(4, "writeMainNSH");
186
        $this->loggerInstance->debug(4, $attr);
187
        $this->loggerInstance->debug(4, "Device_id = ".$this->device_id."\n");
188
        $fcontents = "!define W8\n";
189
        if ($this->device_id == 'w10') {
190
            $fcontents .= "!define W10\n";
191
        }
192
        $fcontents .= "Unicode true\n";
193
        if ($this->useGeantLink) {
194
            $eapStr = 'GEANTLink';
195
        } else {
196
            $eapStr = \core\common\EAP::eapDisplayName($this->selectedEap)['OUTER'];
197
        }
198
        if (isset($this->tlsOtherUsername) && $this->tlsOtherUsername == 1) {
199
            $fcontents .= "!define PFX_USERNAME\n";
200
        }
201
        if ($eap == \core\common\EAP::EAPTYPE_SILVERBULLET) {
202
            $fcontents .= "!define SILVERBULLET\n";
203
        }
204
        $fcontents .= '!define '.$eapStr;
205
        $fcontents .= "\n".'!define EXECLEVEL "user"';
206
        $fcontents .= $this->writeNsisDefines($attr);
207
        file_put_contents('main.nsh', $fcontents);
208
    }
209
210
    
211
    private function copyFiles($eap)
212
    {
213
        $this->loggerInstance->debug(4, "copyFiles start\n");
214
        $this->copyBasicFiles();
215
        switch ($eap["OUTER"]) {
216
            case \core\common\EAP::TTLS:
217
                if ($this->useGeantLink) {
218
                    $this->copyGeantLinkFiles();
219
                } else {
220
                    $this->copyStandardNsi();
221
                }
222
                break;
223
            default:
224
                $this->copyStandardNsi();
225
        }
226
        $this->loggerInstance->debug(4, "copyFiles end\n");
227
        return true;
228
    }
229
    
230
    private function copyStandardNsi()
231
    {
232
        if (!$this->translateFile('eap_w8.inc', 'cat.NSI')) {
233
            throw new Exception("Translating needed file eap_w8.inc failed!");
234
        }
235
    }
236
    
237
    private function saveCerts()
238
    {
239
        $caArray = $this->saveCertificateFiles('der');
240
        $fcontentsCerts = '';
241
        $fileHandleCerts = fopen('certs.nsh', 'w');
242
        if ($fileHandleCerts === false) {
243
            throw new Exception("Unable to open new certs.nsh file for writing CAs.");
244
        }
245
        foreach ($caArray as $certAuthority) {
246
            $store = $certAuthority['root'] ? "root" : "ca";
247
            $fcontentsCerts .= '!insertmacro install_ca_cert "'.$certAuthority['file'].'" "'.$certAuthority['sha1'].'" "'.$store."\"\n";
248
        }
249
        fwrite($fileHandleCerts, $fcontentsCerts);
250
        fclose($fileHandleCerts);
251
    }
252
253
    /* saveProvile writes a LAN or WLAN profile
254
     * @param string $profile the XML content to be saved
255
     * @param int $profileNumber the profile index or NULL to indicate a LAN profile
256
     * @param boolean $hs20 for WLAN profiles indicates if use the nohs prefix
257
     */
258
    private function saveProfile($profile, $profileNumber=NULL, $hs20=false)
259
    {
260
        if ($hs20) {
261
            $prefix = 'w';
262
        } else {
263
            $prefix = 'nohs_w';
264
        }
265
        if (is_null($profileNumber)) {
266
            $prefix = '';
267
            $suffix = '';
268
        } else {
269
            $suffix = "-$profileNumber";
270
        }
271
        $xmlFname = "profiles/".$prefix."lan_prof".$suffix.".xml";
272
        $this->loggerInstance->debug(4, "Saving profile to ".$xmlFname."\n");
273
        file_put_contents($xmlFname, $profile);
274
    }
275
276
    /**
277
     * Selects the approprate handler for a given EAP type and retirns
278
     * an initiated object
279
     * 
280
     * @return a profile object
0 ignored issues
show
Bug introduced by
The type devices\ms\a was not found. Did you mean a? If so, make sure to prefix the type with \.
Loading history...
281
     */
282
    
283
    private function setEapObject()
284
    {        
285
        switch ($this->selectedEap['OUTER']) {
286
            case \core\common\EAP::TTLS:
287
                if ($this->useGeantLink) {
288
                    return(new GeantLinkTtlsProfile());
0 ignored issues
show
Bug Best Practice introduced by
The expression return new devices\ms\GeantLinkTtlsProfile() returns the type devices\ms\GeantLinkTtlsProfile which is incompatible with the documented return type devices\ms\a.
Loading history...
289
                } else {
290
                    return(new MsTtlsProfile());
0 ignored issues
show
Bug Best Practice introduced by
The expression return new devices\ms\MsTtlsProfile() returns the type devices\ms\MsTtlsProfile which is incompatible with the documented return type devices\ms\a.
Loading history...
291
                }
292
            case \core\common\EAP::PEAP:
293
                return(new MsPeapProfile());
0 ignored issues
show
Bug Best Practice introduced by
The expression return new devices\ms\MsPeapProfile() returns the type devices\ms\MsPeapProfile which is incompatible with the documented return type devices\ms\a.
Loading history...
294
            case \core\common\EAP::TLS:
295
                return(new MsTlsProfile());
0 ignored issues
show
Bug Best Practice introduced by
The expression return new devices\ms\MsTlsProfile() returns the type devices\ms\MsTlsProfile which is incompatible with the documented return type devices\ms\a.
Loading history...
296
            default:
297
                // use Exception here
298
                break;
299
        }
300
    }
301
    
302
    private function setupEapConfig() {
303
        $servers = empty($this->attributes['eap:server_name']) ? '' : implode(';', $this->attributes['eap:server_name']);
304
        $outerId = $this->determineOuterIdString();
305
        $nea = (\core\common\Entity::getAttributeValue($this->attributes, 'media:wired', 0) === 'on') ? 'true' : 'false';
306
        $otherTlsName = \core\common\Entity::getAttributeValue($this->attributes, 'eap-specific:tls_use_other_id', 0) === 'on' ? 'true' : 'false';
307
        $this->useGeantLink =  \core\common\Entity::getAttributeValue($this->attributes, 'device-specific:geantlink', $this->device_id)[0] === 'on' ? true : false;
308
        $eapConfig = $this->setEapObject();
309
        $eapConfig->setInnerType($this->selectedEap['INNER']);
310
        $eapConfig->setInnerTypeDisplay(\core\common\EAP::eapDisplayName($this->selectedEap)['INNER']);
311
        $eapConfig->setCAList($this->getAttribute('internal:CAs')[0]);
312
        $eapConfig->setServerNames($servers);
313
        $eapConfig->setOuterId($outerId);
314
        $eapConfig->setNea($nea);
315
        $eapConfig->setDisplayName($this->translateString($this->attributes['general:instname'][0]));
316
        $eapConfig->setIdPId($this->deviceUUID);
317
        $eapConfig->setOtherTlsName($otherTlsName);
318
        $eapConfig->setConfig();
319
        $this->eapConfigObject = $eapConfig;
320
    } 
321
        
322
    private function generateWlanProfile($networkName, $ssids, $authentication, $encryption, $ois, $hs20 = false)
323
    {
324
        if (empty($this->attributes['internal:realm'][0])) {
325
            $domainName = CONFIG_CONFASSISTANT['CONSORTIUM']['interworking-domainname-fallback'];
0 ignored issues
show
Bug introduced by
The constant devices\ms\CONFIG_CONFASSISTANT was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
326
        } else {
327
            $domainName = $this->attributes['internal:realm'][0];
328
        }
329
        $wlanProfile = new MsWlanProfile();
330
        $wlanProfile->setName($networkName);       
331
        $wlanProfile->setEncryption($authentication, $encryption);
332
        $wlanProfile->setSSIDs($ssids);
333
        $wlanProfile->setHS20($hs20);
334
        $wlanProfile->setOIs($ois);
335
        $wlanProfile->setDomainName($domainName);
336
        $wlanProfile->setEapConfig($this->eapConfigObject);
337
        return($wlanProfile->writeWLANprofile());
338
    }
339
    
340
    private function generateLanProfile()
341
    {
342
        $lanProfile = new MsLanProfile();
343
        $lanProfile->setEapConfig($this->eapConfigObject);
344
        return($lanProfile->writeLANprofile());
345
    }
346
347
    private $eapTypeId;
0 ignored issues
show
introduced by
The private property $eapTypeId is not used, and could be removed.
Loading history...
348
    private $eapAuthorId;
0 ignored issues
show
introduced by
The private property $eapAuthorId is not used, and could be removed.
Loading history...
349
    private $eapConfigObject;
350
    private $profileNames;
351
    private $iterator;
352
}
353
354
355
356