Passed
Push — master ( 8ceacb...8c98e8 )
by Jean-Christophe
15:18
created

RestServer::setAllowedOrigin()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 5
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 0
Metric Value
eloc 4
dl 0
loc 5
ccs 0
cts 4
cp 0
rs 10
c 0
b 0
f 0
cc 2
nc 2
nop 1
crap 6
1
<?php
2
3
namespace Ubiquity\controllers\rest;
4
5
use Ubiquity\controllers\Startup;
6
use Ubiquity\cache\ClassUtils;
7
use Ubiquity\cache\CacheManager;
8
use Ubiquity\exceptions\RestException;
9
use Ubiquity\log\Logger;
10
use Ubiquity\utils\http\URequest;
11
12
/**
13
 * Rest server base class.
14
 * Ubiquity\controllers\rest$RestServer
15
 * This class is part of Ubiquity
16
 *
17
 * @author jcheron <[email protected]>
18
 * @version 1.0.7
19
 *
20
 */
21
class RestServer {
22
	/**
23
	 *
24
	 * @var array
25
	 */
26
	protected $config;
27
	protected $headers;
28
	protected $tokensFolder;
29
	protected $tokenLength;
30
	protected $tokenDuration;
31
	protected $tokensCacheKey = "_apiTokens";
32
	protected $allowedOrigins;
33
34
	/**
35
	 *
36
	 * @var ApiTokens
37
	 */
38
	protected $apiTokens;
39
40 13
	public function __construct(&$config, $headers = null) {
41 13
		$this->config = $config;
42 13
		$this->headers = [ 'Access-Control-Allow-Origin' => '*','Access-Control-Allow-Credentials' => 'true','Access-Control-Max-Age' => '86400','Access-Control-Allow-Methods' => 'GET, POST, OPTIONS, PUT, DELETE, PATCH, HEAD','Content-Type' => 'application/json; charset=utf8' ];
43 13
		if (\is_array ( $headers )) {
44
			$this->headers = \array_merge ( $this->headers, $headers );
45
		}
46 13
	}
47
48
	/**
49
	 * Establishes the connection with the server, returns an added token in the Authorization header of the request
50
	 *
51
	 * @return array
52
	 */
53
	public function connect($datas=null) {
54
		if (! isset ( $this->apiTokens )) {
55
			$this->apiTokens = $this->_loadApiTokens ();
56
		}
57
		$token = $this->apiTokens->addToken ($datas);
58
		$this->_addHeaderToken ( $token );
59
		return [ "access_token" => $token,"token_type" => "Bearer","expires_in" => $this->apiTokens->getDuration () ];
60
	}
61
62
	/**
63
	 * Check if token is valid
64
	 * @param callable $callback
65
	 * @return boolean
66
	 */
67 1
	public function isValid($callback) {
68 1
		$this->apiTokens = $this->_loadApiTokens ();
69 1
		$key = $this->_getHeaderToken ();
70
		if ($this->apiTokens->isExpired ( $key )) {
71
			return false;
72
		} else {
73
			$token=$this->apiTokens->getToken($key);
74
			if($callback($token['datas']??null)) {
75
				$this->_addHeaderToken($key);
76
				return true;
77
			}
78
			return false;
79
		}
80
	}
81
82 1
	public function _getHeaderToken() {
83 1
		$authHeader = $this->_getHeader ( "Authorization" );
84 1
		if ($authHeader !== false) {
85
			$headerDatas = explode ( " ", $authHeader, 2 );
86
			if (\count( $headerDatas ) === 2) {
87
				list ( $type, $data ) = $headerDatas;
88
				if (\strcasecmp ( $type, "Bearer" ) == 0) {
89
					return $data;
90
				} else {
91
					throw new RestException ( "Bearer is required in authorization header." );
92
				}
93
			} else {
94
				throw new RestException ( "The header Authorization is required in http headers." );
95
			}
96
		} else {
97 1
			throw new RestException ( "The header Authorization is required in http headers." );
98
		}
99
	}
100
101 13
	public function finalizeTokens() {
102 13
		if (isset ( $this->apiTokens )) {
103
			$this->apiTokens->removeExpireds ();
104
			$this->apiTokens->storeToCache ();
105
		}
106 13
	}
107
108 1
	public function _getHeader($header) {
109 1
		$headers = getallheaders ();
110 1
		if (isset ( $headers [$header] )) {
111
			return $headers [$header];
112
		}
113 1
		return false;
114
	}
115
116
	public function _addHeaderToken($token) {
117
		$this->_header ( "Authorization", "Bearer " . $token, true );
118
	}
119
120 1
	public function _loadApiTokens() {
121 1
		return $this->getApiTokens ()->getFromCache ( CacheManager::getAbsoluteCacheDirectory () . \DS, $this->tokensCacheKey );
122
	}
123
124 1
	protected function getApiTokens() {
125 1
		if (! isset ( $this->apiTokens )) {
126 1
			$this->apiTokens = $this->newApiTokens ();
127
		}
128 1
		return $this->apiTokens;
129
	}
130
131
	/**
132
	 * To override for defining another ApiToken type
133
	 *
134
	 * @return ApiTokens
135
	 */
136 1
	protected function newApiTokens() {
137 1
		return new ApiTokens ( $this->tokenLength, $this->tokenDuration );
138
	}
139
140 13
	protected function getAllowedOrigin() {
141 13
		$http_origin = URequest::getOrigin ();
142 13
		if (is_array ( $this->allowedOrigins )) {
143
			if (array_search ( $http_origin, $this->allowedOrigins ) !== false) {
144
				return $http_origin;
145
			}
146
			return 'null';
147
		}
148 13
		return '*';
149
	}
150
151 13
	protected function setAccessControlAllowOriginHeader() {
152 13
		$origin = $this->getAllowedOrigin ();
153 13
		unset ( $this->headers ['Access-Control-Allow-Origin'] );
154 13
		\header ( 'Access-Control-Allow-Origin: ' . $origin, true );
155 13
	}
156
157 13
	protected function addOtherHeaders() {
158 13
		foreach ( $this->headers as $k => $v ) {
159 13
			$this->_header ( $k, $v );
160
		}
161 13
	}
162
163
	/**
164
	 *
165
	 * @param string $headerField
166
	 * @param string $value
167
	 * @param null|boolean $replace
168
	 */
169 13
	public function _header($headerField, $value = null, $replace = null) {
170 13
		if (! isset ( $value )) {
171 13
			if (isset ( $this->headers [$headerField] )) {
172 13
				$value = $this->headers [$headerField];
173 13
				unset ( $this->headers [$headerField] );
174
			} else
175 13
				return;
176
		}
177 13
		\header ( trim ( $headerField ) . ": " . trim ( $value ), $replace );
0 ignored issues
show
Bug introduced by
It seems like $replace can also be of type null; however, parameter $replace of header() does only seem to accept boolean, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

177
		\header ( trim ( $headerField ) . ": " . trim ( $value ), /** @scrutinizer ignore-type */ $replace );
Loading history...
178 13
	}
179
180
	/**
181
	 *
182
	 * @param string $contentType default application/json
183
	 * @param string $charset default utf8
184
	 */
185 13
	public function _setContentType($contentType = null, $charset = null) {
186 13
		$value = $contentType;
187 13
		if (isset ( $charset ))
188
			$value .= "; charset=" . $charset;
189 13
		$this->_header ( "Content-type", $value );
190 13
	}
191
192 13
	public function cors() {
193 13
		$this->setAccessControlAllowOriginHeader ();
194 13
		$this->_header ( 'Access-Control-Allow-Credentials' );
195 13
		$this->_header ( 'Access-Control-Max-Age' );
196 13
		if ($_SERVER ['REQUEST_METHOD'] == 'OPTIONS') {
197
			if (isset ( $_SERVER ['HTTP_ACCESS_CONTROL_REQUEST_METHOD'] ))
198
				$this->_header ( 'Access-Control-Allow-Methods' );
199
200
			if (isset ( $_SERVER ['HTTP_ACCESS_CONTROL_REQUEST_HEADERS'] )) {
201
				$this->_header ( 'Access-Control-Allow-Headers', $_SERVER ['HTTP_ACCESS_CONTROL_REQUEST_HEADERS'] );
202
			} else {
203
				$this->_header ( 'Access-Control-Allow-Headers', '*' );
204
			}
205
			Logger::info ( "Rest", "cors exit normally", "Cors" );
206
		}
207 13
		$this->addOtherHeaders ();
208 13
	}
209
210 1
	public static function getRestNamespace() {
211 1
		$config = Startup::getConfig ();
212 1
		$controllerNS = Startup::getNS('controllers');
213 1
		$restNS = $config ["mvcNS"]["rest"]??"";
214 1
		return ClassUtils::getNamespaceFromParts ( [ $controllerNS,$restNS ] );
215
	}
216
217
	/**
218
	 * Adds an unique allowed origin for access control.
219
	 *
220
	 * @param string $address
221
	 */
222
	public function setAllowedOrigin($address = '*') {
223
		if ($address !== '*') {
224
			$this->allowedOrigins = [ $address ];
225
		} else {
226
			$this->allowedOrigins = [ ];
227
		}
228
	}
229
230
	/**
231
	 * Sets the allowed origins for access control.
232
	 *
233
	 * @param array $addresses
234
	 */
235
	public function setAllowedOrigins($addresses) {
236
		$this->allowedOrigins = $addresses;
237
	}
238
239
	/**
240
	 * Adds an allowed origin for access control.
241
	 *
242
	 * @param string $address
243
	 */
244
	public function addAllowedOrigin($address) {
245
		$this->allowedOrigins = [ $address ];
246
	}
247
248
	/**
249
	 *
250
	 * @param int $tokenLength
251
	 */
252
	public function setTokenLength($tokenLength) {
253
		$this->tokenLength = $tokenLength;
254
	}
255
256
	/**
257
	 *
258
	 * @param mixed $tokenDuration
259
	 */
260
	public function setTokenDuration($tokenDuration) {
261
		$this->tokenDuration = $tokenDuration;
262
	}
263
}
264