Passed
Push — master ( 1704bc...6b7e8e )
by Tomasz
07:34
created

DeviceLinuxSh::mkSsidList()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 7
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 5
c 0
b 0
f 0
dl 0
loc 7
rs 10
cc 2
nc 2
nop 0
1
<?php
2
/*
3
 * *****************************************************************************
4
  * Contributions to this work were made on behalf of the GÉANT project, a
5
  * project that has received funding from the European Union’s Framework
6
  * Programme 7 under Grant Agreements No. 238875 (GN3) and No. 605243 (GN3plus),
7
  * Horizon 2020 research and innovation programme under Grant Agreements No.
8
  * 691567 (GN4-1) and No. 731122 (GN4-2).
9
  * On behalf of the aforementioned projects, GEANT Association is the sole owner
10
  * of the copyright in all material which was developed by a member of the GÉANT
11
  * project. GÉANT Vereniging (Association) is registered with the Chamber of
12
  * Commerce in Amsterdam with registration number 40535155 and operates in the
13
  * UK as a branch of GÉANT Vereniging.
14
  *
15
  * Registered office: Hoekenrode 3, 1102BR Amsterdam, The Netherlands.
16
  * UK branch address: City House, 126-130 Hills Road, Cambridge CB2 1PQ, UK
17
  *
18
  * License: see the web/copyright.inc.php file in the file structure or
19
  *          <base_url>/copyright.php after deploying the software
20
  */
21
/**
22
 * This file creates Linux installers
23
 *
24
 * @author Tomasz Wolniewicz <[email protected]>
25
 * @author Robert Grätz <[email protected]>
26
 *
27
 * @package ModuleWriting
28
 */
