Passed
Push — master ( 225775...e68838 )
by Stefan
03:49
created

mobileconfigSuperclass::networkBlock()   C

Complexity

Conditions 7
Paths 19

Size

Total Lines 68
Code Lines 50

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 68
rs 6.9654
c 0
b 0
f 0
cc 7
eloc 50
nc 19
nop 2

How to fix   Long Method   

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
 * Copyright 2011-2017 DANTE Ltd. and GÉANT on behalf of the GN3, GN3+, GN4-1 
6
 * and GN4-2 consortia
7
 *
8
 * License: see the web/copyright.php file in the file structure
9
 * ******************************************************************************
10
 */
11
12
/**
13
 * This file contains the installer for iOS devices and Apple 10.7 Lion
14
 *
15
 *
16
 * @author Stefan Winter <[email protected]>
17
 * @package Developer
18
 */
19
20
namespace devices\apple_mobileconfig;
21
22
use \Exception;
23
24
/**
25
 * This is the main implementation class of the module
26
 *
27
 * The class should only define one public method: writeInstaller.
28
 *
29
 * All other methods and properties should be private. This example sets zipInstaller method to protected, so that it can be seen in the documentation.
30
 *
31
 * @package Developer
32
 */
33
abstract class mobileconfigSuperclass extends \core\DeviceConfig {
34
35
    private $instName;
36
    private $profileName;
37
    private $massagedInst;
38
    private $massagedProfile;
39
    private $massagedCountry;
40
    private $massagedConsortium;
41
    private $lang;
42
    static private $iPhonePayloadPrefix = "org.1x-config";
43
    private $clientCertUUID;
44
45
    public function __construct() {
46
        parent::__construct();
47
        // that's what all variants support. Sub-classes can change it.
48
        $this->setSupportedEapMethods([\core\common\EAP::EAPTYPE_PEAP_MSCHAP2, \core\common\EAP::EAPTYPE_TTLS_PAP, \core\common\EAP::EAPTYPE_TTLS_MSCHAP2, \core\common\EAP::EAPTYPE_SILVERBULLET]);
49
        $this->specialities['internal:verify_userinput_suffix'] = _("It is not possible to actively verify the user input for suffix match; but if there is no 'Terms of Use' configured, the installer will display a corresponding hint to the user instead.");
50
    }
51
52
    private function massageName($input) {
53
        return htmlspecialchars(strtolower(iconv("UTF-8", "US-ASCII//TRANSLIT", preg_replace(['/ /', '/\//'], '_', $input))), ENT_XML1, 'UTF-8');
54
    }
55
56
    private function generalPayload() {
57
        $tagline = sprintf(_("Network configuration profile '%s' of '%s' - provided by %s"), htmlspecialchars($this->profileName, ENT_XML1, 'UTF-8'), htmlspecialchars($this->instName, ENT_XML1, 'UTF-8'), CONFIG_CONFASSISTANT['CONSORTIUM']['display_name']);
58
59
        $eapType = $this->selectedEap;
60
        // simpler message for silverbullet
61
        if ($eapType['INNER'] == \core\common\EAP::NE_SILVERBULLET) {
62
            $tagline = sprintf(_("%s configuration for IdP '%s' - provided by %s"), \core\ProfileSilverbullet::PRODUCTNAME, htmlspecialchars($this->instName, ENT_XML1, 'UTF-8'), CONFIG_CONFASSISTANT['CONSORTIUM']['display_name']);
63
        }
64
65
        return "
66
      <key>PayloadDescription</key>
67
         <string>$tagline</string>
68
      <key>PayloadDisplayName</key>
69
         <string>" . CONFIG_CONFASSISTANT['CONSORTIUM']['display_name'] . "</string>
70
      <key>PayloadIdentifier</key>
71
         <string>" . self::$iPhonePayloadPrefix . ".$this->massagedConsortium.$this->massagedCountry.$this->massagedInst.$this->massagedProfile.$this->lang</string>
72
      <key>PayloadOrganization</key>
73
         <string>" . htmlspecialchars(iconv("UTF-8", "UTF-8//IGNORE", $this->attributes['general:instname'][0]), ENT_XML1, 'UTF-8') . ( $this->attributes['internal:profile_count'][0] > 1 ? " (" . htmlspecialchars(iconv("UTF-8", "UTF-8//IGNORE", $this->attributes['profile:name'][0]), ENT_XML1, 'UTF-8') . ")" : "") . "</string>
74
      <key>PayloadType</key>
75
         <string>Configuration</string>
76
      <key>PayloadUUID</key>
77
         <string>" . \core\common\Entity::uuid('', self::$iPhonePayloadPrefix . $this->massagedConsortium . $this->massagedCountry . $this->massagedInst . $this->massagedProfile) . "</string>
78
      <key>PayloadVersion</key>
79
         <integer>1</integer>";
80
    }
81
82
    const FILE_START = "<?xml version=\"1.0\" encoding=\"utf-8\"?>
83
<!DOCTYPE plist PUBLIC \"-//Apple Computer//DTD PLIST 1.0//EN\"
84
\"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">
85
<plist version=\"1.0\">
86
<dict>";
87
    const FILE_END = "</dict></plist>";
88
    const BUFFER_CONSENT_PRE = "
89
      <key>ConsentText</key>
90
         <dict>
91
            <key>default</key>
92
               <string>";
93
    const BUFFER_CONSENT_POST = "</string>
94
         </dict>
95
         ";
96
97
    protected function consentBlock() {
98
        if (isset($this->attributes['support:info_file'])) {
99
            return mobileconfigSuperclass::BUFFER_CONSENT_PRE . htmlspecialchars(iconv("UTF-8", "UTF-8//TRANSLIT", $this->attributes['support:info_file'][0]), ENT_XML1, 'UTF-8') . mobileconfigSuperclass::BUFFER_CONSENT_POST;
100
        }
101
        if (isset($this->attributes['internal:verify_userinput_suffix'])) {
102
            if (isset($this->attributes['internal:realm'])) {
103
                return mobileconfigSuperclass::BUFFER_CONSENT_PRE . sprintf(_("Important Notice: your username must end with @%s!"), $this->attributes['internal:realm'][0]) . mobileconfigSuperclass::BUFFER_CONSENT_POST;
104
            }
105
            return mobileconfigSuperclass::BUFFER_CONSENT_PRE . _("Important Notice: your username MUST be in the form of xxx@yyy where the yyy is a common suffix identifying your Identity Provider. Please find out what to use there and enter the username in the correct format.") . mobileconfigSuperclass::BUFFER_CONSENT_POST;
106
        }
107
        return "";
108
    }
109
110
    /**
111
     * prepare a zip archive containing files and settings which normally would be used inside the module to produce an installer
112
     *
113
     */
114
    public function writeInstaller() {
115
        /** run innitial setup
116
          this will:
117
          - create the temporary directory and save its path as $this->FPATH
118
          - process the CA certificates and store results in $this->attributes['internal:CAs'][0]
119
          $this->attributes['internal:CAs'][0] is an array of processed CA certificates
120
          a processed certifincate is an array
121
          'pem' points to pem feromat certificate
122
          'der' points to der format certificate
123
          'md5' points to md5 fingerprint
124
          'sha1' points to sha1 fingerprint
125
          'name' points to the certificate subject
126
          'root' can be 1 for self-signed certificate or 0 otherwise
127
128
          - save the info_file (if exists) and put the name in $this->attributes['internal:info_file_name'][0]
129
         */
130
        $dom = textdomain(NULL);
131
        textdomain("devices");
132
133
        $this->loggerInstance->debug(4, "mobileconfig Module Installer start\n");
134
135
        // remove spaces and slashes (filename!), make sure it's simple ASCII only, then lowercase it
136
        // also escape htmlspecialchars
137
        // not all names and profiles have a name, so be prepared
138
139
        $this->loggerInstance->debug(5, "List of available attributes: " . var_export($this->attributes, TRUE));
140
141
        $this->instName = $this->attributes['general:instname'][0] ?? sprintf(_("Unnamed %s"), $this->nomenclature_inst);
142
        $this->profileName = $this->attributes['profile:name'][0] ?? _("Unnamed Profile");
143
144
        $this->massagedInst = $this->massageName($this->instName);
145
        $this->massagedProfile = $this->massageName($this->profileName);
146
        $this->massagedCountry = $this->massageName($this->attributes['internal:country'][0]);
147
        $this->massagedConsortium = $this->massageName(CONFIG_CONFASSISTANT['CONSORTIUM']['name']);
148
        $this->lang = preg_replace('/\..+/', '', setlocale(LC_ALL, "0"));
149
150
        $eapType = $this->selectedEap;
151
152
        $outputXml = self::FILE_START;
153
        $outputXml .= "<key>PayloadContent</key>
154
         <array>";
155
156
        // if we are in silverbullet, we will need a whole own block for the client credential
157
        // and also for the profile expiry
158
159
        $this->clientCertUUID = NULL;
160
        if ($eapType['INNER'] == \core\common\EAP::NE_SILVERBULLET) {
161
            $blockinfo = $this->clientP12Block();
162
            $outputXml .= $blockinfo['block'];
163
            $this->clientCertUUID = $blockinfo['UUID'];
164
        }
165
166
        $outputXml .= $this->allCA();
167
168
        $outputXml .= $this->allNetworkBlocks();
169
170
        $outputXml .= "</array>";
171
        $outputXml .= $this->generalPayload();
172
        $outputXml .= $this->consentBlock();
173
174
        if ($eapType['INNER'] == \core\common\EAP::NE_SILVERBULLET) {
175
            $outputXml .= $this->expiryBlock();
176
        }
177
        $outputXml .= self::FILE_END;
178
179
        file_put_contents('installer_profile', $outputXml);
180
181
        textdomain($dom);
182
183
        $fileName = $this->installerBasename . '.mobileconfig';
184
185
        if (!$this->sign) {
186
            rename("installer_profile", $fileName);
187
            return $fileName;
188
        }
189
        // still here? Then we are signing.
190
        $signing = system($this->sign . " installer_profile '$fileName' > /dev/null");
191
        if ($signing === FALSE) {
1 ignored issue
show
introduced by
The condition $signing === FALSE can never be true.
Loading history...
192
            $this->loggerInstance->debug(2, "Signing the mobileconfig installer $fileName FAILED!\n");
193
        }
194
        return $fileName;
195
    }
196
197
    public function writeDeviceInfo() {
198
        $ssidCount = count($this->attributes['internal:SSID']);
199
        $certCount = count($this->attributes['internal:CAs'][0]);
200
        $out = "<p>" . _("For best results, please use the built-in browser (Safari) to open the configuration file.") . "</p>";
201
        $out .= "<p>";
202
        $out .= _("The profile will install itself after you click (or tap) the button. You will be asked for confirmation/input at several points:");
203
        $out .= "<ul>";
204
        $out .= "<li>" . _("to install the profile") . "</li>";
205
        $out .= "<li>" . ngettext("to accept the server certificate authority", "to accept the server certificate authorities", $certCount);
206
        if ($certCount > 1) {
207
            $out .= " " . sprintf(_("(%d times)"), $certCount);
208
        }
209
        $out .= "</li>";
210
        $out .= "<li>" . sprintf(_("to enter the username and password of your %s"), $this->nomenclature_inst);
211
        if ($ssidCount > 1) {
212
            $out .= " " . sprintf(_("(%d times each, because %s is installed for %d SSIDs)"), $ssidCount, CONFIG_CONFASSISTANT['CONSORTIUM']['display_name'], $ssidCount);
213
        }
214
        $out .= "</li>";
215
        $out .= "</ul>";
216
        $out .= "</p>";
217
        return $out;
218
    }
219
220
    private function listCAUuids() {
221
        $retval = [];
222
        foreach ($this->attributes['internal:CAs'][0] as $ca) {
223
            $retval[] = $ca['uuid'];
224
        }
225
        return $retval;
226
    }
227
228
    private function passPointBlock($consortiumOi) {
229
        $retval = "
230
               <key>IsHotspot</key>
231
               <true/>
232
               <key>ServiceProviderRoamingEnabled</key>
233
               <true/>
234
               <key>DisplayedOperatorName</key>
235
               <string>" . CONFIG_CONFASSISTANT['CONSORTIUM']['display_name'] . " via Passpoint</string>";
236
        // if we don't know the realm, omit the entire DomainName key
237
        if (isset($this->attributes['internal:realm'])) {
238
            $retval .= "<key>DomainName</key>
239
               <string>";
240
            $retval .= $this->attributes['internal:realm'][0];
241
            $retval .= "</string>
242
                ";
243
        }
244
        $retval .= "                <key>RoamingConsortiumOIs</key>
245
                <array>";
246
        foreach ($consortiumOi as $oiValue) {
247
            $retval .= "<string>$oiValue</string>";
248
        }
249
        $retval .= "</array>";
250
        // this is an undocmented value found on the net. Does it do something useful?
251
        $retval .= "<key>_UsingHotspot20</key>
252
                <true/>
253
                ";
254
        // do we need to set NAIRealmName ? In Rel 1, probably yes, in Rel 2, 
255
        // no because ConsortiumOI is enough.
256
        // but which release is OS X doing? And what should we fill in, given
257
        // that we have thousands of realms? Try just eduroam.org
258
        if (CONFIG_CONFASSISTANT['CONSORTIUM']['name'] == "eduroam") {
259
            $retval .= "<key>NAIRealmNames</key>
260
                <array>
261
                    <string>eduroam.org</string>
262
                </array>";
263
        }
264
        return $retval;
265
    }
266
267
    private $serial;
268
    private $removeSerial;
269
    private $caSerial;
270
271
    private function eapBlock($eapType) {
272
        $realm = $this->determineOuterIdString();
273
        $retval = "<key>EAPClientConfiguration</key>
274
                  <dict>
275
                      <key>AcceptEAPTypes</key>
276
                         <array>
277
                            <integer>" . $eapType['OUTER'] . "</integer>
278
                         </array>
279
                      <key>EAPFASTProvisionPAC</key>
280
                            <true />
281
                      <key>EAPFASTUsePAC</key>
282
                            <true />
283
                      <key>EAPFastProvisionPACAnonymously</key>
284
                            <false />
285
                      <key>OneTimeUserPassword</key>
286
                            <false />
287
";
288
        if ($realm !== 0) {
1 ignored issue
show
introduced by
The condition $realm !== 0 can never be false.
Loading history...
289
            $retval .= "<key>OuterIdentity</key>
290
                                    <string>" . htmlspecialchars($realm, ENT_XML1, 'UTF-8') . "</string>
291
";
292
        }
293
        $retval .= "<key>PayloadCertificateAnchorUUID</key>
294
                         <array>";
295
        foreach ($this->listCAUuids() as $uuid) {
296
            $retval .= "
297
<string>$uuid</string>";
298
        }
299
        $retval .= "
300
                         </array>
301
                      <key>TLSAllowTrustExceptions</key>
302
                         <false />
303
                      <key>TLSTrustedServerNames</key>
304
                         <array>";
305
        foreach ($this->attributes['eap:server_name'] as $commonName) {
306
            $retval .= "
307
<string>$commonName</string>";
308
        }
309
        $retval .= "
310
                         </array>";
311
        if ($eapType['INNER'] == \core\common\EAP::NE_SILVERBULLET) {
312
            $retval .= "<key>UserName</key><string>" . $this->clientCert["certObject"]->username . "</string>";
313
        }
314
        $retval .= "
315
                      <key>TTLSInnerAuthentication</key>
316
                         <string>" . ($eapType['INNER'] == \core\common\EAP::NONE ? "PAP" : "MSCHAPv2") . "</string>
317
                   </dict>";
318
        return $retval;
319
    }
320
321
    protected function proxySettings() {
322
        $buffer = "<key>ProxyType</key>";
323
        if (isset($this->attributes['media:force_proxy_http'])) {
324
            // find the port delimiter. In case of IPv6, there are multiple ':' 
325
            // characters, so we have to find the LAST one
326
            $serverAndPort = explode(':', strrev($this->attributes['media:force_proxy_http'][0]), 2);
327
            // characters are still reversed, invert on use!
328
            $buffer .= "<string>Manual</string>
329
                  <key>ProxyServer</key>
330
                  <string>" . strrev($serverAndPort[1]) . "</string>
331
                  <key>ProxyServerPort</key>
332
                  <integer>" . strrev($serverAndPort[0]) . "</integer>
333
                  <key>ProxyPACFallbackAllowed</key>
334
                  <false/>";
335
        } else {
336
            $buffer .= "<string>Auto</string>
337
                  <key>ProxyPACFallbackAllowed</key>
338
                  <true/>";
339
        }
340
        return $buffer;
341
    }
342
343
    private function networkBlock($blocktype, $toBeConfigured) {
344
        switch ($blocktype) {
345
            case mobileconfigSuperclass::NETWORK_BLOCK_TYPE_SSID:
346
                $escapedSSID = htmlspecialchars($toBeConfigured, ENT_XML1, 'UTF-8');
347
                $eapType = $this->selectedEap;
348
                $payloadIdentifier = "wifi." . $this->serial;
349
                $payloadShortName = sprintf(_("SSID %s"), $escapedSSID);
350
                $payloadName = sprintf(_("%s configuration for network name %s"), CONFIG_CONFASSISTANT['CONSORTIUM']['display_name'], $escapedSSID);
351
                $encryptionTypeString = "WPA";
352
                $setupModesString = "";
353
                $wifiNetworkIdentification = "<key>SSID_STR</key>
354
                  <string>$escapedSSID</string>";
355
                break;
356
            case mobileconfigSuperclass::NETWORK_BLOCK_TYPE_WIRED:
357
                $payloadIdentifier = "firstactiveethernet";
358
                $payloadShortName = _("Wired Network");
359
                $payloadName = sprintf(_("%s configuration for wired network"), CONFIG_CONFASSISTANT['CONSORTIUM']['display_name']);
360
                $encryptionTypeString = "any";
361
                $setupModesString = "
362
               <key>SetupModes</key>
363
                  <array>
364
                     <string>System</string>
365
                  </array>";
366
                $wifiNetworkIdentification = "";
367
                break;
368
            case mobileconfigSuperclass::NETWORK_BLOCK_TYPE_CONSORTIUMOIS:
369
                $payloadIdentifier = "hs20";
370
                $payloadShortName = _("Hotspot 2.0 Settings");
371
                $payloadName = sprintf(_("%s Hotspot 2.0 configuration"), CONFIG_CONFASSISTANT['CONSORTIUM']['display_name']);
372
                $encryptionTypeString = "WPA";
373
                $wifiNetworkIdentification = $this->passPointBlock($toBeConfigured);
374
                break;
375
            default:
376
                throw new Exception("This type of network block is unknown!");
377
        }
378
        $retval = "<dict>";
379
        $retval .= $this->eapBlock($eapType);
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $eapType does not seem to be defined for all execution paths leading up to this point.
Loading history...
380
        $retval .= "<key>EncryptionType</key>
381
                  <string>$encryptionTypeString</string>
382
               <key>HIDDEN_NETWORK</key>
383
                  <true />
384
               <key>PayloadDescription</key>
385
                  <string>$payloadName</string>
386
               <key>PayloadDisplayName</key>
387
                  <string>$payloadShortName</string>
388
               <key>PayloadIdentifier</key>
389
                  <string>" . self::$iPhonePayloadPrefix . ".$this->massagedConsortium.$this->massagedCountry.$this->massagedInst.$this->massagedProfile.$this->lang.$payloadIdentifier</string>
390
               <key>PayloadOrganization</key>
391
                  <string>" . $this->massagedConsortium . ".1x-config.org</string>
392
               <key>PayloadType</key>
393
                  <string>com.apple." . ($blocktype == mobileconfigSuperclass::NETWORK_BLOCK_TYPE_WIRED ? "firstactiveethernet" : "wifi") . ".managed</string>";
394
        $retval .= $this->proxySettings();
395
        $retval .= $setupModesString;
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $setupModesString does not seem to be defined for all execution paths leading up to this point.
Loading history...
396
        if ($eapType['INNER'] == \core\common\EAP::NE_SILVERBULLET) {
397
            if ($this->clientCertUUID === NULL) {
398
                throw new Exception("Silverbullet REQUIRES a client certificate and we need to know the UUID!");
399
            }
400
            $retval .= "<key>PayloadCertificateUUID</key>
401
                        <string>$this->clientCertUUID</string>";
402
        }
403
        $retval .= "
404
               <key>PayloadUUID</key>
405
                  <string>" . \core\common\Entity::uuid() . "</string>
406
               <key>PayloadVersion</key>
407
                  <integer>1</integer>
408
                  $wifiNetworkIdentification</dict>";
409
        $this->serial = $this->serial + 1;
410
        return $retval;
411
    }
412
413
    private function removenetworkBlock($ssid) {
414
        $retval = "
415
<dict>
416
	<key>AutoJoin</key>
417
	<false/>
418
	<key>EncryptionType</key>
419
	<string>None</string>
420
	<key>HIDDEN_NETWORK</key>
421
	<false/>
422
	<key>IsHotspot</key>
423
	<false/>
424
	<key>PayloadDescription</key>
425
	<string>" . sprintf(_("This SSID should not be used after bootstrapping %s"), CONFIG_CONFASSISTANT['CONSORTIUM']['display_name']) . "</string>
426
	<key>PayloadDisplayName</key>
427
	<string>" . _("Disabled WiFi network") . "</string>
428
	<key>PayloadIdentifier</key>
429
	<string>" . self::$iPhonePayloadPrefix . ".$this->massagedConsortium.$this->massagedCountry.$this->massagedInst.$this->massagedProfile.$this->lang.wifi.disabled.$this->removeSerial</string>
430
	<key>PayloadType</key>
431
	<string>com.apple.wifi.managed</string>
432
	<key>PayloadUUID</key>
433
	<string>" . \core\common\Entity::uuid() . "</string>
434
	<key>PayloadVersion</key>
435
	<real>1</real>";
436
        $retval .= $this->proxySettings();
437
        $retval .= "<key>SSID_STR</key>
438
	<string>$ssid</string>
439
</dict>
440
";
441
        return $retval;
442
    }
443
444
    const NETWORK_BLOCK_TYPE_SSID = 100;
445
    const NETWORK_BLOCK_TYPE_CONSORTIUMOIS = 101;
446
    const NETWORK_BLOCK_TYPE_WIRED = 102;
447
448
    private function allNetworkBlocks() {
449
        $retval = "";
450
        $this->serial = 0;
451
452
        foreach (array_keys($this->attributes['internal:SSID']) as $ssid) {
453
            $retval .= $this->networkBlock(mobileconfigSuperclass::NETWORK_BLOCK_TYPE_SSID, $ssid);
454
        }
455
        if (isset($this->attributes['media:wired']) && get_class($this) == "Device_mobileconfig_os_x") {
456
            $retval .= $this->networkBlock(mobileconfigSuperclass::NETWORK_BLOCK_TYPE_WIRED, TRUE);
457
        }
458
        if (count($this->attributes['internal:consortia']) > 0) {
459
            $retval .= $this->networkBlock(mobileconfigSuperclass::NETWORK_BLOCK_TYPE_CONSORTIUMOIS, $this->attributes['internal:consortia']);
460
        }
461
        if (isset($this->attributes['media:remove_SSID'])) {
462
            $this->removeSerial = 0;
463
            foreach ($this->attributes['media:remove_SSID'] as $removeSSID) {
464
                $retval .= $this->removenetworkBlock($removeSSID);
465
                $this->removeSerial = $this->removeSerial + 1;
466
            }
467
        }
468
        return $retval;
469
    }
470
471
    private function allCA() {
472
        $retval = "";
473
        $this->caSerial = 0;
474
        foreach ($this->attributes['internal:CAs'][0] as $ca) {
475
            $retval .= $this->caBlob($ca);
476
            $this->caSerial = $this->caSerial + 1;
477
        }
478
        return $retval;
479
    }
480
481
    private function clientP12Block() {
482
        if (!is_array($this->clientCert)) {
483
            throw new Exception("the client block was called but there is no client certificate!");
484
        }
485
        $binaryBlob = $this->clientCert["certdata"];
486
        $mimeBlob = base64_encode($binaryBlob);
487
        $mimeFormatted = chunk_split($mimeBlob, 52, "\r\n");
488
        $payloadUUID = \core\common\Entity::uuid('', $mimeBlob);
489
        return ["block" => "<dict>" .
490
            // we don't include the import password. It's displayed on screen, and should be input by the user.
491
            // <key>Password</key>
492
            //   <string>" . $this->clientCert['password'] . "</string>
493
            "<key>PayloadCertificateFileName</key>
494
                     <string>cert-cli.pfx</string>
495
                  <key>PayloadContent</key>
496
                     <data>
497
$mimeFormatted
498
                     </data>
499
                  <key>PayloadDescription</key>
500
                     <string>MIME Base-64 encoded PKCS#12 Client Certificate</string>
501
                  <key>PayloadDisplayName</key>
502
                     <string>" . _("eduroam user certificate") . "</string>
503
                  <key>PayloadIdentifier</key>
504
                     <string>com.apple.security.pkcs12.$payloadUUID</string>
505
                  <key>PayloadType</key>
506
                     <string>com.apple.security.pkcs12</string>
507
                  <key>PayloadUUID</key>
508
                     <string>$payloadUUID</string>
509
                  <key>PayloadVersion</key>
510
                     <integer>1</integer>
511
                </dict>",
512
            "UUID" => $payloadUUID,];
513
    }
514
515
    private function expiryBlock() {
516
        if (!is_array($this->clientCert)) {
517
            throw new Exception("the expiry block was called but there is no client certificate!");
518
        }
519
        $expiryTime = new \DateTime($this->clientCert['certObject']->expiry);
520
        return "<key>RemovalDate</key>
521
        <date>" . $expiryTime->format("Y-m-d") . "T" . $expiryTime->format("H:i:s") . "Z</date>";
522
    }
523
524
    private function caBlob($ca) {
525
        // cut lines with CERTIFICATE
526
        $stage1 = preg_replace('/-----BEGIN CERTIFICATE-----/', '', $ca['pem']);
527
        $stage2 = preg_replace('/-----END CERTIFICATE-----/', '', $stage1);
528
        $trimmedPem = trim($stage2);
529
530
        $stream = "
531
            <dict>
532
               <key>PayloadCertificateFileName</key>
533
               <string>" . $ca['uuid'] . ".der</string>
534
               <key>PayloadContent</key>
535
               <data>
536
" . $trimmedPem . "</data>
537
               <key>PayloadDescription</key>
538
               <string>" . _("Your Identity Providers Certification Authority") . "</string>
539
               <key>PayloadDisplayName</key>
540
               <string>" . _("Identity Provider's CA") . "</string>
541
               <key>PayloadIdentifier</key>
542
               <string>" . self::$iPhonePayloadPrefix . ".$this->massagedConsortium.$this->massagedCountry.$this->massagedInst.$this->massagedProfile.credential.$this->caSerial</string>
543
               <key>PayloadOrganization</key>
544
               <string>" . $this->massagedConsortium . ".1x-config.org</string>
545
               <key>PayloadType</key>
546
               <string>com.apple.security.root</string>
547
               <key>PayloadUUID</key><string>" . $ca['uuid'] . "</string>
548
               <key>PayloadVersion</key>
549
               <integer>1</integer>
550
            </dict>";
551
552
        return $stream;
553
    }
554
555
}
556