Test Setup Failed
Push — master ( de37f4...b19653 )
by Tomasz
05:59
created

DeviceW8W10::saveLogo()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 3
c 0
b 0
f 0
dl 0
loc 5
rs 10
cc 1
nc 1
nop 0
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
        if ($setWired) {
90
            $this->loggerInstance->debug(4, "Saving LAN profile\n");
91
            $windowsProfile = $this->generateLANprofile();
92
            $this->saveProfile($windowsProfile);
93
        }
94
        $this->saveCerts();
95
        if ($this->selectedEap == \core\common\EAP::EAPTYPE_SILVERBULLET) {
96
            $this->writeClientP12File();
97
        }
98
        $this->copyFiles($this->selectedEap);
99
        $this->saveLogo();
100
        $this->writeMainNSH($this->selectedEap, $this->attributes);
101
        $this->compileNSIS();
102
        $installerPath = $this->signInstaller();
103
        \core\common\Entity::outOfThePotatoes();
104
        return $installerPath;
105
    }
106
    
107
    private function createProfileDir()
108
    {
109
        if (!is_dir('profiles')) {
110
            mkdir('profiles');
111
        }
112
    }
113
    
114
    /**
115
     * If separateHS20profiles is true then we should be saving OID and SSID
116
     * profiles separately. OID profiles should be considered optionl, i.e.
117
     * the installer should not report installation failure (??). If we decide
118
     * that such installation failures should be silent then it is enough if
119
     * these profiles are marked as hs20 and no "nohs" profiles are created
120
     */
121
    
122
    private function saveNetworkProfileSeparateHS($name, $network)
123
    {
124
        $profileName = iconv('UTF-8', 'ASCII//IGNORE', $name);
125
        $out = '';
126
        if (!empty($network['ssid'])) {
127
            $windowsProfileSSID = $this->generateWlanProfile($profileName, $network['ssid'], 'WPA2', 'AES', [], false);
128
            $this->saveProfile($windowsProfileSSID, $this->iterator, true);
129
            $out = "!insertmacro define_wlan_profile \"$profileName\" \"AES\" 0\n";
130
            $this->iterator ++;
131
            $profileName .= " via Hotspot 2.0";
132
        }
133
        if (!empty($network['oi'])) {
134
            $windowsProfileHS = $this->generateWlanProfile($profileName, ['cat-passpoint-profile'], 'WPA2', 'AES', $network['oi'], true);
135
            $this->saveProfile($windowsProfileHS, $this->iterator, true);
136
            $out .= "!insertmacro define_wlan_profile \"$profileName\" \"AES\" 1\n";
137
            $this->iterator ++;
138
        }
139
        return($out);
140
    }
141
    
142
    /**
143
     * If separateHS20profiles is false then we should be saving a hs20 profile
144
     * containing both OIDs and SSIDs. In addiotion we should also be saving
145
     * a nohs_... profile. When  the installer runs it first tries the normal
146
     * profile and if this fails it will try the nohs (if one exists)
147
     */
148
    
149
    private function saveNetworkProfileJoinedHS($name, $network)
150
    {
151
        $profileName = iconv('UTF-8', 'ASCII//IGNORE', $name);
152
        $oiOnly = false;
153
        if ($network['ssid'] == []) {
154
            $oiOnly = true;
155
            $network['ssid'] = ['cat-passpoint-profile'];
156
        }
157
        $windowsProfile = $this->generateWlanProfile($profileName, $network['ssid'], 'WPA2', 'AES', $network['oi'], true);
158
        $this->saveProfile($windowsProfile, $this->iterator, true);
159
        if (!$oiOnly) {
160
            $windowsProfile = $this->generateWlanProfile($profileName, $network['ssid'], 'WPA2', 'AES', [], false);
161
            $this->saveProfile($windowsProfile, $this->iterator, false);
162
        }
163
        $this->iterator ++;
164
        return("!insertmacro define_wlan_profile \"$profileName\" \"AES\" 1\n");
165
    }
