| 
							- <?php
 - 
 - namespace dokuwiki;
 - 
 - /**
 -  * Minimal JWT implementation
 -  */
 - class JWT
 - {
 -     protected $user;
 -     protected $issued;
 -     protected $secret;
 - 
 -     /**
 -      * Create a new JWT object
 -      *
 -      * Use validate() or create() to create a new instance
 -      *
 -      * @param string $user
 -      * @param int $issued
 -      */
 -     protected function __construct($user, $issued)
 -     {
 -         $this->user = $user;
 -         $this->issued = $issued;
 -     }
 - 
 -     /**
 -      * Load the cookiesalt as secret
 -      *
 -      * @return string
 -      */
 -     protected static function getSecret()
 -     {
 -         return auth_cookiesalt(false, true);
 -     }
 - 
 -     /**
 -      * Create a new instance from a token
 -      *
 -      * @param $token
 -      * @return self
 -      * @throws \Exception
 -      */
 -     public static function validate($token)
 -     {
 -         [$header, $payload, $signature] = sexplode('.', $token, 3, '');
 -         $signature = base64_decode($signature);
 - 
 -         if (!hash_equals($signature, hash_hmac('sha256', "$header.$payload", self::getSecret(), true))) {
 -             throw new \Exception('Invalid JWT signature');
 -         }
 - 
 -         try {
 -             $header = json_decode(base64_decode($header), true, 512, JSON_THROW_ON_ERROR);
 -             $payload = json_decode(base64_decode($payload), true, 512, JSON_THROW_ON_ERROR);
 -         } catch (\Exception $e) {
 -             throw new \Exception('Invalid JWT', $e->getCode(), $e);
 -         }
 - 
 -         if (!$header || !$payload || !$signature) {
 -             throw new \Exception('Invalid JWT');
 -         }
 - 
 -         if ($header['alg'] !== 'HS256') {
 -             throw new \Exception('Unsupported JWT algorithm');
 -         }
 -         if ($header['typ'] !== 'JWT') {
 -             throw new \Exception('Unsupported JWT type');
 -         }
 -         if ($payload['iss'] !== 'dokuwiki') {
 -             throw new \Exception('Unsupported JWT issuer');
 -         }
 -         if (isset($payload['exp']) && $payload['exp'] < time()) {
 -             throw new \Exception('JWT expired');
 -         }
 - 
 -         $user = $payload['sub'];
 -         $file = self::getStorageFile($user);
 -         if (!file_exists($file)) {
 -             throw new \Exception('JWT not found, maybe it expired?');
 -         }
 - 
 -         if (file_get_contents($file) !== $token) {
 -             throw new \Exception('JWT invalid, maybe it expired?');
 -         }
 - 
 -         return new self($user, $payload['iat']);
 -     }
 - 
 -     /**
 -      * Create a new instance from a user
 -      *
 -      * Loads an existing token if available
 -      *
 -      * @param $user
 -      * @return self
 -      */
 -     public static function fromUser($user)
 -     {
 -         $file = self::getStorageFile($user);
 - 
 -         if (file_exists($file)) {
 -             try {
 -                 return self::validate(io_readFile($file));
 -             } catch (\Exception $ignored) {
 -             }
 -         }
 - 
 -         $token = new self($user, time());
 -         $token->save();
 -         return $token;
 -     }
 - 
 - 
 -     /**
 -      * Get the JWT token for this instance
 -      *
 -      * @return string
 -      */
 -     public function getToken()
 -     {
 -         $header = [
 -             'alg' => 'HS256',
 -             'typ' => 'JWT',
 -         ];
 -         $header = base64_encode(json_encode($header));
 - 
 -         $payload = [
 -             'iss' => 'dokuwiki',
 -             'sub' => $this->user,
 -             'iat' => $this->issued,
 -         ];
 -         $payload = base64_encode(json_encode($payload, JSON_THROW_ON_ERROR));
 - 
 -         $signature = hash_hmac('sha256', "$header.$payload", self::getSecret(), true);
 -         $signature = base64_encode($signature);
 -         return "$header.$payload.$signature";
 -     }
 - 
 -     /**
 -      * Save the token for the user
 -      *
 -      * Resets the issued timestamp
 -      */
 -     public function save()
 -     {
 -         $this->issued = time();
 -         io_saveFile(self::getStorageFile($this->user), $this->getToken());
 -     }
 - 
 -     /**
 -      * Get the user of this token
 -      *
 -      * @return string
 -      */
 -     public function getUser()
 -     {
 -         return $this->user;
 -     }
 - 
 -     /**
 -      * Get the issued timestamp of this token
 -      *
 -      * @return int
 -      */
 -     public function getIssued()
 -     {
 -         return $this->issued;
 -     }
 - 
 -     /**
 -      * Get the storage file for this token
 -      *
 -      * Tokens are stored to be able to invalidate them
 -      *
 -      * @param string $user The user the token is for
 -      * @return string
 -      */
 -     public static function getStorageFile($user)
 -     {
 -         return getCacheName($user, '.token');
 -     }
 - }
 
 
  |