diff options
-rw-r--r-- | doku.php | 2 | ||||
-rw-r--r-- | inc/infoutils.php | 15 | ||||
-rw-r--r-- | lib/plugins/authldap/lang/cs/settings.php | 3 | ||||
-rw-r--r-- | lib/plugins/config/lang/cs/lang.php | 6 | ||||
-rw-r--r-- | lib/plugins/extension/Extension.php | 4 | ||||
-rw-r--r-- | lib/plugins/extension/ExtensionApiResponse.php | 96 | ||||
-rw-r--r-- | lib/plugins/extension/lang/cs/lang.php | 39 | ||||
-rw-r--r-- | lib/plugins/extension/remote.php | 149 |
8 files changed, 294 insertions, 20 deletions
@@ -13,7 +13,7 @@ use dokuwiki\ChangeLog\PageChangeLog; use dokuwiki\Extension\Event; // update message version - always use a string to avoid localized floats! -$updateVersion = "56"; +$updateVersion = "57"; // xdebug_start_profiling(); diff --git a/inc/infoutils.php b/inc/infoutils.php index 6319b94d9..a25839282 100644 --- a/inc/infoutils.php +++ b/inc/infoutils.php @@ -184,7 +184,7 @@ function getRuntimeVersions() if (getenv('KUBERNETES_SERVICE_HOST')) { $data['container'] = 'Kubernetes'; - } elseif (file_exists('/.dockerenv')) { + } elseif (@file_exists('/.dockerenv')) { $data['container'] = 'Docker'; } @@ -199,14 +199,16 @@ function getRuntimeVersions() */ function getOsRelease() { + $reader = fn($file) => @parse_ini_string(preg_replace('/#.*$/m', '', file_get_contents($file))); + $osRelease = []; - if (file_exists('/etc/os-release')) { + if (@file_exists('/etc/os-release')) { // pretty much any common Linux distribution has this - $osRelease = parse_ini_file('/etc/os-release'); - } elseif (file_exists('/etc/synoinfo.conf') && file_exists('/etc/VERSION')) { + $osRelease = $reader('/etc/os-release'); + } elseif (@file_exists('/etc/synoinfo.conf') && @file_exists('/etc/VERSION')) { // Synology DSM has its own way - $synoInfo = parse_ini_file('/usr/lib/synoinfo.conf'); - $synoVersion = parse_ini_file('/etc/VERSION'); + $synoInfo = $reader('/etc/synoinfo.conf'); + $synoVersion = $reader('/etc/VERSION'); $osRelease['NAME'] = 'Synology DSM'; $osRelease['ID'] = 'synology'; $osRelease['ID_LIKE'] = 'linux'; @@ -218,6 +220,7 @@ function getOsRelease() return $osRelease; } + /** * Run a few sanity checks * diff --git a/lib/plugins/authldap/lang/cs/settings.php b/lib/plugins/authldap/lang/cs/settings.php index 1bdaf29ba..19d41507f 100644 --- a/lib/plugins/authldap/lang/cs/settings.php +++ b/lib/plugins/authldap/lang/cs/settings.php @@ -3,7 +3,7 @@ /** * @license GPL 2 (http://www.gnu.org/licenses/gpl.html) * - * @author Petr Kajzar <petr.kajzar@lf1.cuni.cz> + * @author Petr Kajzar <petr.kajzar@centrum.cz> * @author mkucera66 <mkucera66@seznam.cz> * @author Jaroslav Lichtblau <jlichtblau@seznam.cz> * @author Martin Růžička <martinr@post.cz> @@ -26,6 +26,7 @@ $lang['groupscope'] = 'Omezení rozsahu vyhledávání skupiny'; $lang['userkey'] = 'Atribut označující uživatelské jméno; musí být konzistetní s uživatelským filtrem.'; $lang['groupkey'] = 'Atribut členství uživatele ve skupinách (namísto standardních AD skupin), tj. skupina z oddělení nebo telefonní číslo'; $lang['modPass'] = 'Může být LDAP heslo změněno přes dokuwiki?'; +$lang['modPassPlain'] = 'Odesílat aktualizace hesel na server LDAP v prostém textu (namísto jejich zabezpečení nakonfigurovaným algoritmem před přenosem)?'; $lang['debug'] = 'Zobrazit dodatečné debugovací informace'; $lang['deref_o_0'] = 'LDAP_DEREF_NEVER'; $lang['deref_o_1'] = 'LDAP_DEREF_SEARCHING'; diff --git a/lib/plugins/config/lang/cs/lang.php b/lib/plugins/config/lang/cs/lang.php index 8e1241ed7..f23e7c4a3 100644 --- a/lib/plugins/config/lang/cs/lang.php +++ b/lib/plugins/config/lang/cs/lang.php @@ -3,8 +3,8 @@ /** * @license GPL 2 (http://www.gnu.org/licenses/gpl.html) * - * @author Martin Růžička <martinr@post.cz> * @author Petr Kajzar <petr.kajzar@centrum.cz> + * @author Martin Růžička <martinr@post.cz> * @author Aleksandr Selivanov <alexgearbox@yandex.ru> * @author Robert Surý <rsurycz@seznam.cz> * @author Martin Hořínek <hev@hev.cz> @@ -141,6 +141,7 @@ $lang['mailreturnpath'] = 'E-mailová adresa příjemce pro oznámení o $lang['mailprefix'] = 'Předpona předmětu e-mailu, která se bude používat pro automatické e-maily'; $lang['htmlmail'] = 'Posílat e-maily v HTML (hezčí ale větší). Při vypnutí budou posílány jen textové e-maily.'; $lang['dontlog'] = 'Zakázat protokolování pro tyto typy záznamů.'; +$lang['logretain'] = 'Kolik dní uchovávat protokoly.'; $lang['sitemap'] = 'Generovat Google sitemap (interval ve dnech)'; $lang['rss_type'] = 'Typ XML kanálu'; $lang['rss_linkto'] = 'XML kanál odkazuje na'; @@ -175,13 +176,14 @@ $lang['search_fragment_o_exact'] = 'přesný'; $lang['search_fragment_o_starts_with'] = 'začíná s'; $lang['search_fragment_o_ends_with'] = 'končí s'; $lang['search_fragment_o_contains'] = 'obsahuje'; -$lang['trustedproxy'] = 'Důvěřovat proxy serverům odpovídajícím tomuto regulárním výrazu ohledně skutečné IP adresy klienta, kterou hlásí. Výchozí hodnota odpovídá místním sítím. Ponechejte prázdné, pokud nechcete důvěřovat žádné proxy.'; $lang['_feature_flags'] = 'Feature flags'; $lang['defer_js'] = 'Odložit spuštění javascriptu až po zpracování HTML kódu stránky. Zlepšuje vnímanou rychlost načtení stránky, ale může narušit funkci některých zásuvných modulů.'; $lang['hidewarnings'] = 'Nezobrazovat žádná varování PHP. To může usnadnit přechod na PHP8+. Varování budou stále zaznamenána v protokolu chyb a měla by být hlášena.'; $lang['dnslookups'] = 'DokuWiki zjišťuje DNS jména pro vzdálené IP adresy uživatelů, kteří editují stránky. Pokud máte pomalý, nebo nefunkční DNS server, nebo nepotřebujete tuto funkci, tak tuto volbu zrušte.'; $lang['jquerycdn'] = 'Mají být skripty jQuery a jQuery UI načítány z CDN? Vzniknou tím další HTTP dotazy, ale soubory se mohou načíst rychleji a uživatelé je už mohou mít ve vyrovnávací paměti.'; +$lang['trustedproxies'] = 'Čárkou oddělený seznam důvěryhodných proxy serverů, ze kterých se načítá hlavička X-Forwarded-For. Každá položka v poli může být buď adresa IPv4 nebo IPv6, nebo rozsah IPv4 nebo IPv6 CIDR (např. 10.0.0.0/8). Pokud nechcete důvěřovat žádnému proxy serveru, ponechte prázdné pole.'; +$lang['realip'] = 'Důvěřovat záhlaví X-Real-IP. Tuto funkci povolte pouze v případě, že váš server tuto hlavičku zapisuje, jinak může dojít k jejímu podvržení.'; $lang['jquerycdn_o_0'] = 'Bez CDN, pouze lokální doručení'; $lang['jquerycdn_o_jquery'] = 'CDN na code.jquery.com'; $lang['jquerycdn_o_cdnjs'] = 'CDN na cdnjs.com'; diff --git a/lib/plugins/extension/Extension.php b/lib/plugins/extension/Extension.php index 763b348c2..6de7a92f6 100644 --- a/lib/plugins/extension/Extension.php +++ b/lib/plugins/extension/Extension.php @@ -507,7 +507,9 @@ class Extension { $last = $this->getManager()->getDownloadURL(); if (!$last) return false; - return $last !== $this->getDownloadURL(); + $url = $this->getDownloadURL(); + if (!$url) return false; + return $last !== $url; } /** diff --git a/lib/plugins/extension/ExtensionApiResponse.php b/lib/plugins/extension/ExtensionApiResponse.php new file mode 100644 index 000000000..c684e770f --- /dev/null +++ b/lib/plugins/extension/ExtensionApiResponse.php @@ -0,0 +1,96 @@ +<?php + +namespace dokuwiki\plugin\extension; + +use dokuwiki\Remote\Response\ApiResponse; + +class ExtensionApiResponse extends ApiResponse +{ + protected Extension $extension; + + /** @var string The type of this extension ("plugin" or "template") */ + public $type; + + /** @var string The id of this extension (templates are prefixed with "template") */ + public $id; + + /** @var string The base name of this extension */ + public $base; + + /** @var string The display name of this extension */ + public $name; + + /** @var string The installed version/date of this extension */ + public $version; + + /** @var string The author of this extension */ + public $author; + + /** @var string The description of this extension */ + public $description; + + /** @var bool Whether this extension is installed */ + public $isInstalled; + + /** @var bool Whether this extension is enabled */ + public $isEnabled; + + /** @var bool Whether an update is available */ + public $updateAvailable; + + /** @var bool Whether this extension is bundled with DokuWiki */ + public $isBundled; + + /** @var bool Whether this extension is under git control */ + public $isGitControlled; + + /** @var string[] Notices for this extension */ + public $notices; + + /** @var string Documentation URL for this extension */ + public $url; + + /** @var string[] The component types this plugin provides */ + public $componentTypes; + + /** @var string The last available remote update date */ + public $lastUpdate; + + /** @var string The download URL for this extension */ + public string $downloadURL; + + /** + * Constructor + * + * @param Extension $extension The extension to create the response for + */ + public function __construct(Extension $extension) + { + $this->extension = $extension; + $this->type = $extension->getType(); + $this->id = $extension->getId(); + $this->base = $extension->getBase(); + $this->name = $extension->getDisplayName(); + $this->version = $extension->getInstalledVersion(); + $this->author = $extension->getAuthor(); + $this->description = $extension->getDescription(); + $this->isInstalled = $extension->isInstalled(); + $this->isEnabled = $extension->isEnabled(); + $this->updateAvailable = $extension->isUpdateAvailable(); + $this->isBundled = $extension->isBundled(); + $this->isGitControlled = $extension->isGitControlled(); + $this->componentTypes = $extension->getComponentTypes(); + $this->lastUpdate = $extension->getLastUpdate(); + $this->url = $extension->getURL(); + $this->downloadURL = $extension->getDownloadURL(); + + // Add notices + $this->notices = array_merge(...array_values(Notice::list($extension))); + } + + /** @inheritdoc */ + public function __toString() + { + return $this->extension->getId(); + } +} diff --git a/lib/plugins/extension/lang/cs/lang.php b/lib/plugins/extension/lang/cs/lang.php index 3a1dc48ac..8cf586d5a 100644 --- a/lib/plugins/extension/lang/cs/lang.php +++ b/lib/plugins/extension/lang/cs/lang.php @@ -3,9 +3,9 @@ /** * @license GPL 2 (http://www.gnu.org/licenses/gpl.html) * + * @author Petr Kajzar <petr.kajzar@centrum.cz> * @author Tomáš Heger <heger.tomas@gmail.com> * @author Martin Růžička <martinr@post.cz> - * @author Petr Kajzar <petr.kajzar@lf1.cuni.cz> * @author Viktor Zavadil <vzavadil@newps.cz> * @author Jaroslav Lichtblau <jlichtblau@seznam.cz> * @author Turkislav <turkislav@blabla.com> @@ -16,9 +16,6 @@ $lang['tab_templates'] = 'Instalované šablony'; $lang['tab_search'] = 'Vyhledat a instalovat'; $lang['tab_install'] = 'Ruční instalace'; $lang['notimplemented'] = 'Tato vychytávka není dosud implementována'; -$lang['notinstalled'] = 'Toto rozšíření není instalováno'; -$lang['alreadyenabled'] = 'Toto rozšíření je již povoleno'; -$lang['alreadydisabled'] = 'Toto rozšíření je již vypnuto'; $lang['pluginlistsaveerror'] = 'Došlo k chybě při ukládání seznamu zásuvných modulů'; $lang['unknownauthor'] = 'Neznámý autor'; $lang['unknownversion'] = 'Neznámá verze'; @@ -34,6 +31,8 @@ $lang['js']['display_viewoptions'] = 'Zobrazit možnosti:'; $lang['js']['display_enabled'] = 'povolené'; $lang['js']['display_disabled'] = 'zakázané'; $lang['js']['display_updatable'] = 'aktualizovatelné'; +$lang['js']['close'] = 'Kliknutím zavřete'; +$lang['js']['filter'] = 'Zobrazit pouze aktualizovatelná rozšíření'; $lang['search_for'] = 'Hledat rozšíření:'; $lang['search'] = 'Hledat'; $lang['extensionby'] = '<strong>%s</strong> od %s'; @@ -72,23 +71,40 @@ $lang['msg_enabled'] = 'Zásuvný modul %s povolen'; $lang['msg_disabled'] = 'Zásuvný modul %s zakázán'; $lang['msg_delete_success'] = 'Rozšíření %s odinstalováno'; $lang['msg_delete_failed'] = 'Odinstalování rozšíření %s selhalo'; -$lang['msg_template_install_success'] = 'Šablona %s úspěšně nainstalována'; -$lang['msg_template_update_success'] = 'Šablona %s úspěšně aktualizována'; -$lang['msg_plugin_install_success'] = 'Zásuvný modul %s úspěšně nainstalován.'; -$lang['msg_plugin_update_success'] = 'Zásuvný modul %s úspěšně aktualizován.'; +$lang['msg_install_success'] = 'Rozšíření %s bylo úspěšně nainstalováno'; +$lang['msg_update_success'] = 'Rozšíření %s bylo úspěšně aktualizováno'; $lang['msg_upload_failed'] = 'Nahrávání souboru selhalo'; $lang['msg_nooverwrite'] = 'Rozšíření %s již existuje, proto nebylo přepsáno; pro přepsání zatrhněte příslušnou možnost'; $lang['missing_dependency'] = 'Chybějící nebo zakázaná závislost: %s'; +$lang['found_conflict'] = 'Toto rozšíření je označeno jako konfliktní s následujícími nainstalovanými rozšířeními: %s'; $lang['security_issue'] = 'Bezpečnostní problém: %s'; $lang['security_warning'] = 'Bezpečnostní varování: %s'; +$lang['update_message'] = 'Aktualizační zpráva: %s'; $lang['wrong_folder'] = 'Zásuvný modul nesprávně nainstalován: Přejmenujte adresář modulu "%s" na "%s".'; -$lang['url_change'] = "URL se změnila: URL pro stahování se změnila od poslední aktualizace. Před další aktualizací tohoto rozšíření ověřte správnost nové URL.\nNová: %s\nStará: %s"; +$lang['url_change'] = 'URL se změnila: URL pro stahování se změnila od poslední aktualizace. Před další aktualizací tohoto rozšíření ověřte správnost nové URL. +Nová: %s +Stará: %s'; $lang['error_badurl'] = 'Adresy URL by měly začínat s http nebo https'; $lang['error_dircreate'] = 'Nelze vytvořit dočasný adresář pro přijetí stahování'; $lang['error_download'] = 'Nelze stáhnout soubor: %s'; $lang['error_decompress'] = 'Selhalo rozbalení staženého souboru. Toto je nejspíš důsledek poškození souboru při přenosu, zkuste soubor stáhnout znovu; případně nemusel být rozpoznán formát sbaleného souboru a bude třeba přistoupit k ruční instalaci. '; $lang['error_findfolder'] = 'Nelze rozpoznat adresář pro rozšíření, je třeba stáhnout a instalovat ručně'; $lang['error_copy'] = 'Došlo k chybě kopírování souborů při pokusu nainstalovat soubory do adresáře <em>%s</em>: může být plný disk nebo špatně nastavena přístupová práva. Tato chyba mohla zapříčinit pouze částečnou instalaci zásuvného modulu a uvést wiki do nestabilního stavu.'; +$lang['error_copy_read'] = 'Nepodařilo se načíst adresář %s'; +$lang['error_copy_mkdir'] = 'Nepodařilo se vytvořit adresář %s'; +$lang['error_copy_copy'] = 'Nepodařilo se zkopírovat %s do %s'; +$lang['error_archive_read'] = 'Nepodařilo se otevřít archiv %s pro čtení'; +$lang['error_archive_extract'] = 'Nepodařilo se rozbalit archiv %s: %s'; +$lang['error_uninstall_protected'] = 'Rozšíření %s je chráněno a nelze jej odinstalovat'; +$lang['error_uninstall_dependants'] = 'Rozšíření %s je stále vyžadováno %s, a proto jej nelze odinstalovat'; +$lang['error_disable_protected'] = 'Rozšíření %s je chráněno a nelze jej zakázat'; +$lang['error_disable_dependants'] = 'Rozšíření %s je stále vyžadováno %s, a proto jej nelze zakázat'; +$lang['error_nourl'] = 'Pro rozšíření %s nebyla nalezena žádná adresa URL pro stahování'; +$lang['error_notinstalled'] = 'Rozšíření %s není nainstalováno'; +$lang['error_alreadyenabled'] = 'Rozšíření %s již bylo povoleno'; +$lang['error_alreadydisabled'] = 'Rozšíření %s již bylo zakázáno'; +$lang['error_minphp'] = 'Rozšíření %s vyžaduje alespoň PHP %s, ale tato wiki používá PHP %s.'; +$lang['error_maxphp'] = 'Rozšíření %s podporuje pouze PHP do %s, ale tato wiki používá PHP %s.'; $lang['noperms'] = 'Nelze zapisovat do adresáře pro rozšíření'; $lang['notplperms'] = 'Nelze zapisovat do odkládacího adresáře'; $lang['nopluginperms'] = 'Nelze zapisovat do adresáře se zásuvnými moduly'; @@ -96,5 +112,10 @@ $lang['git'] = 'Toto rozšíření bylo nainstalováno přes g $lang['auth'] = 'Tento ověřovací zásuvný modul není povolen v nastavení, zvažte jeho deaktivaci.'; $lang['install_url'] = 'Nainstalovat z URL:'; $lang['install_upload'] = 'Nahrát rozšíření:'; +$lang['repo_badresponse'] = 'Úložiště zásuvných modulů vrátilo neplatnou odpověď.'; $lang['repo_error'] = 'Nelze kontaktovat repozitář se zásuvnými moduly. Ujistěte se, že váš server může kontaktovat www.dokuwiki.org a zkontrolujte nastavení proxy.'; $lang['nossl'] = 'Použité PHP pravděpodobně nepodporuje SSL. Stažení mnoha DokuWiki rozšíření nebude fungovat.'; +$lang['popularity_high'] = 'Toto je jedno z nejoblíbenějších rozšíření'; +$lang['popularity_medium'] = 'Toto rozšíření je poměrně oblíbené'; +$lang['popularity_low'] = 'Toto rozšíření vzbudilo určitý zájem'; +$lang['details'] = 'Podrobnosti'; diff --git a/lib/plugins/extension/remote.php b/lib/plugins/extension/remote.php new file mode 100644 index 000000000..4eb84a829 --- /dev/null +++ b/lib/plugins/extension/remote.php @@ -0,0 +1,149 @@ +<?php + +use dokuwiki\Extension\RemotePlugin; +use dokuwiki\plugin\extension\Extension; +use dokuwiki\plugin\extension\ExtensionApiResponse; +use dokuwiki\plugin\extension\Installer; +use dokuwiki\plugin\extension\Local; +use dokuwiki\plugin\extension\Repository; +use dokuwiki\Remote\AccessDeniedException; + +/** + * DokuWiki Plugin extension (Remote Component) + * + * @license GPL 2 http://www.gnu.org/licenses/gpl-2.0.html + * @author Andreas Gohr <andi@splitbrain.org> + */ +class remote_plugin_extension extends RemotePlugin +{ + /** + * List installed extensions + * + * This lists all installed extensions. The list is not sorted in any way. + * + * @return ExtensionApiResponse[] The list of installed extensions and their details + */ + public function list() + { + if (!auth_isadmin()) { + throw new AccessDeniedException('Only admins are allowed to access extensions', 114); + } + + $extensions = (new Local())->getExtensions(); + Repository::getInstance()->initExtensions(array_keys($extensions)); + + return array_values( + array_map( + static fn($extension) => new ExtensionApiResponse($extension), + $extensions + ) + ); + } + + /** + * Search for extensions in the repository + * + * @param string $query The keyword(s) to search for + * @param int $max Maximum number of results (default 10) + * @return ExtensionApiResponse[] List of matching extensions + */ + public function search($query, $max = 10) + { + if (!auth_isadmin()) { + throw new AccessDeniedException('Only admins are allowed to access extensions', 114); + } + + $repo = Repository::getInstance(); + $result = $repo->searchExtensions($query); + + if ($max > 0) { + $result = array_slice($result, 0, $max); + } + + return array_values( + array_map( + static fn($extension) => new ExtensionApiResponse($extension), + $result + ) + ); + } + + /** + * Enable a specific extension + * + * @param string $extension Extension ID to enable + * @return bool Success status + */ + public function enable($extension) + { + if (!auth_isadmin()) { + throw new AccessDeniedException('Only admins are allowed to manage extensions', 114); + } + + $ext = Extension::createFromId($extension); + $ext->enable(); + return true; + } + + /** + * Disable a specific extension + * + * @param string $extension Extension ID to disable + * @return bool Success status + */ + public function disable($extension) + { + if (!auth_isadmin()) { + throw new AccessDeniedException('Only admins are allowed to manage extensions', 114); + } + + $ext = Extension::createFromId($extension); + $ext->disable(); + return true; + } + + /** + * Install a specific extension + * + * This will also install dependencies, so more than the given extension may be installed. + * + * @param string $extension Extension ID or download URL + * @return string[] List of installed extensions + */ + public function install($extension) + { + if (!auth_isadmin()) { + throw new AccessDeniedException('Only admins are allowed to manage extensions', 114); + } + + $installer = new Installer(true); + $installer->installFromId($extension); + + return array_keys( + array_filter( + $installer->getProcessed(), + static fn($status) => ( + $status == Installer::STATUS_INSTALLED || $status == Installer::STATUS_UPDATED + ) + ) + ); + } + + /** + * Uninstall a specific extension + * + * @param string $extension Extension ID to uninstall + * @return bool Success status + */ + public function uninstall($extension) + { + if (!auth_isadmin()) { + throw new AccessDeniedException('Only admins are allowed to manage extensions', 114); + } + + $ext = Extension::createFromId($extension); + $installer = new Installer(); + $installer->uninstall($ext); + return true; + } +} |