166
167
    private function saveLogo()
168
    {
169
        $fedLogo = $this->attributes['fed:logo_file'] ?? NULL;
170
        $idpLogo = $this->attributes['internal:logo_file'] ?? NULL;
171
        $this->combineLogo($idpLogo, $fedLogo);
172
    }
173
174
    private function writeMainNSH($eap, $attr)
175
    {
176
        $this->loggerInstance->debug(4, "writeMainNSH");
177
        $this->loggerInstance->debug(4, $attr);
178
        $this->loggerInstance->debug(4, "Device_id = ".$this->device_id."\n");
179
        $fcontents = "!define W8\n";
180
        if ($this->device_id == 'w10') {
181
            $fcontents .= "!define W10\n";
182
        }
183
        $fcontents .= "Unicode true\n";
184
        if ($this->useGeantLink) {
185
            $eapStr = 'GEANTLink';
186
        } else {
187
            $eapStr = \core\common\EAP::eapDisplayName($this->selectedEap)['OUTER'];
188
        }
189
        if (isset($this->tlsOtherUsername) && $this->tlsOtherUsername == 1) {
190
            $fcontents .= "!define PFX_USERNAME\n";
191
        }
192
        if ($eap == \core\common\EAP::EAPTYPE_SILVERBULLET) {
193
            $fcontents .= "!define SILVERBULLET\n";
194
        }
195
        $fcontents .= '!define '.$eapStr;
196
        $fcontents .= "\n".'!define EXECLEVEL "user"';
197
        $fcontents .= $this->writeNsisDefines($attr);
198
        file_put_contents('main.nsh', $fcontents);
199
    }
200
201
    
202
    private function copyFiles($eap)
203
    {
204
        $this->loggerInstance->debug(4, "copyFiles start\n");
205
        $this->copyBasicFiles();
206
        switch ($eap["OUTER"]) {
207
            case \core\common\EAP::TTLS:
208
                if ($this->useGeantLink) {
209
                    $this->copyGeantLinkFiles();
210
                } else {
211
                    $this->copyStandardNsi();
212
                }
213
                break;
214
            default:
215
                $this->copyStandardNsi();
216
        }
217
        $this->loggerInstance->debug(4, "copyFiles end\n");
218
        return true;
219
    }
220
    
221
    private function copyStandardNsi()
222
    {
223
        if (!$this->translateFile('eap_w8.inc', 'cat.NSI')) {
224
            throw new Exception("Translating needed file eap_w8.inc failed!");
225
        }
226
    }
227
    
228
    private function saveCerts()
229
    {
230
        $caArray = $this->saveCertificateFiles('der');
231
        $fcontentsCerts = '';
232
        $fileHandleCerts = fopen('certs.nsh', 'w');
233
        if ($fileHandleCerts === false) {
234
            throw new Exception("Unable to open new certs.nsh file for writing CAs.");
235
        }
236
        foreach ($caArray as $certAuthority) {
237
            $store = $certAuthority['root'] ? "root" : "ca";
238
            $fcontentsCerts .= '!insertmacro install_ca_cert "'.$certAuthority['file'].'" "'.$certAuthority['sha1'].'" "'.$store."\"\n";
239
        }
240
        fwrite($fileHandleCerts, $fcontentsCerts);
241
        fclose($fileHandleCerts);
242
    }
243
244
    /* saveProvile writes a LAN or WLAN profile
245
     * @param string $profile the XML content to be saved
246
     * @param int $profileNumber the profile index or NULL to indicate a LAN profile
247
     * @param boolean $hs20 for WLAN profiles indicates if use the nohs prefix
248
     */
249
    private function saveProfile($profile, $profileNumber=NULL, $hs20=false)
250
    {
251
        if ($hs20) {
252
            $prefix = 'w';
253
        } else {
254
            $prefix = 'nohs_w';
255
        }
256
        if (is_null($profileNumber)) {
257
            $prefix = '';
258
            $suffix = '';
259
        } else {
260
            $suffix = "-$profileNumber";
261
        }
262
        $xmlFname = "profiles/".$prefix."lan_prof".$suffix.".xml";
263
        $this->loggerInstance->debug(4, "Saving profile to ".$xmlFname."\n");
264
        file_put_contents($xmlFname, $profile);
265
    }
