ILIAS  trunk Revision v11.0_alpha-2638-g80c1d007f79
class.ilWACSignedPath.php
Go to the documentation of this file.
1 <?php
2 
19 // declare(strict_types=1);
24 
32 {
33  public const WAC_TOKEN_ID = 'il_wac_token';
34  public const WAC_TIMESTAMP_ID = 'il_wac_ts';
35  public const WAC_TTL_ID = 'il_wac_ttl';
36  public const TS_SUFFIX = 'ts';
37  public const TTL_SUFFIX = 'ttl';
38  public const MAX_LIFETIME = 600;
39 
40  protected ?ilWACPath $path_object = null;
42  protected int $type = PathType::FILE;
43  protected static int $token_max_lifetime_in_seconds = 5;
44  protected static int $cookie_max_lifetime_in_seconds = 300;
45  protected bool $checked = false;
46 
50  public function __construct(ilWACPath $ilWACPath, private GlobalHttpState $httpService, private CookieFactory $cookieFactory)
51  {
52  $this->setPathObject($ilWACPath);
53  }
54 
58  public function getSignedPath(): string
59  {
60  if ($this->getType() !== PathType::FILE) {
62  }
63  if ($this->getPathObject()->getOriginalRequest() === '' || $this->getPathObject()->getOriginalRequest() === '0') {
64  return '';
65  }
66  if (!$this->getPathObject()->fileExists()) {
67  // return $this->getPathObject()->getOriginalRequest();
68  }
69 
70  if (strpos($this->getPathObject()->getPath(), '?')) {
71  $path = $this->getPathObject()->getPath() . '&' . self::WAC_TOKEN_ID . '='
72  . $this->getTokenInstance()->getToken();
73  } else {
74  $path = $this->getPathObject()->getPath() . '?' . self::WAC_TOKEN_ID . '='
75  . $this->getTokenInstance()->getToken();
76  }
77 
78  $path .= '&' . self::WAC_TTL_ID . '=' . $this->getTokenInstance()->getTTL();
79 
80  return $path . '&' . self::WAC_TIMESTAMP_ID . '='
81  . $this->getTokenInstance()->getTimestamp();
82  }
83 
84  public function isFolderSigned(): bool
85  {
86  $this->httpService->cookieJar();
87 
88  $this->setType(PathType::FOLDER);
89  $plain_token = $this->buildTokenInstance();
90  $name = $plain_token->getHashedId();
91 
92  // Token
93  $default_token = '';
94  $token_cookie_value = $this->httpService->request()->getCookieParams()[$name] ?? $default_token;
95  // Timestamp
96  $default_timestamp = 0;
97  $timestamp_cookie_value = $this->httpService->request()->getCookieParams()[$name . self::TS_SUFFIX] ?? $default_timestamp;
98  $timestamp_cookie_value = (int) $timestamp_cookie_value;
99  // TTL
100  $default_ttl = 0;
101  $ttl_cookie_value = $this->httpService->request()->getCookieParams()[$name . self::TTL_SUFFIX] ?? $default_ttl;
102  $ttl_cookie_value = (int) $ttl_cookie_value;
103 
104  $this->getPathObject()->setToken($token_cookie_value);
105  $this->getPathObject()->setTimestamp($timestamp_cookie_value);
106  $this->getPathObject()->setTTL($ttl_cookie_value);
107  $this->buildAndSetTokenInstance();
108 
109  return $this->getPathObject()->hasToken();
110  }
111 
115  public function isFolderTokenValid(): bool
116  {
117  if (!$this->isFolderSigned()) {
118  return false;
119  }
120 
121  return $this->checkToken();
122  }
123 
124  protected function saveFolderToken(): void
125  {
126  $ttl = $this->getPathObject()->getTTL();
127  $cookie_lifetime = $ttl !== 0 ? $ttl : self::getCookieMaxLifetimeInSeconds();
128  $id = $this->getTokenInstance()->getHashedId();
129  $expire = time() + $cookie_lifetime + 3600;
130  $secure = true;
131  $domain = null;
132  $http_only = true;
133  $path = '/';
134 
135  $tokenCookie = $this->cookieFactory->create($id, $this->getTokenInstance()->getToken())
136  ->withExpires($expire)
137  ->withPath($path)
138  ->withSecure($secure)
139  ->withDomain($domain)
140  ->withHttpOnly($http_only);
141 
142  $timestampCookie = $this->cookieFactory->create($id . self::TS_SUFFIX, time())
143  ->withExpires($expire)
144  ->withPath($path)
145  ->withDomain($domain)
146  ->withSecure($secure)
147  ->withHttpOnly($http_only);
148 
149  $ttlCookie = $this->cookieFactory->create($id . self::TTL_SUFFIX, $cookie_lifetime)
150  ->withExpires($expire)
151  ->withPath($path)
152  ->withDomain($domain)
153  ->withSecure($secure)
154  ->withHttpOnly($http_only);
155 
156  $jar = $this->httpService->cookieJar()->with($tokenCookie)
157  ->with($timestampCookie)
158  ->with($ttlCookie);
159 
160  // FIX: currently the cookies are never stored, we must use setcookie
161  foreach ($jar->getAll() as $cookie) {
162  setcookie(
163  $cookie->getName(),
164  (string) $cookie->getValue(),
165  [
166  'expires' => $cookie->getExpires(),
167  'path' => $cookie->getPath() ?? '/',
168  'domain' => $cookie->getDomain() ?? '',
169  'secure' => $cookie->getSecure(),
170  'httponly' => $cookie->getHttpOnly()
171  ]
172  );
173  }
174  }
175 
176  public function revalidatingFolderToken(): bool
177  {
178  if ($this->getType() !== PathType::FOLDER) {
179  return false;
180  }
181  $this->buildAndSetTokenInstance(time(), $this->getPathObject()->getTTL());
182  $this->getPathObject()->setTTL($this->getTokenInstance()->getTTL());
183  $this->getPathObject()->setTimestamp($this->getTokenInstance()->getTimestamp());
184  $this->getPathObject()->setToken($this->getTokenInstance()->getToken());
185 
186  $this->saveFolderToken();
187 
188  return true;
189  }
190 
191  public function isSignedPath(): bool
192  {
193  return ($this->getPathObject()->hasToken() && $this->getPathObject()->hasTimestamp()
194  && $this->getPathObject()->hasTTL());
195  }
196 
200  public function isSignedPathValid(): bool
201  {
202  $this->buildAndSetTokenInstance($this->getPathObject()->getTimestamp(), $this->getPathObject()->getTTL());
203 
204  return $this->checkToken();
205  }
206 
212  public static function signFile(string $path_to_file): string
213  {
214  global $DIC;
215  if ($path_to_file === '' || $path_to_file === '0') {
216  return '';
217  }
218  $ilWACPath = new ilWACPath($path_to_file);
219  if ($ilWACPath->getClient() === '' || $ilWACPath->getClient() === '0') {
220  return $path_to_file;
221  }
222  $obj = new self($ilWACPath, $DIC->http(), new CookieFactoryImpl());
223  $obj->setType(PathType::FILE);
224  $obj->buildAndSetTokenInstance(time(), self::getTokenMaxLifetimeInSeconds());
225 
226  return $obj->getSignedPath();
227  }
228 
229  public static function signFolderOfStartFile(string $start_file_path): void
230  {
231  global $DIC;
232  $obj = new self(new ilWACPath($start_file_path), $DIC->http(), new CookieFactoryImpl());
233  $obj->setType(PathType::FOLDER);
234  $obj->buildAndSetTokenInstance(time(), self::getCookieMaxLifetimeInSeconds());
235  $obj->saveFolderToken();
236  }
237 
238  public function getTokenInstance(): ?\ilWACToken
239  {
240  return $this->token_instance;
241  }
242 
243  public function setTokenInstance(ilWACToken $token_instance): void
244  {
245  $this->token_instance = $token_instance;
246  }
247 
248  public function getType(): int
249  {
250  return $this->type;
251  }
252 
253  public function setType(int $type): void
254  {
255  $this->type = $type;
256  }
257 
258  public function getPathObject(): ?\ilWACPath
259  {
260  return $this->path_object;
261  }
262 
263  public function setPathObject(ilWACPath $path_object): void
264  {
265  $this->path_object = $path_object;
266  }
267 
271  protected function checkToken(): bool
272  {
273  $request_token_string = $this->getPathObject()->getToken();
274  $request_ttl = $this->getPathObject()->getTTL();
275  $request_timestamp = $this->getPathObject()->getTimestamp();
276  $current_timestamp = time();
277 
278  $timestamp_valid = ($current_timestamp < ($request_timestamp + $request_ttl));
279 
280  if (!$timestamp_valid) {
281  $this->setChecked(true);
282 
283  return false;
284  }
285 
286  $simulated_token = $this->buildTokenInstance($request_timestamp, $request_ttl);
287  $simulated_token_string = $simulated_token->getToken();
288  $token_valid = ($simulated_token_string === $request_token_string);
289 
290  if (!$token_valid) {
291  $this->setChecked(true);
292 
293  return false;
294  }
295 
296  return true;
297  }
298 
303  protected function buildTokenInstance(int $timestamp = 0, int $ttl = 0): \ilWACToken
304  {
305  if ($this->getType() === 0) {
307  }
308 
309  $path = match ($this->getType()) {
310  PathType::FOLDER => $this->getPathObject()->getSecurePath(),
311  default => $this->getPathObject()->getPathWithoutQuery(),
312  };
313 
314  $client = $this->getPathObject()->getClient();
315  $timestamp = $timestamp !== 0 ? $timestamp : $this->getPathObject()->getTimestamp();
316  $ttl = $ttl !== 0 ? $ttl : $this->getPathObject()->getTTL();
317 
318  return new ilWACToken($path, $client, $timestamp, $ttl);
319  }
320 
325  public function buildAndSetTokenInstance(int $timestamp = 0, int $ttl = 0): void
326  {
327  $this->setTokenInstance($this->buildTokenInstance($timestamp, $ttl));
328  }
329 
330  public static function getTokenMaxLifetimeInSeconds(): int
331  {
332  return self::$token_max_lifetime_in_seconds;
333  }
334 
339  public static function setTokenMaxLifetimeInSeconds(int $token_max_lifetime_in_seconds): void
340  {
341  if ($token_max_lifetime_in_seconds > self::MAX_LIFETIME) {
343  }
344  self::$token_max_lifetime_in_seconds = $token_max_lifetime_in_seconds;
345  }
346 
347  public static function getCookieMaxLifetimeInSeconds(): int
348  {
349  return self::$cookie_max_lifetime_in_seconds;
350  }
351 
357  public static function setCookieMaxLifetimeInSeconds(int $cookie_max_lifetime_in_seconds): void
358  {
359  if ($cookie_max_lifetime_in_seconds > self::MAX_LIFETIME) {
361  }
362  self::$cookie_max_lifetime_in_seconds = $cookie_max_lifetime_in_seconds;
363  }
364 
365  protected function getRelevantLifeTime(): int
366  {
367  $request_ttl = $this->getPathObject()->getTTL();
368  if ($request_ttl > 0) {
369  return $request_ttl;
370  }
371 
372  return match ($this->getType()) {
373  PathType::FOLDER => self::getCookieMaxLifetimeInSeconds(),
374  PathType::FILE => self::getTokenMaxLifetimeInSeconds(),
375  default => 0,
376  };
377  }
378 
379  public function isChecked(): bool
380  {
381  return $this->checked;
382  }
383 
384  public function setChecked(bool $checked): void
385  {
386  $this->checked = $checked;
387  }
388 }
static getCookieMaxLifetimeInSeconds()
setTokenInstance(ilWACToken $token_instance)
buildAndSetTokenInstance(int $timestamp=0, int $ttl=0)
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
static setTokenMaxLifetimeInSeconds(int $token_max_lifetime_in_seconds)
static setCookieMaxLifetimeInSeconds(int $cookie_max_lifetime_in_seconds)
static int $token_max_lifetime_in_seconds
$path
Definition: ltiservices.php:29
while($session_entry=$r->fetchRow(ilDBConstants::FETCHMODE_ASSOC)) return null
checked()
description: > Example for rendering a Checked Glyph.
Definition: checked.php:25
$client
static signFolderOfStartFile(string $start_file_path)
setPathObject(ilWACPath $path_object)
__construct(ilWACPath $ilWACPath, private GlobalHttpState $httpService, private CookieFactory $cookieFactory)
ilWACSignedPath constructor.
global $DIC
Definition: shib_login.php:26
buildTokenInstance(int $timestamp=0, int $ttl=0)
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
foreach($mandatory_scripts as $file) $timestamp
Definition: buildRTE.php:70
$id
plugin.php for ilComponentBuildPluginInfoObjectiveTest::testAddPlugins
Definition: plugin.php:23
static int $cookie_max_lifetime_in_seconds
static signFile(string $path_to_file)
static getTokenMaxLifetimeInSeconds()
setChecked(bool $checked)