Passed
Push — master ( 09cfdd...94b89f )
by Stefan
07:21 queued 03:30
created

WindowsCommon::compileNSIS()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 9
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 9
c 0
b 0
f 0
rs 9.6666
cc 2
eloc 7
nc 2
nop 0
1
<?php
2
/*
3
 * ******************************************************************************
4
 * Copyright 2011-2017 DANTE Ltd. and GÉANT on behalf of the GN3, GN3+, GN4-1 
5
 * and GN4-2 consortia
6
 *
7
 * License: see the web/copyright.php file in the file structure
8
 * ******************************************************************************
9
 */
10
11
/**
12
 * This file contains common functions needed by all Windows installers
13
 * @author Tomasz Wolniewicz <[email protected]>
14
 *
15
 * @package ModuleWriting
16
 */
17
18
namespace devices\ms;
19
use \Exception;
20
21
/**
22
 * This class defines common functions needed by all Windows installers
23
 * @author Tomasz Wolniewicz <[email protected]>
24
 *
25
 * @package ModuleWriting
26
 */
27
abstract class WindowsCommon extends \core\DeviceConfig {
28
29
    public function copyBasicFiles() {
30
        if (!($this->copyFile('wlan_test.exe') &&
31
                $this->copyFile('check_wired.cmd') &&
32
                $this->copyFile('install_wired.cmd') &&
33
                $this->copyFile('cat_bg.bmp') &&
34
                $this->copyFile('base64.nsh'))) {
35
            throw new Exception("Copying needed files (part 1) failed for at least one file!");
36
        }
37
38
        if (!($this->copyFile('cat32.ico') &&
39
                $this->copyFile('cat_150.bmp') &&
40
                $this->copyFile('WLANSetEAPUserData/WLANSetEAPUserData32.exe', 'WLANSetEAPUserData32.exe') &&
41
                $this->copyFile('WLANSetEAPUserData/WLANSetEAPUserData64.exe', 'WLANSetEAPUserData64.exe'))) {
42
            throw new Exception("Copying needed files (part 2) failed for at least one file!");
43
        }
44
        if (!$this->translateFile('common.inc', 'common.nsh', $this->codePage)) {
45
            throw new Exception("Translating needed file common.inc failed!");
46
        }
47
        return;
48
    }
49
50
    public function copyPwdFiles() {
51
        if (!($this->copyFile('Aruba_Networks_EAP-pwd_x32.msi') &&
52
                $this->copyFile('Aruba_Networks_EAP-pwd_x64.msi'))) {
53
            throw new Exception("Copying needed files (EAP-pwd) failed for at least one file!");
54
        }
55
        if (!$this->translateFile('pwd.inc', 'cat.NSI', $this->codePage)) {
56
            throw new Exception("Translating needed file pwd.inc failed!");
57
        }
58
    }
59
60
    public function copyGeantLinkFiles() {
61
        if (!($this->copyFile('GEANTLink/GEANTLink32.msi', 'GEANTLink32.msi') &&
62
                $this->copyFile('GEANTLink/GEANTLink64.msi', 'GEANTLink64.msi') &&
63
                $this->copyFile('GEANTLink/CredWrite.exe', 'CredWrite.exe') &&
64
                $this->copyFile('GEANTLink/MsiUseFeature.exe', 'MsiUseFeature.exe'))) {
65
            throw new Exception("Copying needed files (GEANTLink) failed for at least one file!");
66
        }
67
        if (!$this->translateFile('geant_link.inc', 'cat.NSI', $this->codePage)) {
68
            throw new Exception("Translating needed file geant_link.inc failed!");
69
        }
70
    }
71
72
73
    /**
74
     * function to escape double quotes in a special NSI-compatible way
75
     * 
76
     * @param string $in input string
77
     * @return string
78
     */
79
    public static function echo_nsi($in) {
80
        echo preg_replace('/"/', '$\"', $in);
81
    }
82
83
    /**
84
     * @param string $input input string
85
     * @return string
86
     */
87
    public static function sprint_nsi($input) {
88
        return preg_replace('/"/', '$\"', $input);
89
    }
90
91
    public function __construct() {
92
        parent::__construct();
93
        $this->useGeantLink = (isset($this->options['args']) && $this->options['args'] == 'gl') ? 1 : 0;
94
    }
95
96
    protected function prepareInstallerLang() {
97
        if (isset($this->LANGS[$this->languageInstance->getLang()])) {
98
            $language = $this->LANGS[$this->languageInstance->getLang()];
99
            $this->lang = $language['nsis'];
100
            $this->codePage = 'cp' . $language['cp'];
101
        } else {
102
            $this->lang = 'English';
103
            $this->codePage = 'cp1252';
104
        }
105
    }
106
107
    public function writeDeviceInfo() {
108
        $ssidCount = count($this->attributes['internal:SSID']);
109
        $out = "<p>";
110
        $out .= sprintf(_("%s installer will be in the form of an EXE file. It will configure %s on your device, by creating wireless network profiles.<p>When you click the download button, the installer will be saved by your browser. Copy it to the machine you want to configure and execute."), CONFIG_CONFASSISTANT['CONSORTIUM']['display_name'], CONFIG_CONFASSISTANT['CONSORTIUM']['display_name']);
111
        $out .= "<p>";
112
        if ($ssidCount > 1) {
113
            if ($ssidCount > 2) {
114
                $out .= sprintf(_("In addition to <strong>%s</strong> the installer will also configure access to the following networks:"), implode(', ', CONFIG_CONFASSISTANT['CONSORTIUM']['ssid'])) . " ";
115
            } else {
116
                $out .= sprintf(_("In addition to <strong>%s</strong> the installer will also configure access to:"), implode(', ', CONFIG_CONFASSISTANT['CONSORTIUM']['ssid'])) . " ";
117
            }
118
            $out .= '<strong>' . join('</strong>, <strong>', array_diff(array_keys($this->attributes['internal:SSID']), CONFIG_CONFASSISTANT['CONSORTIUM']['ssid'])) . '</strong>';
119
            $out .= "<p>";
120
        }
121
// TODO - change this below
122
        if ($this->selectedEapObject->isClientCertRequired()) {
123
            $out .= sprintf(_("In order to connect to the network you will need an a personal certificate in the form of a p12 file. You should obtain this certificate from your %s. Consult the support page to find out how this certificate can be obtained. Such certificate files are password protected. You should have both the file and the password available during the installation process."), $this->nomenclature_inst);
124
            return($out);
125
        }
126
        // not EAP-TLS
127
        $out .= sprintf(_("In order to connect to the network you will need an account from your %s. You should consult the support page to find out how this account can be obtained. It is very likely that your account is already activated."), $this->nomenclature_inst);
128
129
        if (!$this->useGeantLink && $this->selectedEap['OUTER'] == \core\common\EAP::TTLS) {
130
            $out .= "<p>";
131
            $out .= _("When you are connecting to the network for the first time, Windows will pop up a login box, where you should enter your user name and password. This information will be saved so that you will reconnect to the network automatically each time you are in the range.");
132
            if ($ssidCount > 1) {
133
                $out .= "<p>";
134
                $out .= _("You will be required to enter the same credentials for each of the configured notworks:") . " ";
135
                $out .= '<strong>' . join('</strong>, <strong>', array_keys($this->attributes['internal:SSID'])) . '</strong>';
136
            }
137
        }
138
        return($out);
139
    }    
140
    
141
    private function scaleLogo($imagePath, $maxSize) {
142
        $imageObject = new \Imagick($imagePath);
143
        $imageSize = $imageObject->getImageGeometry();
144
        $imageMax = max($imageSize);
145
        $this->loggerInstance->debug(5, "Logo size: ");
146
        $this->loggerInstance->debug(5, $imageSize);
147
        $this->loggerInstance->debug(5, "max=$imageMax\n");
148
// resize logo if necessary
149
        if ($imageMax > $maxSize) {
150
            if ($imageMax == $imageSize['width']) {
151
                $imageObject->scaleImage($maxSize, 0);
152
            } else {
153
                $imageObject->scaleImage(0, $maxSize);
154
            }
155
        }
156
        $imageSize = $imageObject->getImageGeometry();
157
        $this->background['freeHeight'] -= $imageSize['height'];
158
        return($imageObject);
159
    }
160
161
    protected function combineLogo($logos = NULL, $fedLogo = NULL) {
162
        // maximum size to which we want to resize the logos
163
        
164
        $maxSize = 120;
165
        // $freeTop is set to how much vertical space we need to leave at the top
166
        // this will depend on the design of the background
167
        $freeTop = 70;
168
        // $freeBottom is set to how much vertical space we need to leave at the bottom
169
        // this will depend on the design of the background
170
        $freeBottom = 30;
171
        
172
        $bgImage = new \Imagick('cat_bg.bmp');
173
        $bgImage->setFormat('BMP3');
174
        $bgImageSize = $bgImage->getImageGeometry();
175
        $logosToPlace = [];
176
        $this->background = [];
177
        $this->background['freeHeight'] = $bgImageSize['height'] - $freeTop - $freeBottom;
178
179
        if (empty($this->attributes['fed:include_logo_installers'])) {
180
            $fedLogo = NULL;
181
        }
182
        if ($fedLogo != NULL) {
183
            $logosToPlace[] = $this->scaleLogo($fedLogo[0]['name'], $maxSize);
184
        }
185
        if ($logos != NULL) {
186
            $logosToPlace[] = $this->scaleLogo($logos[0]['name'], $maxSize);
187
        }
188
189
        $logoCount = count($logosToPlace);
190
        if ($logoCount > 0) {
191
            $voffset = $freeTop;
192
            $freeSpace = (int)round($this->background['freeHeight'] / ($logoCount + 1));
193
            foreach ($logosToPlace as $logo) {
194
                $voffset += $freeSpace;
195
                $logoSize = $logo->getImageGeometry();
196
                $hoffset = (int)round(($bgImageSize['width'] - $logoSize['width']) / 2);
197
                $bgImage->compositeImage($logo, $logo->getImageCompose(), $hoffset, $voffset);
198
                $voffset += $logoSize['height'];
199
                }
200
        }
201
//new image is saved as the background
202
        $bgImage->writeImage('BMP3:cat_bg.bmp');
203
    }
204
205
    protected function signInstaller() {
206
        $fileName = $this->installerBasename . '.exe';
207
        if (!$this->sign) {
208
            rename("installer.exe", $fileName);
209
            return $fileName;
210
        }
211
        // are actually signing
212
        $outputFromSigning = system($this->sign . " installer.exe '$fileName' > /dev/null");
213
        if ($outputFromSigning === FALSE) {
1 ignored issue
show
introduced by
The condition $outputFromSigning === FALSE can never be true.
Loading history...
214
            $this->loggerInstance->debug(2, "Signing the WindowsCommon installer $fileName FAILED!\n");
215
        }
216
        return $fileName;
217
    }
218
219
    protected function compileNSIS() {
220
        if (CONFIG_CONFASSISTANT['NSIS_VERSION'] >= 3) {
221
            $makensis = CONFIG_CONFASSISTANT['PATHS']['makensis'] . " -INPUTCHARSET UTF8";
222
        } else {
223
            $makensis = CONFIG_CONFASSISTANT['PATHS']['makensis'];
224
        }
225
        $command = $makensis . ' -V4 cat.NSI > nsis.log 2>&1';
226
        system($command);
227
        $this->loggerInstance->debug(4, "compileNSIS:$command\n");
228
    }
229
230
    private function getSupport($attr, $type) {
231
        $supportString = [
232
            'email' => 'SUPPORT',
233
            'url' => 'URL',
234
        ];
235
        $s = "support_" . $type . "_substitute";
236
        $substitute = $this->translateString($this->$s, $this->codePage);
237
        $returnValue = !empty($attr['support:' . $type][0]) ? $attr['support:' .  $type][0] : $substitute;
238
        return('!define ' . $supportString[$type] . ' "' . $returnValue . '"' . "\n");
239
    }
240
    
241
    
242
    protected function writeNsisDefines($attr) {
243
        $fcontents = "\n" . '!define NSIS_MAJOR_VERSION ' . CONFIG_CONFASSISTANT['NSIS_VERSION'];
244
        if ($attr['internal:profile_count'][0] > 1) {
245
            $fcontents .= "\n" . '!define USER_GROUP "' . $this->translateString(str_replace('"', '$\\"', $attr['profile:name'][0]), $this->codePage) . '"
246
';
247
        }
248
        $fcontents .=  '
249
Caption "' . $this->translateString(sprintf(WindowsCommon::sprint_nsi(_("%s installer for %s")), CONFIG_CONFASSISTANT['CONSORTIUM']['display_name'], $attr['general:instname'][0]), $this->codePage) . '"
250
!define APPLICATION "' . $this->translateString(sprintf(WindowsCommon::sprint_nsi(_("%s installer for %s")), CONFIG_CONFASSISTANT['CONSORTIUM']['display_name'], $attr['general:instname'][0]), $this->codePage) . '"
251
!define VERSION "' . \core\CAT::VERSION_MAJOR . '.' . \core\CAT::VERSION_MINOR . '"
252
!define INSTALLER_NAME "installer.exe"
253
!define LANG "' . $this->lang . '"
254
!define LOCALE "' . preg_replace('/\..*$/', '', CONFIG['LANGUAGES'][$this->languageInstance->getLang()]['locale']) . '"
255
;--------------------------------
256
!define ORGANISATION "' . $this->translateString($attr['general:instname'][0], $this->codePage) . '"
257
';
258
        $fcontents .= $this->getSupport($attr, 'email');
259
        $fcontents .= $this->getSupport($attr, 'url');                
260
        if (\core\common\Entity::getAttributeValue($attr, 'media:wired', 0) == 'on') {
261
            $fcontents .= '!define WIRED
262
        ';
263
        }
264
        $fcontents .= '!define PROVIDERID "urn:UUID:' . $this->deviceUUID . '"
265
';
266
        if (!empty($attr['internal:realm'][0])) {
267
            $fcontents .= '!define REALM "' . $attr['internal:realm'][0] . '"
268
';
269
        }
270
        if(!empty($attr['internal:hint_userinput_suffix'][0]) && $attr['internal:hint_userinput_suffix'][0] == 1) {
271
            $fcontents .= '!define HINT_USER_INPUT "' . $attr['internal:hint_userinput_suffix'][0] . '"
272
';
273
        }
274
        if(!empty($attr['internal:verify_userinput_suffix'][0]) && $attr['internal:verify_userinput_suffix'][0] == 1) {
275
            $fcontents .= '!define VERIFY_USER_REALM_INPUT "' . $attr['internal:verify_userinput_suffix'][0] . '"
276
';
277
        }
278
        $fcontents .= $this->msInfoFile($attr);
279
        return($fcontents);
280
           
281
    }
282
    
283
    protected function msInfoFile($attr) {
284
        $out = '';
285
        if (isset($attr['support:info_file'])) {
286
            $out .= '!define EXTERNAL_INFO "';
287
//  $this->loggerInstance->debug(4,"Info file type ".$attr['support:info_file'][0]['mime']."\n");
288
            if ($attr['internal:info_file'][0]['mime'] == 'rtf') {
289
                $out = '!define LICENSE_FILE "' . $attr['internal:info_file'][0]['name'];
290
            } elseif ($attr['internal:info_file'][0]['mime'] == 'txt') {
291
                $infoFile = file_get_contents($attr['internal:info_file'][0]['name']);
292
                if ($infoFile === FALSE) {
1 ignored issue
show
introduced by
The condition $infoFile === FALSE can never be true.
Loading history...
293
                    throw new Exception("We were told this file exists. Failing to read it is not really possible.");
294
                }
295
                if (CONFIG_CONFASSISTANT['NSIS_VERSION'] >= 3) {
296
                    $infoFileConverted = $infoFile;
297
                } else {
298
                    $infoFileConverted = iconv('UTF-8', $this->codePage . '//TRANSLIT', $infoFile);
299
                }
300
                if ($infoFileConverted !== FALSE && strlen($infoFileConverted) > 0) {
301
                    file_put_contents('info_f.txt', $infoFileConverted);
302
                    $out = '!define LICENSE_FILE " info_f.txt';
303
                }
304
            } else {
305
                $out = '!define EXTERNAL_INFO "' . $attr['internal:info_file'][0]['name'];
306
            }
307
308
            $out .= "\"\n";
309
        }
310
        $this->loggerInstance->debug(4, "Info file returned: $out");
311
        return $out;
312
    }
313
314
    protected function writeAdditionalDeletes($profiles) {
315
        if (count($profiles) == 0) {
316
            return;
317
        }
318
        $fileHandle = fopen('profiles.nsh', 'a');
319
        if ($fileHandle === FALSE) {
320
            throw new Exception("Unable to open possibly pre-existing profiles.nsh to append additional deletes.");
321
        }
322
        fwrite($fileHandle, "!define AdditionalDeletes\n");
323
        foreach ($profiles as $profile) {
324
            fwrite($fileHandle, "!insertmacro define_delete_profile \"$profile\"\n");
325
        }
326
        fclose($fileHandle);
327
    }
328
329
    protected function writeClientP12File() {
330
        if (!is_array($this->clientCert)) {
331
            throw new Exception("the client block was called but there is no client certificate!");
332
        }
333
        file_put_contents('SB_cert.p12', $this->clientCert["certdata"]);
334
    }
335
336
    protected function writeTlsUserProfile() {
337
        
338
    }
339
340
    public $LANGS = [
341
        'fr' => ['nsis' => "French", 'cp' => '1252'],
342
        'de' => ['nsis' => "German", 'cp' => '1252'],
343
        'es' => ['nsis' => "SpanishInternational", 'cp' => '1252'],
344
        'it' => ['nsis' => "Italian", 'cp' => '1252'],
345
        'nl' => ['nsis' => "Dutch", 'cp' => '1252'],
346
        'sv' => ['nsis' => "Swedish", 'cp' => '1252'],
347
        'fi' => ['nsis' => "Finnish", 'cp' => '1252'],
348
        'pl' => ['nsis' => "Polish", 'cp' => '1250'],
349
        'ca' => ['nsis' => "Catalan", 'cp' => '1252'],
350
        'sr' => ['nsis' => "SerbianLatin", 'cp' => '1250'],
351
        'hr' => ['nsis' => "Croatian", 'cp' => '1250'],
352
        'sl' => ['nsis' => "Slovenian", 'cp' => '1250'],
353
        'da' => ['nsis' => "Danish", 'cp' => '1252'],
354
        'nb' => ['nsis' => "Norwegian", 'cp' => '1252'],
355
        'nn' => ['nsis' => "NorwegianNynorsk", 'cp' => '1252'],
356
        'el' => ['nsis' => "Greek", 'cp' => '1253'],
357
        'ru' => ['nsis' => "Russian", 'cp' => '1251'],
358
        'pt' => ['nsis' => "Portuguese", 'cp' => '1252'],
359
        'uk' => ['nsis' => "Ukrainian", 'cp' => '1251'],
360
        'cs' => ['nsis' => "Czech", 'cp' => '1250'],
361
        'sk' => ['nsis' => "Slovak", 'cp' => '1250'],
362
        'bg' => ['nsis' => "Bulgarian", 'cp' => '1251'],
363
        'hu' => ['nsis' => "Hungarian", 'cp' => '1250'],
364
        'ro' => ['nsis' => "Romanian", 'cp' => '1250'],
365
        'lv' => ['nsis' => "Latvian", 'cp' => '1257'],
366
        'mk' => ['nsis' => "Macedonian", 'cp' => '1251'],
367
        'et' => ['nsis' => "Estonian", 'cp' => '1257'],
368
        'tr' => ['nsis' => "Turkish", 'cp' => '1254'],
369
        'lt' => ['nsis' => "Lithuanian", 'cp' => '1257'],
370
        'ar' => ['nsis' => "Arabic", 'cp' => '1256'],
371
        'he' => ['nsis' => "Hebrew", 'cp' => '1255'],
372
        'id' => ['nsis' => "Indonesian", 'cp' => '1252'],
373
        'mn' => ['nsis' => "Mongolian", 'cp' => '1251'],
374
        'sq' => ['nsis' => "Albanian", 'cp' => '1252'],
375
        'br' => ['nsis' => "Breton", 'cp' => '1252'],
376
        'be' => ['nsis' => "Belarusian", 'cp' => '1251'],
377
        'is' => ['nsis' => "Icelandic", 'cp' => '1252'],
378
        'ms' => ['nsis' => "Malay", 'cp' => '1252'],
379
        'bs' => ['nsis' => "Bosnian", 'cp' => '1250'],
380
        'ga' => ['nsis' => "Irish", 'cp' => '1250'],
381
        'uz' => ['nsis' => "Uzbek", 'cp' => '1251'],
382
        'gl' => ['nsis' => "Galician", 'cp' => '1252'],
383
        'af' => ['nsis' => "Afrikaans", 'cp' => '1252'],
384
        'ast' => ['nsis' => "Asturian", 'cp' => '1252'],
385
    ];
386
    public $codePage;
387
    public $lang;
388
    public $useGeantLink;
389
    private $background;
390
391
}
392