Passed
Push — master ( 0ed261...e52b37 )
by Jean-Christophe
17:09
created

RestServer::setTokenLength()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 2
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
eloc 1
dl 0
loc 2
ccs 0
cts 2
cp 0
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 1
crap 2
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.8
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 boolean $replace
168
	 */
169 13
	public function _header($headerField, $value = null, bool $replace = true) {
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 );
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
		}
190 13
		$this->_header ( 'Content-type', $value );
191 13
	}
192
193 13
	public function cors() {
194 13
		$this->setAccessControlAllowOriginHeader ();
195 13
		$this->_header ( 'Access-Control-Allow-Credentials' );
196 13
		$this->_header ( 'Access-Control-Max-Age' );
197 13
		if ($_SERVER ['REQUEST_METHOD'] == 'OPTIONS') {
198
			if (isset ( $_SERVER ['HTTP_ACCESS_CONTROL_REQUEST_METHOD'] )){
199
				$this->_header ( 'Access-Control-Allow-Methods' );
200
			}
201
			if (isset ( $_SERVER ['HTTP_ACCESS_CONTROL_REQUEST_HEADERS'] )) {
202
				$this->_header ( 'Access-Control-Allow-Headers', $_SERVER ['HTTP_ACCESS_CONTROL_REQUEST_HEADERS'] );
203
			} else {
204
				$this->_header ( 'Access-Control-Allow-Headers', '*' );
205
			}
206
			Logger::info ( 'Rest', 'cors exit normally', 'Cors' );
207
		}
208 13
		$this->addOtherHeaders ();
209 13
	}
210
211 1
	public static function getRestNamespace() {
212 1
		$config = Startup::getConfig ();
213 1
		$controllerNS = Startup::getNS('controllers');
214 1
		$restNS = $config ['mvcNS']['rest']??"";
215 1
		return ClassUtils::getNamespaceFromParts ( [ $controllerNS,$restNS ] );
216
	}
217
218
	/**
219
	 * Adds an unique allowed origin for access control.
220
	 *
221
	 * @param string $address
222
	 */
223
	public function setAllowedOrigin($address = '*') {
224
		if ($address !== '*') {
225
			$this->allowedOrigins = [ $address ];
226
		} else {
227
			$this->allowedOrigins = [ ];
228
		}
229
	}
230
231
	/**
232
	 * Sets the allowed origins for access control.
233
	 *
234
	 * @param array $addresses
235
	 */
236
	public function setAllowedOrigins($addresses) {
237
		$this->allowedOrigins = $addresses;
238
	}
239
240
	/**
241
	 * Adds an allowed origin for access control.
242
	 *
243
	 * @param string $address
244
	 */
245
	public function addAllowedOrigin($address) {
246
		$this->allowedOrigins = [ $address ];
247
	}
248
249
	/**
250
	 *
251
	 * @param int $tokenLength
252
	 */
253
	public function setTokenLength($tokenLength) {
254
		$this->tokenLength = $tokenLength;
255
	}
256
257
	/**
258
	 *
259
	 * @param mixed $tokenDuration
260
	 */
261
	public function setTokenDuration($tokenDuration) {
262
		$this->tokenDuration = $tokenDuration;
263
	}
264
}
265