29
namespace devices\linux;
30
use Exception;
31
class DeviceLinuxSh extends \core\DeviceConfig {
32
    /**
33
     * constructor. Sets supported EAP methods.
34
     */
35
    final public function __construct() {
36
        parent::__construct();
37
        $this->setSupportedEapMethods([\core\common\EAP::EAPTYPE_PEAP_MSCHAP2, \core\common\EAP::EAPTYPE_TTLS_PAP, \core\common\EAP::EAPTYPE_TTLS_MSCHAP2, \core\common\EAP::EAPTYPE_TLS, \core\common\EAP::EAPTYPE_SILVERBULLET]);
38
    }
39
40
    /**
41
     * create the actual installer script
42
     *
43
     * @return string filename of the generated installer
44
     * @throws Exception
45
     *
46
     */
47
    public function writeInstaller() {
48
        $installerPath = $this->installerBasename . ".py";
49
        $this->copyFile("eduroam_linux_main.sh", $installerPath);
50
        $installer = fopen($installerPath, "a");
51
        if ($installer === FALSE) {
52
            throw new Exception("Unable to open installer file for writing!");
53
        }
54
        fwrite($installer, "\n\n");
55
        $this->fseek($installer, 0, SEEK_END);
0 ignored issues
show
Bug introduced by
The method fseek() does not exist on devices\linux\DeviceLinuxSh. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

55
        $this->/** @scrutinizer ignore-call */ 
56
               fseek($installer, 0, SEEK_END);

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
56
        $this->writeMessages($installer);
57
        $this->writeConfigVars($installer);
58
        fwrite($installer, "printf -v INIT_INFO \"$INIT_INFO_TMP\" \"$ORGANISATION\" \"$E_MAIL\" \"$URL\"\n");
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $E_MAIL seems to be never defined.
Loading history...
Comprehensibility Best Practice introduced by
The variable $URL seems to be never defined.
Loading history...
Comprehensibility Best Practice introduced by
The variable $INIT_INFO_TMP seems to be never defined.
Loading history...
Comprehensibility Best Practice introduced by
The variable $ORGANISATION seems to be never defined.
Loading history...
59
        fwrite($installer, "printf -v INIT_CONFIRMATION \"$INIT_CONFIRMATION_TMP\" \"$ORGANISATION\"");
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $INIT_CONFIRMATION_TMP seems to be never defined.
Loading history...
60
        fwrite($installer, "main \"$@\"; exit\n");
61
        fclose($installer);
62
        return($installerPath);
63
    }
64
65
    /**
66
     * produces the HTML text to be displayed when clicking on the "help" button
67
     * besides the download button.
68
     *
69
     * @return string
70
     */
71
    public function writeDeviceInfo() {
72
        \core\common\Entity::intoThePotatoes();
73
        $ssidCount = count($this->attributes['internal:SSID']);
74
        $out = '';
75
76
        $out .= sprintf(_("The installer is in the form of a Python script. It will try to configure %s under NetworkManager and if this is either not appropriate for your system or your version of NetworkManager is too old, a wpa_supplicant config file will be created instead."), \config\ConfAssistant::CONSORTIUM['display_name']);
77
        $out .= "<p>";
78
        if ($ssidCount > 1) {
79
            if ($ssidCount > 2) {
80
                $out .= sprintf(_("In addition to <strong>%s</strong> the installer will also configure access to the following networks:"), implode(', ', \config\ConfAssistant::CONSORTIUM['ssid'])) . " ";
81
            } else {
82
                $out .= sprintf(_("In addition to <strong>%s</strong> the installer will also configure access to:"), implode(', ', \config\ConfAssistant::CONSORTIUM['ssid'])) . " ";
83
            }
84
            $iterator = 0;
85
            foreach ($this->attributes['internal:SSID'] as $ssid => $v) {
86
                if (!in_array($ssid, \config\ConfAssistant::CONSORTIUM['ssid'])) {
87
                    if ($iterator > 0) {
88
                        $out .= ", ";
89
                    }
90
                    $iterator++;
91
                    $out .= "<strong>$ssid</strong>";
92
                }
93
            }
94
            $out .= "<p>";
95
        }
96
        $out .= _("The installer will create .cat_installer sub-directory in your home directory and will copy your server certificates there.");
97
        if ($this->selectedEap == \core\common\EAP::EAPTYPE_TLS) {
98
            $out .= _("In order to connect to the network you will need a personal certificate in the form of a p12 file. You should obtain this certificate from your organisation. 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. Your p12 file will also be copied to the .cat_installer directory.");
99
        } elseif ($this->selectedEap != \core\common\EAP::EAPTYPE_SILVERBULLET) {
100
            $out .= _("In order to connect to the network you will need an account from your organisation. 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.");
101
            $out .= "<p>";
102
            $out .= _("You will be requested to enter your account credentials during the installation. This information will be saved so that you will reconnect to the network automatically each time you are in the range.");
103
        }
104
        // nothing to say if we are doing silverbullet.
105
        $out .= "<p>";
106
        \core\common\Entity::outOfThePotatoes();
107
        return $out;
108
    }
109
110
    /**
111
     * writes a line of Python code into the installer script
112
     *
113
     * @param resource $file   the file handle
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 3 found
Loading history...
114
     * @param string   $name   config item to write
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 3 found
Loading history...
115
     * @param string   $text   text to write
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 3 found
Loading history...
116
     * @return void
117
     */
118
    private function writeConfigLine($file, $name, $text) {
119
        $out = $name . '="' . $text . '"\n';
120
        fwrite($file, wordwrap($out, 70, "\n"));
121
    }
122
123
    /**
124
     * localises the user messages and writes them into the file
125
     *
126
     * @param resource $file the file resource of the installer script
127
     * @return void
128
     */
129
    private function writeMessages($file) {
130
        \core\common\Entity::intoThePotatoes();
131
        $messages = [
132
        'QUIT'=> _("Really quit?"),
133
        'USERNAME_PROMPT'=> _("enter your userid"),
134
        'ENTER_PASSWORD' => _("enter password"),
135
        'ENTER_IMPORT_PASSWORD' => _("enter your import password"),
136
        'INCORRECT_PASSWORD' => _("incorrect password"),
137
        'REPEAT_PASSWORD' => _("repeat your password"),
138
        'PASSWORD_DIFFER'=> _("passwords do not match"),
139
        'INSTALLATION_FINISHED' => _("Installation successful"),
140
        'CAT_DIR_EXISTS' => _("Directory {} exists; some of its files may be overwritten."),
141
        'CONTINUE' => _("Continue?"),
142
        'NM_NOT_SUPPORTED' => _("This NetworkManager version is not supported"),
143
        'CERT_ERROR' => _("Certificate file not found, looks like a CAT error"),
144
        'UNKNOWN_VERSION' => _("Unknown version"),
145
        'DBUS_ERROR' => _("DBus connection problem, a sudo might help"),
146
        'YES' => _("Y"),
147
        'NO' => _("N"),
148
        'SAVE_WPA_CONF' => _("NetworkManager configuration failed, but we may generate a wpa_supplicant configuration file if you wish. Be warned that your connection password will be saved in this file as clear text."),
149
        'SAVE_WPA_CONFIRM' => _("Write the file"),
150
        'WRONG_USERNAME_FORMAT' =>_("Error: Your username must be of the form 'xxx@institutionID' e.g. '[email protected]'!"),
151
        'WRONG_REALM' => _("Error: your username must be in the form of 'xxx@{}'. Please enter the username in the correct format."),
152
        'WRONG_REALM_SUFFIX' => _("Error: your username must be in the form of 'xxx@institutionID' and end with '{}'. Please enter the username in the correct format."),
153
        'USER_CERT_MISSING' => _("personal certificate file not found"),
154
        ];
155
        foreach ($messages as $name => $value) {
156
            $this->writeConfigLine($file, $name, $value);
157
        }
158
        \core\common\Entity::outOfThePotatoes();
159
    }
160
161
    /**
162
     * writes configuration variables into the installer script
163
     *
164
     * @param resource $file the file handle
165
     * @return void
166
     */
167
    private function writeConfigVars($file) {
168
        $eapMethod = \core\common\EAP::eapDisplayName($this->selectedEap);
169
        $contacts = $this->mkSupportContacts();
170
        $tou = $this->mkUserConsent();
171
        $outerId = $this->determineOuterIdString();
172
        $config = [
173
            'ORGANISATION' => $this->attributes['general:instname'][0],
174
            'PROFILE_NAME' => $this->attributes['profile:name'][0],
175
            'URL' => $contacts['url'],
176
            'E-MAIL' => $contacts['email'],
177
            'TITLE' => "eduroam CAT",
178
            'SERVER_MATCH' => $this->glueServerNames(),
179
            'EAP_OUTER' => $eapMethod['OUTER'],
180
            'EAP_INNER' => $eapMethod['INNER'],
181
            'INIT_INFO' => $this->mkIntro(),
182
            'INIT_CONFIRMATION' => $this->mkProfileConfirmation(),
183
            // 'sb_user_file' => $this->mkSbUserFile(),
184
        ];
185
186
        $configRaw = [
187
            'SSIDS' => $this->mkSsidList(),
188
            'DEL_SSIDS' => $this->mkDelSsidList(),
189
            'SERVERS' => $this->mkSubjectAltNameList(),
190
        ];
191
192
        if ($this->selectedEap == \core\common\EAP::EAPTYPE_TLS && isset($this->attributes['eap-specific:tls_use_other_id']) && $this->attributes['eap-specific:tls_use_other_id'][0] == 'on') {
193
            $configRaw['USE_OTHER_TLS_ID'] = "True";
194
        }
195
        else {
196
            $configRaw['USE_OTHER_TLS_ID'] = "False";
197
        }
198
199
        if ($outerId !== NULL) {
200
            $configRaw['ANONYMOUS_IDENTITY'] = '"' . $outerId . '"';
201
        }
202
203
        if (!empty($this->attributes['internal:realm'][0])) {
204
           $config['USER_REALM'] = $this->attributes['internal:realm'][0];
205
        }
206
207
        if(!empty($this->attributes['internal:hint_userinput_suffix'][0]) && $this->attributes['internal:hint_userinput_suffix'][0] == 1) {
208
            $configRaw['HINT_USER_INPUT'] = "True";
209
        }
210
211
        if(!empty($this->attributes['internal:verify_userinput_suffix'][0]) && $this->attributes['internal:verify_userinput_suffix'][0] == 1) {
212
            $configRaw['VERIFY_USER_REALM_INPUT'] = "True";
213
        }
214
215
        foreach ($config as $name => $value) {
216
            $this->writeConfigLine($file, $name, $value);
217
        }
218
219
        foreach ($configRaw as $name => $value) {
220
            fwrite($file, $name, $value);
221
        }
222
223
        if ($tou === '') {
224
            fwrite($file, "TOU=\"\"\n");
225
        } else {
226
            fwrite($file, "TOU=\"" . $tou . "\"\n");
227
        }
228
229
        fwrite($file, "CA=\"" . $this->mkCAfile() . "\"\n");
230
        $sbUserFile = $this->mkSbUserFile();
231
        if ($sbUserFile !== '') {
232
            fwrite($file, "SB_USER_FILE=\"" . $sbUserFile . "\"\n");
233
        }
234
    }
235
236
    /**
237
     * coerces the list of EAP server names into a single string
238
     *
239
     * @return string
240
     */
241
    private function glueServerNames() {
242
        $serverList = $this->attributes['eap:server_name'];
243
        if (!$serverList) {
244
            return '';
245
        }
246
        $A0 = array_reverse(explode('.', array_shift($serverList)));
247
        $B = $A0;
248
        foreach ($serverList as $oneServer) {
249
            $A = array_reverse(explode('.', $oneServer));
250
            $B = array_intersect_assoc($A0, $A);
251
            $A0 = $B;
252
        }
253
        return implode('.', array_reverse($B));
254
    }
255
256
    /**
257
     * generates the list of support contacts
258
     *
259
     * @return array
260
     */
261
    private function mkSupportContacts() {
262
        $url = (!empty($this->attributes['support:url'][0])) ? $this->attributes['support:url'][0] : $this->support_url_substitute;
263
        $email = (!empty($this->attributes['support:email'][0])) ? $this->attributes['support:email'][0] : $this->support_email_substitute;
264
        return ['url'=>$url, 'email'=>$email];
265
    }
266
267
    /**
268
     * generates the list of subjectAltNames to configure
269
     *
270
     * @return string
271
     */
272
    private function mkSubjectAltNameList() {
273
        $serverList = $this->attributes['eap:server_name'];
274
        if (!$serverList) {
275
            return '';
276
        }
277
        $out = '';
278
        foreach ($serverList as $oneServer) {
279
            if ($out) {
280
                $out .= ', ';
281
            }
282
            $out .= "'DNS:$oneServer'";
283
        }
284
        return "[" . $out. "]";
285
    }
286
287
    /**
288
     * generates the list of SSIDs to configure
289
     *
290
     * @return string
291
     */
292
    private function mkSsidList() {
293
        $ssids = $this->attributes['internal:SSID'];
294
        $outArray = [];
295
        foreach ($ssids as $ssid => $cipher) {
296
            $outArray[] = "'$ssid'";
297
        }
298
        return '[' . implode(', ', $outArray) . ']';
299
    }
300
301
    /**
302
     * generates the list of SSIDs to delete from the system
303
     *
304
     * @return string
305
     */
306
    private function mkDelSsidList() {
307
        $outArray = [];
308
        $delSSIDs = $this->attributes['internal:remove_SSID'];
309
        foreach ($delSSIDs as $ssid => $cipher) {
310
            if ($cipher == 'DEL') {
311
                $outArray[] = "'$ssid'";
312
            }
313
        }
314
        return '[' . implode(', ', $outArray) . ']';
315
    }
316
317
    /**
318
     * creates a blob containing all CA certificates
319
     *
320
     * @return string
321
     */
322
    private function mkCAfile(){
323
        $out = '';
324
        $cAlist = $this->attributes['internal:CAs'][0];
325
        foreach ($cAlist as $oneCa) {
326
            $out .= $oneCa['pem'];
327
        }
328
        return $out;
329
    }
330
331
    /**
332
     * generates the welcome text
333
     *
334
     * @return string
335
     */
336
    private function mkIntro() {
337
        \core\common\Entity::intoThePotatoes();
338
        $out = _("This installer has been prepared for {0}") . '\n\n' . _("More information and comments:") . '\n\nE-Mail: {1}\nWWW: {2}\n\n' .
339
            _("Installer created with software from the GEANT project.");
340
        \core\common\Entity::outOfThePotatoes();
341
        return $out;
342
    }
343
344
    /**
345
     * generates text for the user consent dialog box, if any
346
     *
347
     * @return string
348
     */
349
    private function mkUserConsent() {
350
        $out = '';
351
        if (isset($this->attributes['support:info_file'])) {
352
            if ($this->attributes['internal:info_file'][0]['mime'] == 'txt') {
353
                $out = $this->attributes['support:info_file'][0];
354
            }
355
        }
356
        return $out;
357
    }
358
359
    /**
360
     * generates the warning that the account will only work for inst members
361
     *
362
     * @return string
363
     */
364
    private function mkProfileConfirmation() {
365
        \core\common\Entity::intoThePotatoes();
366
        if ($this->attributes['internal:profile_count'][0] > 1) {
367
            $out = _("This installer will only work properly if you are a member of {0} and the user group: {1}.");
368
        } else {
369
            $out = _("This installer will only work properly if you are a member of {0}.");
370
        }
371
        \core\common\Entity::outOfThePotatoes();
372
        return $out;
373
    }
374
375
376
    /**
377
     * generates the client certificate data for Silberbullet installers
378
     *
379
     * @return string
380
     */
381
    private function mkSbUserFile() {
382
        if ($this->selectedEap == \core\common\EAP::EAPTYPE_SILVERBULLET) {
383
            return chunk_split(base64_encode($this->clientCert["certdata"]), 64, "\n");
384
        }
385
        return "";
386
    }
387
388
}
389