Provisioning::Handle()   F
last analyzed

Complexity

Conditions 49
Paths 6404

Size

Total Lines 244
Code Lines 144

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
cc 49
eloc 144
c 2
b 0
f 0
nc 6404
nop 1
dl 0
loc 244
rs 0

How to fix   Long Method    Complexity   

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
 * SPDX-License-Identifier: AGPL-3.0-only
5
 * SPDX-FileCopyrightText: Copyright 2007-2016 Zarafa Deutschland GmbH
6
 * SPDX-FileCopyrightText: Copyright 2020-2022 grommunio GmbH
7
 *
8
 * Provides the PROVISIONING command
9
 */
10
11
class Provisioning extends RequestProcessor {
12
	/**
13
	 * Handles the Provisioning command.
14
	 *
15
	 * @param int $commandCode
16
	 *
17
	 * @return bool
18
	 */
19
	public function Handle($commandCode) {
20
		$status = SYNC_PROVISION_STATUS_SUCCESS;
21
		$policystatus = SYNC_PROVISION_POLICYSTATUS_SUCCESS;
22
23
		$rwstatus = GSync::GetProvisioningManager()->GetProvisioningWipeStatus();
24
		$rwstatusWiped = false;
25
		$deviceInfoSet = false;
26
		$wipeRequest = !($rwstatus < SYNC_PROVISION_RWSTATUS_PENDING);
27
28
		// if this is a regular provisioning require that an authenticated remote user
29
		if (!$wipeRequest) {
30
			SLog::Write(LOGLEVEL_DEBUG, "RequestProcessor::HandleProvision(): Forcing delayed Authentication");
31
			self::Authenticate();
32
		}
33
34
		$phase2 = true;
35
36
		if (!self::$decoder->getElementStartTag(SYNC_PROVISION_PROVISION)) {
37
			return false;
38
		}
39
40
		// Loop through Provision request tags. Possible are:
41
		// - Remote Wipe
42
		// - DeviceInformation
43
		// - Policies
44
		// Each of them should only be once per request.
45
		WBXMLDecoder::ResetInWhile("provisioningMain");
46
		while (WBXMLDecoder::InWhile("provisioningMain")) {
47
			$requestName = "";
48
			if (self::$decoder->getElementStartTag(SYNC_PROVISION_REMOTEWIPE)) {
49
				$requestName = SYNC_PROVISION_REMOTEWIPE;
50
			}
51
			if (self::$decoder->getElementStartTag(SYNC_PROVISION_ACCOUNTONLYREMOTEWIPE)) {
52
				$requestName = SYNC_PROVISION_ACCOUNTONLYREMOTEWIPE;
53
			}
54
			if (self::$decoder->getElementStartTag(SYNC_PROVISION_POLICIES)) {
55
				$requestName = SYNC_PROVISION_POLICIES;
56
			}
57
			if (self::$decoder->getElementStartTag(SYNC_SETTINGS_DEVICEINFORMATION)) {
58
				$requestName = SYNC_SETTINGS_DEVICEINFORMATION;
59
			}
60
61
			if (!$requestName) {
62
				break;
63
			}
64
65
			// set is available for OOF, device password and device information
66
			switch ($requestName) {
67
				case SYNC_PROVISION_REMOTEWIPE:
68
				case SYNC_PROVISION_ACCOUNTONLYREMOTEWIPE:
69
					if (!self::$decoder->getElementStartTag(SYNC_PROVISION_STATUS)) {
70
						return false;
71
					}
72
73
					$instatus = self::$decoder->getElementContent();
0 ignored issues
show
Unused Code introduced by
The assignment to $instatus is dead and can be removed.
Loading history...
74
75
					if (!self::$decoder->getElementEndTag()) {
76
						return false;
77
					}
78
79
					if (!self::$decoder->getElementEndTag()) {
80
						return false;
81
					}
82
83
					$phase2 = false;
84
					$rwstatusWiped = true;
85
					// TODO check - do it after while(1) finished?
86
					break;
87
88
				case SYNC_PROVISION_POLICIES:
89
					if (!self::$decoder->getElementStartTag(SYNC_PROVISION_POLICY)) {
90
						return false;
91
					}
92
93
					if (!self::$decoder->getElementStartTag(SYNC_PROVISION_POLICYTYPE)) {
94
						return false;
95
					}
96
97
					$policytype = self::$decoder->getElementContent();
98
					if ($policytype != 'MS-WAP-Provisioning-XML' && $policytype != 'MS-EAS-Provisioning-WBXML') {
99
						$status = SYNC_PROVISION_STATUS_SERVERERROR;
100
					}
101
					if (!self::$decoder->getElementEndTag()) { // policytype
102
						return false;
103
					}
104
105
					if (self::$decoder->getElementStartTag(SYNC_PROVISION_POLICYKEY)) {
106
						$devpolicykey = self::$decoder->getElementContent();
0 ignored issues
show
Unused Code introduced by
The assignment to $devpolicykey is dead and can be removed.
Loading history...
107
108
						if (!self::$decoder->getElementEndTag()) {
109
							return false;
110
						}
111
112
						if (!self::$decoder->getElementStartTag(SYNC_PROVISION_STATUS)) {
113
							return false;
114
						}
115
116
						$instatus = self::$decoder->getElementContent();
117
118
						if (!self::$decoder->getElementEndTag()) {
119
							return false;
120
						}
121
122
						$phase2 = false;
123
					}
124
125
					if (!self::$decoder->getElementEndTag()) { // policy
126
						return false;
127
					}
128
129
					if (!self::$decoder->getElementEndTag()) { // policies
130
						return false;
131
					}
132
					break;
133
134
				case SYNC_SETTINGS_DEVICEINFORMATION:
135
					// AS14.1 and later clients pass Device Information on the initial Provision request
136
					if (!self::$decoder->getElementStartTag(SYNC_SETTINGS_SET)) {
137
						return false;
138
					}
139
					$deviceInfoSet = true;
140
					$deviceinformation = new SyncDeviceInformation();
141
					$deviceinformation->Decode(self::$decoder);
142
					$deviceinformation->Status = SYNC_SETTINGSSTATUS_SUCCESS;
143
					if (!$wipeRequest) {
144
						// for this operation the device manager is available
145
						GSync::GetDeviceManager()->SaveDeviceInformation($deviceinformation);
146
					}
147
					else {
148
						SLog::Write(LOGLEVEL_DEBUG, "Ignoring incoming device information as WIPE is due.");
149
					}
150
					if (!self::$decoder->getElementEndTag()) {  // SYNC_SETTINGS_SET
151
						return false;
152
					}
153
					if (!self::$decoder->getElementEndTag()) {  // SYNC_SETTINGS_DEVICEINFORMATION
154
						return false;
155
					}
156
					break;
157
158
				default:
159
					// TODO: a special status code needed?
160
					SLog::Write(LOGLEVEL_WARN, sprintf("This property ('%s') is not allowed to be used in a provision request", $requestName));
161
			}
162
		}
163
164
		if (!self::$decoder->getElementEndTag()) { // provision
165
			return false;
166
		}
167
168
		if (PROVISIONING !== true) {
0 ignored issues
show
introduced by
The condition PROVISIONING !== true is always false.
Loading history...
169
			SLog::Write(LOGLEVEL_INFO, "No policies deployed to device");
170
			$policystatus = SYNC_PROVISION_POLICYSTATUS_NOPOLICY;
171
		}
172
173
		self::$encoder->StartWBXML();
174
175
		// just create a temporary key (i.e. iPhone OS4 Beta does not like policykey 0 in response)
176
		$policykey = GSync::GetProvisioningManager()->GenerateProvisioningPolicyKey();
177
178
		self::$encoder->startTag(SYNC_PROVISION_PROVISION);
179
180
		self::$encoder->startTag(SYNC_PROVISION_STATUS);
181
		self::$encoder->content($status);
182
		self::$encoder->endTag();
183
184
		if ($deviceInfoSet) {
185
			self::$encoder->startTag(SYNC_SETTINGS_DEVICEINFORMATION);
186
			self::$encoder->startTag(SYNC_SETTINGS_STATUS);
187
			self::$encoder->content($deviceinformation->Status);
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $deviceinformation does not seem to be defined for all execution paths leading up to this point.
Loading history...
188
			self::$encoder->endTag(); // SYNC_SETTINGS_STATUS
189
			self::$encoder->endTag(); // SYNC_SETTINGS_DEVICEINFORMATION
190
		}
191
192
		self::$encoder->startTag(SYNC_PROVISION_POLICIES);
193
		self::$encoder->startTag(SYNC_PROVISION_POLICY);
194
195
		if (isset($policytype)) {
196
			self::$encoder->startTag(SYNC_PROVISION_POLICYTYPE);
197
			self::$encoder->content($policytype);
198
			self::$encoder->endTag();
199
		}
200
201
		self::$encoder->startTag(SYNC_PROVISION_STATUS);
202
		self::$encoder->content($policystatus);
203
		self::$encoder->endTag();
204
205
		self::$encoder->startTag(SYNC_PROVISION_POLICYKEY);
206
		self::$encoder->content($policykey);
207
		self::$encoder->endTag();
208
209
		if ($phase2 && $policystatus === SYNC_PROVISION_POLICYSTATUS_SUCCESS) {
210
			self::$encoder->startTag(SYNC_PROVISION_DATA);
211
			if ($policytype == 'MS-WAP-Provisioning-XML') {
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $policytype does not seem to be defined for all execution paths leading up to this point.
Loading history...
212
				self::$encoder->content('<wap-provisioningdoc><characteristic type="SecurityPolicy"><parm name="4131" value="1"/><parm name="4133" value="1"/></characteristic></wap-provisioningdoc>');
213
			}
214
			elseif ($policytype == 'MS-EAS-Provisioning-WBXML') {
215
				self::$encoder->startTag(SYNC_PROVISION_EASPROVISIONDOC);
216
217
				// get the provisioning object and log the loaded policy values
218
				$prov = GSync::GetProvisioningManager()->GetProvisioningObject(true);
219
				if (!$prov->Check()) {
220
					throw new FatalException("Invalid policies!");
221
				}
222
223
				GSync::GetProvisioningManager()->SavePolicyHash($prov);
224
				$prov->Encode(self::$encoder);
225
				self::$encoder->endTag();
226
			}
227
			else {
228
				SLog::Write(LOGLEVEL_WARN, "Wrong policy type");
229
				self::$topCollector->AnnounceInformation("Policytype not supported", true);
230
231
				return false;
232
			}
233
			self::$topCollector->AnnounceInformation("Updated provisioning", true);
234
235
			self::$encoder->endTag(); // data
236
		}
237
		self::$encoder->endTag(); // policy
238
		self::$encoder->endTag(); // policies
239
240
		// set the new final policy key in the provisioning manager
241
		if (!$phase2 && !$wipeRequest) {
242
			GSync::GetProvisioningManager()->SetProvisioningPolicyKey($policykey);
243
			self::$topCollector->AnnounceInformation("Policies deployed", true);
244
		}
245
246
		// wipe data if a higher RWSTATUS is requested
247
		if ($rwstatus > SYNC_PROVISION_RWSTATUS_OK && $policystatus === SYNC_PROVISION_POLICYSTATUS_SUCCESS) {
248
			if ($rwstatus <= SYNC_PROVISION_RWSTATUS_WIPED) {
249
				self::$encoder->startTag(SYNC_PROVISION_REMOTEWIPE, false, true);
250
				GSync::GetProvisioningManager()->SetProvisioningWipeStatus(($rwstatusWiped) ? SYNC_PROVISION_RWSTATUS_WIPED : SYNC_PROVISION_RWSTATUS_REQUESTED);
251
				self::$topCollector->AnnounceInformation(sprintf("Remote wipe %s", ($rwstatusWiped) ? "executed" : "requested"), true);
252
			}
253
			else {
254
				self::$encoder->startTag(SYNC_PROVISION_ACCOUNTONLYREMOTEWIPE, false, true);
255
				GSync::GetProvisioningManager()->SetProvisioningWipeStatus(($rwstatusWiped) ? SYNC_PROVISION_RWSTATUS_WIPED_ACCOUNT_ONLY : SYNC_PROVISION_RWSTATUS_REQUESTED_ACCOUNT_ONLY);
256
				self::$topCollector->AnnounceInformation(sprintf("Account Only Remote wipe %s", ($rwstatusWiped) ? "executed" : "requested"), true);
257
			}
258
		}
259
260
		self::$encoder->endTag(); // provision
261
262
		return true;
263
	}
264
}
265