]> git.mxchange.org Git - friendica.git/blob - src/Security/OAuth1/OAuthUtil.php
Merge pull request #12928 from jsoref/spelling
[friendica.git] / src / Security / OAuth1 / OAuthUtil.php
1 <?php
2 /**
3  * @copyright Copyright (C) 2010-2023, the Friendica project
4  *
5  * @license GNU AGPL version 3 or any later version
6  *
7  * This program is free software: you can redistribute it and/or modify
8  * it under the terms of the GNU Affero General Public License as
9  * published by the Free Software Foundation, either version 3 of the
10  * License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU Affero General Public License for more details.
16  *
17  * You should have received a copy of the GNU Affero General Public License
18  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
19  *
20  */
21
22 namespace Friendica\Security\OAuth1;
23
24 class OAuthUtil
25 {
26         public static function urlencode_rfc3986($input)
27         {
28                 if (is_array($input)) {
29                         return array_map(['Friendica\Security\OAuth1\OAuthUtil', 'urlencode_rfc3986'], $input);
30                 } else if (is_scalar($input)) {
31                         return str_replace(
32                                 '+',
33                                 ' ',
34                                 str_replace('%7E', '~', rawurlencode($input))
35                         );
36                 } else {
37                         return '';
38                 }
39         }
40
41
42         // This decode function isn't taking into consideration the above
43         // modifications to the encoding process. However, this method doesn't
44         // seem to be used anywhere so leaving it as is.
45         public static function urldecode_rfc3986($string)
46         {
47                 return urldecode($string);
48         }
49
50         // Utility function for turning the Authorization: header into
51         // parameters, has to do some unescaping
52         // Can filter out any non-oauth parameters if needed (default behaviour)
53         public static function split_header($header, $only_allow_oauth_parameters = true)
54         {
55                 $pattern = '/(([-_a-z]*)=("([^"]*)"|([^,]*)),?)/';
56                 $offset  = 0;
57                 $params  = [];
58                 while (preg_match($pattern, $header, $matches, PREG_OFFSET_CAPTURE, $offset) > 0) {
59                         $match          = $matches[0];
60                         $header_name    = $matches[2][0];
61                         $header_content = (isset($matches[5])) ? $matches[5][0] : $matches[4][0];
62                         if (preg_match('/^oauth_/', $header_name) || !$only_allow_oauth_parameters) {
63                                 $params[$header_name] = OAuthUtil::urldecode_rfc3986($header_content);
64                         }
65                         $offset = $match[1] + strlen($match[0]);
66                 }
67
68                 if (isset($params['realm'])) {
69                         unset($params['realm']);
70                 }
71
72                 return $params;
73         }
74
75         // helper to try to sort out headers for people who aren't running apache
76         public static function get_headers()
77         {
78                 if (function_exists('apache_request_headers')) {
79                         // we need this to get the actual Authorization: header
80                         // because apache tends to tell us it doesn't exist
81                         $headers = apache_request_headers();
82
83                         // sanitize the output of apache_request_headers because
84                         // we always want the keys to be Cased-Like-This and arh()
85                         // returns the headers in the same case as they are in the
86                         // request
87                         $out = [];
88                         foreach ($headers as $key => $value) {
89                                 $key       = str_replace(
90                                         " ",
91                                         "-",
92                                         ucwords(strtolower(str_replace("-", " ", $key)))
93                                 );
94                                 $out[$key] = $value;
95                         }
96                 } else {
97                         // otherwise we don't have apache and are just going to have to hope
98                         // that $_SERVER actually contains what we need
99                         $out = [];
100                         if (isset($_SERVER['CONTENT_TYPE']))
101                                 $out['Content-Type'] = $_SERVER['CONTENT_TYPE'];
102                         if (isset($_ENV['CONTENT_TYPE']))
103                                 $out['Content-Type'] = $_ENV['CONTENT_TYPE'];
104
105                         foreach ($_SERVER as $key => $value) {
106                                 if (substr($key, 0, 5) == "HTTP_") {
107                                         // this is chaos, basically it is just there to capitalize the first
108                                         // letter of every word that is not an initial HTTP and strip HTTP
109                                         // code from przemek
110                                         $key       = str_replace(
111                                                 " ",
112                                                 "-",
113                                                 ucwords(strtolower(str_replace("_", " ", substr($key, 5))))
114                                         );
115                                         $out[$key] = $value;
116                                 }
117                         }
118                 }
119                 return $out;
120         }
121
122         // This function takes a input like a=b&a=c&d=e and returns the parsed
123         // parameters like this
124         // array('a' => array('b','c'), 'd' => 'e')
125         public static function parse_parameters($input)
126         {
127                 if (!isset($input) || !$input) return [];
128
129                 $pairs = explode('&', $input);
130
131                 $parsed_parameters = [];
132                 foreach ($pairs as $pair) {
133                         $split     = explode('=', $pair, 2);
134                         $parameter = OAuthUtil::urldecode_rfc3986($split[0]);
135                         $value     = isset($split[1]) ? OAuthUtil::urldecode_rfc3986($split[1]) : '';
136
137                         if (isset($parsed_parameters[$parameter])) {
138                                 // We have already received parameter(s) with this name, so add to the list
139                                 // of parameters with this name
140
141                                 if (is_scalar($parsed_parameters[$parameter])) {
142                                         // This is the first duplicate, so transform scalar (string) into an array
143                                         // so we can add the duplicates
144                                         $parsed_parameters[$parameter] = [$parsed_parameters[$parameter]];
145                                 }
146
147                                 $parsed_parameters[$parameter][] = $value;
148                         } else {
149                                 $parsed_parameters[$parameter] = $value;
150                         }
151                 }
152                 return $parsed_parameters;
153         }
154
155         public static function build_http_query($params)
156         {
157                 // Parameters are sorted by name, using lexicographical byte value ordering.
158                 // Ref: Spec: 9.1.1 (1)
159                 uksort($params, 'strcmp');
160                 return http_build_query($params, '', null, PHP_QUERY_RFC3986);
161         }
162 }