source: trunk/zpush/lib/request/request.php @ 7589

Revision 7589, 19.2 KB checked in by douglas, 11 years ago (diff)

Ticket #3209 - Integrar módulo de sincronização Z-push ao Expresso

Line 
1<?php
2/***********************************************
3* File      :   request.php
4* Project   :   Z-Push
5* Descr     :   This class checks and processes
6*               all incoming data of the request.
7*
8* Created   :   01.10.2007
9*
10* Copyright 2007 - 2012 Zarafa Deutschland GmbH
11*
12* This program is free software: you can redistribute it and/or modify
13* it under the terms of the GNU Affero General Public License, version 3,
14* as published by the Free Software Foundation with the following additional
15* term according to sec. 7:
16*
17* According to sec. 7 of the GNU Affero General Public License, version 3,
18* the terms of the AGPL are supplemented with the following terms:
19*
20* "Zarafa" is a registered trademark of Zarafa B.V.
21* "Z-Push" is a registered trademark of Zarafa Deutschland GmbH
22* The licensing of the Program under the AGPL does not imply a trademark license.
23* Therefore any rights, title and interest in our trademarks remain entirely with us.
24*
25* However, if you propagate an unmodified version of the Program you are
26* allowed to use the term "Z-Push" to indicate that you distribute the Program.
27* Furthermore you may use our trademarks where it is necessary to indicate
28* the intended purpose of a product or service provided you use it in accordance
29* with honest practices in industrial or commercial matters.
30* If you want to propagate modified versions of the Program under the name "Z-Push",
31* you may only do so if you have a written permission by Zarafa Deutschland GmbH
32* (to acquire a permission please contact Zarafa at trademark@zarafa.com).
33*
34* This program is distributed in the hope that it will be useful,
35* but WITHOUT ANY WARRANTY; without even the implied warranty of
36* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
37* GNU Affero General Public License for more details.
38*
39* You should have received a copy of the GNU Affero General Public License
40* along with this program.  If not, see <http://www.gnu.org/licenses/>.
41*
42* Consult LICENSE file for details
43************************************************/
44
45class Request {
46    const UNKNOWN = "unknown";
47
48    /**
49     * self::filterEvilInput() options
50     */
51    const LETTERS_ONLY = 1;
52    const HEX_ONLY = 2;
53    const WORDCHAR_ONLY = 3;
54    const NUMBERS_ONLY = 4;
55    const NUMBERSDOT_ONLY = 5;
56    const HEX_EXTENDED = 6;
57
58    /**
59     * Command parameters for base64 encoded requests (AS >= 12.1)
60     */
61    const COMMANDPARAM_ATTACHMENTNAME = 0;
62    const COMMANDPARAM_COLLECTIONID = 1; //deprecated
63    const COMMANDPARAM_COLLECTIONNAME = 2; //deprecated
64    const COMMANDPARAM_ITEMID = 3;
65    const COMMANDPARAM_LONGID = 4;
66    const COMMANDPARAM_PARENTID = 5; //deprecated
67    const COMMANDPARAM_OCCURRENCE = 6;
68    const COMMANDPARAM_OPTIONS = 7; //used by SmartReply, SmartForward, SendMail, ItemOperations
69    const COMMANDPARAM_USER = 8; //used by any command
70    //possible bitflags for COMMANDPARAM_OPTIONS
71    const COMMANDPARAM_OPTIONS_SAVEINSENT = 0x01;
72    const COMMANDPARAM_OPTIONS_ACCEPTMULTIPART = 0x02;
73
74    static private $input;
75    static private $output;
76    static private $headers;
77    static private $getparameters;
78    static private $command;
79    static private $device;
80    static private $method;
81    static private $remoteAddr;
82    static private $getUser;
83    static private $devid;
84    static private $devtype;
85    static private $authUser;
86    static private $authDomain;
87    static private $authPassword;
88    static private $asProtocolVersion;
89    static private $policykey;
90    static private $useragent;
91    static private $attachmentName;
92    static private $collectionId;
93    static private $itemId;
94    static private $longId; //TODO
95    static private $occurence; //TODO
96    static private $saveInSent;
97    static private $acceptMultipart;
98
99
100    /**
101     * Initializes request data
102     *
103     * @access public
104     * @return
105     */
106    static public function Initialize() {
107        // try to open stdin & stdout
108        self::$input = fopen("php://input", "r");
109        self::$output = fopen("php://output", "w+");
110
111        // Parse the standard GET parameters
112        if(isset($_GET["Cmd"]))
113            self::$command = self::filterEvilInput($_GET["Cmd"], self::LETTERS_ONLY);
114
115        // getUser is unfiltered, as everything is allowed.. even "/", "\" or ".."
116        if(isset($_GET["User"]))
117            self::$getUser = strtolower($_GET["User"]);
118        if(isset($_GET["DeviceId"]))
119            self::$devid = self::filterEvilInput($_GET["DeviceId"], self::WORDCHAR_ONLY);
120        if(isset($_GET["DeviceType"]))
121            self::$devtype = self::filterEvilInput($_GET["DeviceType"], self::LETTERS_ONLY);
122        if (isset($_GET["AttachmentName"]))
123            self::$attachmentName = self::filterEvilInput($_GET["AttachmentName"], self::HEX_EXTENDED);
124        if (isset($_GET["CollectionId"]))
125            self::$collectionId = self::filterEvilInput($_GET["CollectionId"], self::HEX_ONLY);
126        if (isset($_GET["ItemId"]))
127            self::$itemId = self::filterEvilInput($_GET["ItemId"], self::HEX_ONLY);
128        if (isset($_GET["SaveInSent"]) && $_GET["SaveInSent"] == "T")
129            self::$saveInSent = true;
130
131        if(isset($_SERVER["REQUEST_METHOD"]))
132            self::$method = self::filterEvilInput($_SERVER["REQUEST_METHOD"], self::LETTERS_ONLY);
133        // TODO check IPv6 addresses
134        if(isset($_SERVER["REMOTE_ADDR"]))
135            self::$remoteAddr = self::filterEvilInput($_SERVER["REMOTE_ADDR"], self::NUMBERSDOT_ONLY);
136
137        // in protocol version > 14 mobile send these inputs as encoded query string
138        if (!isset(self::$command) && !empty($_SERVER['QUERY_STRING']) && Utils::IsBase64String($_SERVER['QUERY_STRING'])) {
139            $query = Utils::DecodeBase64URI($_SERVER['QUERY_STRING']);
140            if (!isset(self::$command) && isset($query['Command']))
141                self::$command = Utils::GetCommandFromCode($query['Command']);
142
143            if (!isset(self::$getUser) && isset($query[self::COMMANDPARAM_USER]))
144                self::$getUser = strtolower($query[self::COMMANDPARAM_USER]);
145
146            if (!isset(self::$devid) && isset($query['DevID']))
147                self::$devid = self::filterEvilInput($query['DevID'], self::WORDCHAR_ONLY);
148
149            if (!isset(self::$devtype) && isset($query['DevType']))
150                self::$devtype = self::filterEvilInput($query['DevType'], self::LETTERS_ONLY);
151
152            if (isset($query['PolKey']))
153                self::$policykey = (int) self::filterEvilInput($query['PolKey'], self::NUMBERS_ONLY);
154
155            if (isset($query['ProtVer']))
156                self::$asProtocolVersion = self::filterEvilInput($query['ProtVer'], self::NUMBERS_ONLY) / 10;
157
158            if (isset($query[self::COMMANDPARAM_ATTACHMENTNAME]))
159                self::$attachmentName = self::filterEvilInput($query[self::COMMANDPARAM_ATTACHMENTNAME], self::HEX_EXTENDED);
160
161            if (isset($query[self::COMMANDPARAM_COLLECTIONID]))
162                self::$collectionId = self::filterEvilInput($query[self::COMMANDPARAM_COLLECTIONID], self::HEX_ONLY);
163
164            if (isset($query[self::COMMANDPARAM_ITEMID]))
165                self::$itemId = self::filterEvilInput($query[self::COMMANDPARAM_ITEMID], self::HEX_ONLY);
166
167            if (isset($query[self::COMMANDPARAM_OPTIONS]) && (ord($query[self::COMMANDPARAM_OPTIONS]) & self::COMMANDPARAM_OPTIONS_SAVEINSENT))
168                self::$saveInSent = true;
169
170            if (isset($query[self::COMMANDPARAM_OPTIONS]) && (ord($query[self::COMMANDPARAM_OPTIONS]) & self::COMMANDPARAM_OPTIONS_ACCEPTMULTIPART))
171                self::$acceptMultipart = true;
172        }
173
174        // in base64 encoded query string user is not necessarily set
175        if (!isset(self::$getUser) && isset($_SERVER['PHP_AUTH_USER']))
176            list(self::$getUser,) = Utils::SplitDomainUser(strtolower($_SERVER['PHP_AUTH_USER']));
177    }
178
179    /**
180     * Reads and processes the request headers
181     *
182     * @access public
183     * @return
184     */
185    static public function ProcessHeaders() {
186        self::$headers = array_change_key_case(apache_request_headers(), CASE_LOWER);
187        self::$useragent = (isset(self::$headers["user-agent"]))? self::$headers["user-agent"] : self::UNKNOWN;
188        if (!isset(self::$asProtocolVersion))
189            self::$asProtocolVersion = (isset(self::$headers["ms-asprotocolversion"]))? self::filterEvilInput(self::$headers["ms-asprotocolversion"], self::NUMBERSDOT_ONLY) : ZPush::GetLatestSupportedASVersion();
190
191        //if policykey is not yet set, try to set it from the header
192        //the policy key might be set in Request::Initialize from the base64 encoded query
193        if (!isset(self::$policykey)) {
194            if (isset(self::$headers["x-ms-policykey"]))
195                self::$policykey = (int) self::filterEvilInput(self::$headers["x-ms-policykey"], self::NUMBERS_ONLY);
196            else
197                self::$policykey = 0;
198        }
199
200        if (!empty($_SERVER['QUERY_STRING']) && Utils::IsBase64String($_SERVER['QUERY_STRING'])) {
201            ZLog::Write(LOGLEVEL_DEBUG, "Using data from base64 encoded query string");
202            if (isset(self::$policykey))
203                self::$headers["x-ms-policykey"] = self::$policykey;
204
205            if (isset(self::$asProtocolVersion))
206                self::$headers["ms-asprotocolversion"] = self::$asProtocolVersion;
207        }
208
209        if (!isset(self::$acceptMultipart) && isset(self::$headers["ms-asacceptmultipart"]) && strtoupper(self::$headers["ms-asacceptmultipart"]) == "T") {
210            self::$acceptMultipart = true;
211        }
212
213        ZLog::Write(LOGLEVEL_DEBUG, sprintf("Request::ProcessHeaders() ASVersion: %s", self::$asProtocolVersion));
214    }
215
216    /**
217     * Reads and parses the HTTP-Basic-Auth data
218     *
219     * @access public
220     * @return boolean      data sent or not
221     */
222    static public function AuthenticationInfo() {
223        // split username & domain if received as one
224        if (isset($_SERVER['PHP_AUTH_USER'])) {
225            list(self::$authUser, self::$authDomain) = Utils::SplitDomainUser($_SERVER['PHP_AUTH_USER']);
226            self::$authPassword = (isset($_SERVER['PHP_AUTH_PW']))?$_SERVER['PHP_AUTH_PW'] : "";
227        }
228        // authUser & authPassword are unfiltered!
229        return (self::$authUser != "" && self::$authPassword != "");
230    }
231
232
233    /**----------------------------------------------------------------------------------------------------------
234     * Getter & Checker
235     */
236
237    /**
238     * Returns the input stream
239     *
240     * @access public
241     * @return handle/boolean      false if not available
242     */
243    static public function GetInputStream() {
244        if (isset(self::$input))
245            return self::$input;
246        else
247            return false;
248    }
249
250    /**
251     * Returns the output stream
252     *
253     * @access public
254     * @return handle/boolean      false if not available
255     */
256    static public function GetOutputStream() {
257        if (isset(self::$output))
258            return self::$output;
259        else
260            return false;
261    }
262
263    /**
264     * Returns the request method
265     *
266     * @access public
267     * @return string
268     */
269    static public function GetMethod() {
270        if (isset(self::$method))
271            return self::$method;
272        else
273            return self::UNKNOWN;
274    }
275
276    /**
277     * Returns the value of the user parameter of the querystring
278     *
279     * @access public
280     * @return string/boolean       false if not available
281     */
282    static public function GetGETUser() {
283        if (isset(self::$getUser))
284            return self::$getUser;
285        else
286            return self::UNKNOWN;
287    }
288
289    /**
290     * Returns the value of the ItemId parameter of the querystring
291     *
292     * @access public
293     * @return string/boolean       false if not available
294     */
295    static public function GetGETItemId() {
296        if (isset(self::$itemId))
297            return self::$itemId;
298        else
299            return false;
300        }
301
302    /**
303     * Returns the value of the CollectionId parameter of the querystring
304     *
305     * @access public
306     * @return string/boolean       false if not available
307     */
308    static public function GetGETCollectionId() {
309        if (isset(self::$collectionId))
310            return self::$collectionId;
311        else
312            return false;
313    }
314
315    /**
316     * Returns if the SaveInSent parameter of the querystring is set
317     *
318     * @access public
319     * @return boolean
320     */
321    static public function GetGETSaveInSent() {
322        if (isset(self::$saveInSent))
323            return self::$saveInSent;
324        else
325            return true;
326    }
327
328    /**
329    * Returns if the AcceptMultipart parameter of the querystring is set
330    *
331    * @access public
332    * @return boolean
333    */
334    static public function GetGETAcceptMultipart() {
335        if (isset(self::$acceptMultipart))
336            return self::$acceptMultipart;
337        else
338            return false;
339    }
340
341    /**
342     * Returns the value of the AttachmentName parameter of the querystring
343     *
344     * @access public
345     * @return string/boolean       false if not available
346     */
347    static public function GetGETAttachmentName() {
348        if (isset(self::$attachmentName))
349            return self::$attachmentName;
350        else
351            return false;
352    }
353
354    /**
355     * Returns the authenticated user
356     *
357     * @access public
358     * @return string/boolean       false if not available
359     */
360    static public function GetAuthUser() {
361        if (isset(self::$authUser))
362            return self::$authUser;
363        else
364            return false;
365    }
366
367    /**
368     * Returns the authenticated domain for the user
369     *
370     * @access public
371     * @return string/boolean       false if not available
372     */
373    static public function GetAuthDomain() {
374        if (isset(self::$authDomain))
375            return self::$authDomain;
376        else
377            return false;
378    }
379
380    /**
381     * Returns the transmitted password
382     *
383     * @access public
384     * @return string/boolean       false if not available
385     */
386    static public function GetAuthPassword() {
387        if (isset(self::$authPassword))
388            return self::$authPassword;
389        else
390            return false;
391    }
392
393    /**
394     * Returns the RemoteAddress
395     *
396     * @access public
397     * @return string
398     */
399    static public function GetRemoteAddr() {
400        if (isset(self::$remoteAddr))
401            return self::$remoteAddr;
402        else
403            return "UNKNOWN";
404    }
405
406    /**
407     * Returns the command to be executed
408     *
409     * @access public
410     * @return string/boolean       false if not available
411     */
412    static public function GetCommand() {
413        if (isset(self::$command))
414            return self::$command;
415        else
416            return false;
417    }
418
419    /**
420     * Returns the command code which is being executed
421     *
422     * @access public
423     * @return string/boolean       false if not available
424     */
425    static public function GetCommandCode() {
426        if (isset(self::$command))
427            return Utils::GetCodeFromCommand(self::$command);
428        else
429            return false;
430    }
431
432    /**
433     * Returns the device id transmitted
434     *
435     * @access public
436     * @return string/boolean       false if not available
437     */
438    static public function GetDeviceID() {
439        if (isset(self::$devid))
440            return self::$devid;
441        else
442            return false;
443    }
444
445    /**
446     * Returns the device type if transmitted
447     *
448     * @access public
449     * @return string/boolean       false if not available
450     */
451    static public function GetDeviceType() {
452        if (isset(self::$devtype))
453            return self::$devtype;
454        else
455            return false;
456    }
457
458    /**
459     * Returns the value of supported AS protocol from the headers
460     *
461     * @access public
462     * @return string/boolean       false if not available
463     */
464    static public function GetProtocolVersion() {
465        if (isset(self::$asProtocolVersion))
466            return self::$asProtocolVersion;
467        else
468            return false;
469    }
470
471    /**
472     * Returns the user agent sent in the headers
473     *
474     * @access public
475     * @return string/boolean       false if not available
476     */
477    static public function GetUserAgent() {
478        if (isset(self::$useragent))
479            return self::$useragent;
480        else
481            return self::UNKNOWN;
482    }
483
484    /**
485     * Returns policy key sent by the device
486     *
487     * @access public
488     * @return int/boolean       false if not available
489     */
490    static public function GetPolicyKey() {
491        if (isset(self::$policykey))
492            return self::$policykey;
493        else
494            return false;
495    }
496
497    /**
498     * Indicates if a policy key was sent by the device
499     *
500     * @access public
501     * @return boolean
502     */
503    static public function WasPolicyKeySent() {
504        return isset(self::$headers["x-ms-policykey"]);
505    }
506
507    /**
508     * Indicates if Z-Push was called with a POST request
509     *
510     * @access public
511     * @return boolean
512     */
513    static public function IsMethodPOST() {
514        return (self::$method == "POST");
515    }
516
517    /**
518     * Indicates if Z-Push was called with a GET request
519     *
520     * @access public
521     * @return boolean
522     */
523    static public function IsMethodGET() {
524        return (self::$method == "GET");
525    }
526
527    /**
528     * Indicates if Z-Push was called with a OPTIONS request
529     *
530     * @access public
531     * @return boolean
532     */
533    static public function IsMethodOPTIONS() {
534        return (self::$method == "OPTIONS");
535    }
536
537    /**
538     * Sometimes strange device ids are sumbitted
539     * No device information should be saved when this happens
540     *
541     * @access public
542     * @return boolean       false if invalid
543     */
544    static public function IsValidDeviceID() {
545        if (self::GetDeviceID() === "validate" || self::GetDeviceID() === "webservice")
546            return false;
547        else
548            return true;
549    }
550
551    /**
552     * Returns the amount of data sent in this request (from the headers)
553     *
554     * @access public
555     * @return int
556     */
557    static public function GetContentLength() {
558        return (isset(self::$headers["content-length"]))? (int) self::$headers["content-length"] : 0;
559    }
560
561
562    /**----------------------------------------------------------------------------------------------------------
563     * Private stuff
564     */
565
566    /**
567     * Replaces all not allowed characters in a string
568     *
569     * @param string    $input          the input string
570     * @param int       $filter         one of the predefined filters: LETTERS_ONLY, HEX_ONLY, WORDCHAR_ONLY, NUMBERS_ONLY, NUMBERSDOT_ONLY
571     * @param char      $replacevalue   (opt) a character the filtered characters should be replaced with
572     *
573     * @access public
574     * @return string
575     */
576    static private function filterEvilInput($input, $filter, $replacevalue = '') {
577        $re = false;
578        if ($filter == self::LETTERS_ONLY)            $re = "/[^A-Za-z]/";
579        else if ($filter == self::HEX_ONLY)           $re = "/[^A-Fa-f0-9]/";
580        else if ($filter == self::WORDCHAR_ONLY)      $re = "/[^A-Za-z0-9]/";
581        else if ($filter == self::NUMBERS_ONLY)       $re = "/[^0-9]/";
582        else if ($filter == self::NUMBERSDOT_ONLY)    $re = "/[^0-9\.]/";
583        else if ($filter == self::HEX_EXTENDED)       $re = "/[^A-Fa-f0-9\:]/";
584
585        return ($re) ? preg_replace($re, $replacevalue, $input) : '';
586    }
587}
588?>
Note: See TracBrowser for help on using the repository browser.