1<?php 2 3use dokuwiki\Extension\Plugin; 4 5/** 6 * DokuWiki Plugin cosmocode (Helper Component) 7 * 8 * @license GPL 2 http://www.gnu.org/licenses/gpl-2.0.html 9 * @author Andreas Gohr <dokuwiki@cosmocode.de> 10 */ 11class helper_plugin_cosmocode_partner extends Plugin 12{ 13 const HOST = 'https://partnerapi.cosmocode.de/'; 14 15 /** 16 * Construct the URL at which a extension can be downloaded 17 * 18 * @param string $base 19 * @param string $token 20 * @return string 21 */ 22 public function getDownloadUrl($base, $token) 23 { 24 return self::HOST . 'download/' . $base . '.zip?token=' . $token; 25 } 26 27 /** 28 * Talk to the API to get the list of extensions 29 * 30 * Results are cached for 24 hours 31 * 32 * @return array 33 * @throws Exception 34 */ 35 public function getExtensions() 36 { 37 $http = new \dokuwiki\HTTP\DokuHTTPClient(); 38 $url = self::HOST . 'feed'; 39 $domain = parse_url(self::HOST, PHP_URL_HOST); 40 41 $tokens = $this->getTokens(); 42 if ($tokens) { 43 $http->headers['x-token'] = join(',', array_keys($tokens)); 44 } 45 $http->headers['x-wiki-id'] = md5(auth_cookiesalt()); 46 47 $cache = getCacheName($url . join(',', array_keys($tokens)), '.json'); 48 if (@filemtime($cache) > time() - 60 * 60 * 24) { 49 $data = io_readFile($cache, false); 50 } else { 51 $data = $http->get($url); 52 if ($data === false) { 53 $data = $http->resp_body; 54 $decoded = json_decode($data, true); 55 if ($decoded && isset($decoded['error'])) { 56 throw new \RuntimeException( 57 sprintf($this->getLang('error_api'), $decoded['error']) 58 ); 59 } else { 60 throw new \RuntimeException( 61 sprintf($this->getLang('error_connect'), $domain, $http->error) 62 ); 63 } 64 } 65 io_saveFile($cache, $data); 66 } 67 return json_decode($data, true); 68 } 69 70 /** 71 * Get the tokens from the config 72 * 73 * Decodes the payload and filters out expired tokens 74 * 75 * @return array 76 */ 77 public function getTokens() 78 { 79 $lines = $this->getConf('tokens'); 80 if (!$lines) return []; 81 $lines = explode("\n", $lines); 82 83 $tokens = []; 84 foreach ($lines as $token) { 85 $token = trim($token); 86 if (!$token) continue; 87 $decoded = $this->decodeJWT($token); 88 if (!$decoded) continue; 89 if (!isset($decoded['exp'])) continue; 90 if ($decoded['exp'] < time()) continue; 91 92 $tokens[$token] = $decoded; 93 } 94 95 return $tokens; 96 } 97 98 /** 99 * Decode the payload of a JWT token 100 * 101 * Does not validate expiration or signature 102 * 103 * @link https://www.converticacommerce.com/support-maintenance/security/php-one-liner-decode-jwt-json-web-tokens/ 104 * @param $jwt 105 * @return array 106 */ 107 protected function decodeJWT($jwt) 108 { 109 return json_decode(base64_decode(str_replace('_', '/', str_replace('-', '+', explode('.', $jwt)[1]))), true); 110 } 111 112} 113