Passed
Push — master ( cba2d0...6bd2b4 )
by Stefan
03:34
created

mobileconfigSuperclass::networkBlock()   B

Complexity

Conditions 6
Paths 24

Size

Total Lines 65
Code Lines 43

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 65
rs 8.6195
c 0
b 0
f 0
cc 6
eloc 43
nc 24
nop 4

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