266
267
    /**
268
     * Selects the approprate handler for a given EAP type and retirns
269
     * an initiated object
270
     * 
271
     * @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...
272
     */
273
    
274
    private function setEapObject()
275
    {        
276
        switch ($this->selectedEap['OUTER']) {
277
            case \core\common\EAP::TTLS:
278
                if ($this->useGeantLink) {
279
                    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...
280
                } else {
281
                    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...
282
                }
283
            case \core\common\EAP::PEAP:
284
                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...
285
            case \core\common\EAP::TLS:
286
                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...
287
            default:
288
                // use Exception here
289
                break;
290
        }
291
    }
292
    
293
    private function setupEapConfig() {
294
        $servers = empty($this->attributes['eap:server_name']) ? '' : implode(';', $this->attributes['eap:server_name']);
295
        $outerId = $this->determineOuterIdString();
296
        $nea = (\core\common\Entity::getAttributeValue($this->attributes, 'media:wired', 0) === 'on') ? 'true' : 'false';
297
        $otherTlsName = \core\common\Entity::getAttributeValue($this->attributes, 'eap-specific:tls_use_other_id', 0) === 'on' ? 'true' : 'false';
298
        $this->useGeantLink =  \core\common\Entity::getAttributeValue($this->attributes, 'device-specific:geantlink', $this->device_id)[0] === 'on' ? true : false;
299
        $eapConfig = $this->setEapObject();
300
        $eapConfig->setInnerType($this->selectedEap['INNER']);
301
        $eapConfig->setInnerTypeDisplay(\core\common\EAP::eapDisplayName($this->selectedEap)['INNER']);
302
        $eapConfig->setCAList($this->getAttribute('internal:CAs')[0]);
303
        $eapConfig->setServerNames($servers);
304
        $eapConfig->setOuterId($outerId);
305
        $eapConfig->setNea($nea);
306
        $eapConfig->setDisplayName($this->translateString($this->attributes['general:instname'][0]));
307
        $eapConfig->setIdPId($this->deviceUUID);
308
        $eapConfig->setOtherTlsName($otherTlsName);
309
        $eapConfig->setConfig();
310
        $this->eapConfigObject = $eapConfig;
311
    } 
312
        
313
    private function generateWlanProfile($networkName, $ssids, $authentication, $encryption, $ois, $hs20 = false)
314
    {
315
        if (empty($this->attributes['internal:realm'][0])) {
316
            $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...
317
        } else {
318
            $domainName = $this->attributes['internal:realm'][0];
319
        }
320
        $wlanProfile = new MsWlanProfile();
321
        $wlanProfile->setName($networkName);       
322
        $wlanProfile->setEncryption($authentication, $encryption);
323
        $wlanProfile->setSSIDs($ssids);
324
        $wlanProfile->setHS20($hs20);
325
        $wlanProfile->setOIs($ois);
326
        $wlanProfile->setDomainName($domainName);
327
        $wlanProfile->setEapConfig($this->eapConfigObject);
328
        return($wlanProfile->writeWLANprofile());
329
    }
330
    
331
    private function generateLanProfile()
332
    {
333
        $lanProfile = new MsLanProfile();
334
        $lanProfile->setEapConfig($this->eapConfigObject);
335
        return($lanProfile->writeLANprofile());
336
    }
337
338
    private $eapTypeId;
0 ignored issues
show
introduced by
The private property $eapTypeId is not used, and could be removed.
Loading history...
339
    private $eapAuthorId;
0 ignored issues
show
introduced by
The private property $eapAuthorId is not used, and could be removed.
Loading history...
340
    private $eapConfigObject;
341
    private $profileNames;
342
    private $iterator;
343
}
344
345
346
347