diff --git a/README.md b/README.md index e9c861c4fb5e36b19df5df12413a1f5fa64becff..c3e8d716c1884045fcd765ad1e590305c2bca35b 100644 --- a/README.md +++ b/README.md @@ -24,7 +24,7 @@ https://www.oidplus.com/ Download a TAR.GZ file here: https://www.viathinksoft.com/projects/oidplus ### System requirements -- PHP compatible web server (tested with Apache 2, nginx and Microsoft IIS) +- PHP compatible web server (tested with Apache 2, nginx, and Microsoft IIS) - PHP 7.0 or higher (tested till PHP version 8.2 inclusive) with extension MySQLi, PostgreSQL, SQLite3, PDO, OCI8, or ODBC, depending on your database - Supported databases: diff --git a/TODO b/TODO index 103fe121616a918776aa725be6ee28f367d7cb15..0a5045cd5dbf22ce0c56dbb16333a10431cf60a4 100644 --- a/TODO +++ b/TODO @@ -3,7 +3,7 @@ April 2023 planned: - Don't send information object OIDs to oid-info.com anymore - https://github.com/danielmarschall/oidplus/issues/5 => "Offline mode" (do not contact internet, e.g. gs1-barcodes, polyfill, oidinfo, ...) - Everywhere where url_post_contents() is used, we need to check url_post_contents_available() too -- Attachments plugin: Via "notifications", let the admin know if the upload directory is writeable + Maybe also url_get_contents_available() which can either return bool or raise an Exception with the requirements (e.g. "CURL is missing" or "OIDplus is in offline mode") Type safety: - PhpStorm warnings diff --git a/includes/functions.inc.php b/includes/functions.inc.php index dbed65ac1edf4314ec33a8d9db9c5e54b2098af1..070689546fb6b802561a892b0a9728dfd6a476e4 100644 --- a/includes/functions.inc.php +++ b/includes/functions.inc.php @@ -479,3 +479,78 @@ function stdobj_to_array(\stdClass $obj): array { } return $ary; } + +/** + * @return string|false + */ +function get_own_username() { + $current_user = exec('whoami'); + if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') { + try { + if (function_exists('mb_convert_encoding')) { + $current_user = @mb_convert_encoding($current_user, "UTF-8", "cp850"); + } else if (function_exists('iconv')) { + $current_user = @iconv("cp850", "UTF-8", $current_user); + } + } catch (\Exception $e) {} + if (function_exists('mb_strtoupper')) { + $current_user = mb_strtoupper($current_user); // just cosmetics + } + } + if (!$current_user) { + if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') { + // Windows on an IIS server: + // getenv('USERNAME') MARSCHALL$ (That is the "machine account", see https://docs.microsoft.com/en-us/iis/manage/configuring-security/application-pool-identities#accessing-the-network ) + // get_current_user() DefaultAppPool + // exec('whoami') iis apppool\defaultapppool + // Windows with XAMPP: + // getenv('USERNAME') dmarschall + // get_current_user() dmarschall (even if script has a different NTFS owner!) + // exec('whoami') hickelsoft\dmarschall + $current_user = get_current_user(); + if (!$current_user) { + $current_user = getenv('USERNAME'); + $current_user = mb_strtoupper($current_user); // just cosmetics + } + } else { + // On Linux: + $current_user = exec('id -un'); + if (!$current_user) { + // PHP'S get_current_user() will get the owner of the PHP script, not the process owner! + // We want the process owner, so we use posix_geteuid() preferably. + if (function_exists('posix_geteuid')) { + $uid = posix_geteuid(); + } else { + $temp_file = tempnam(sys_get_temp_dir(), 'TMP'); + if ($temp_file !== false) { + $uid = fileowner($temp_file); + if ($uid === false) $uid = -1; + @unlink($temp_file); + } else { + $uid = -1; + } + } + if ($uid >= 0) { + $current_user = '#' . $uid; + if (function_exists('posix_getpwuid')) { + $userinfo = posix_getpwuid($uid); // receive username from the UID (requires read access to /etc/passwd) + if ($userinfo !== false) $current_user = $userinfo['name']; + } + } else { + $current_user = get_current_user(); + } + } + } + } + return $current_user ?: false; +} + +/** + * @param string $path + * @return bool + */ +function isFileOrPathWritable(string $path): bool { + if ($writable_file = (file_exists($path) && is_writable($path))) return true; + if ($writable_directory = (!file_exists($path) && is_writable(dirname($path)))) return true; + return false; +} \ No newline at end of file diff --git a/plugins/viathinksoft/adminPages/010_notifications/INTF_OID_1_3_6_1_4_1_37476_2_5_2_3_8.class.php b/plugins/viathinksoft/adminPages/010_notifications/INTF_OID_1_3_6_1_4_1_37476_2_5_2_3_8.class.php index d3541a7b03e111ecef13af58fe956a74559e1a45..fd77366bf837c2cfe56cc717d11db79617b139ba 100644 --- a/plugins/viathinksoft/adminPages/010_notifications/INTF_OID_1_3_6_1_4_1_37476_2_5_2_3_8.class.php +++ b/plugins/viathinksoft/adminPages/010_notifications/INTF_OID_1_3_6_1_4_1_37476_2_5_2_3_8.class.php @@ -27,7 +27,7 @@ interface INTF_OID_1_3_6_1_4_1_37476_2_5_2_3_8 { /** * @param string|null $user - * @return array returns array of array($severity, $htmlMessage) + * @return array returns array of array($severity, $htmlMessage) where severity can be OK|INFO|WARN|ERR|CRIT. */ public function getNotifications(string $user=null): array; diff --git a/plugins/viathinksoft/adminPages/010_notifications/OIDplusPageAdminNotifications.class.php b/plugins/viathinksoft/adminPages/010_notifications/OIDplusPageAdminNotifications.class.php index 9e5be909762226af855541276c1b29b7846c5f71..51c93e45dcc48c0c49df8b571d772dd052159970 100644 --- a/plugins/viathinksoft/adminPages/010_notifications/OIDplusPageAdminNotifications.class.php +++ b/plugins/viathinksoft/adminPages/010_notifications/OIDplusPageAdminNotifications.class.php @@ -110,7 +110,7 @@ class OIDplusPageAdminNotifications extends OIDplusPagePluginAdmin else if ($severity == 3) $sev_hf = _L('Warnings'); else if ($severity == 4) $sev_hf = _L('Errors'); else if ($severity == 5) $sev_hf = _L('Critical issues'); - else $sev_hf = _L('Severity %1', $severity-1); + else $sev_hf = _L('Severity %1', $severity-1); // TODO: actually, this should raise an Exception? $out['text'] .= '<h2><span class="severity_'.$severity.'">'.$sev_hf.' ('.count($htmlMessages).')</span></h2>'; $out['text'] .= '<span class="severity_'.$severity.'"><ol>'; @@ -226,8 +226,11 @@ class OIDplusPageAdminNotifications extends OIDplusPagePluginAdmin } // Check if cache directory is writeable - if (!is_writeable(OIDplus::localpath(null).'userdata/cache/')) { - $notifications[] = array('ERR', _L('Directory %1 is not writeable. Please check the permissions!', 'userdata/cache/')); + $cache_dir = OIDplus::localpath(null).'userdata/cache/'; + if (!is_dir($cache_dir)) { + $notifications[] = array('ERR', _L('Directory %1 does not exist', $cache_dir)); + } else if (!isFileOrPathWritable($cache_dir)) { + $notifications[] = array('ERR', _L('Directory %1 is not writeable. Please check the permissions!', $cache_dir)); } } return $notifications; diff --git a/plugins/viathinksoft/adminPages/111_systeminfo/OIDplusPageAdminSysteminfo.class.php b/plugins/viathinksoft/adminPages/111_systeminfo/OIDplusPageAdminSysteminfo.class.php index 798300fcb293821c50e6053dbe1112ab6edb99b0..9c566b90a89987f6c8ba40efc26d3f396db50609 100644 --- a/plugins/viathinksoft/adminPages/111_systeminfo/OIDplusPageAdminSysteminfo.class.php +++ b/plugins/viathinksoft/adminPages/111_systeminfo/OIDplusPageAdminSysteminfo.class.php @@ -248,50 +248,8 @@ class OIDplusPageAdminSysteminfo extends OIDplusPagePluginAdmin { $out['text'] .= ' </tr>'; $out['text'] .= ' <tr>'; $out['text'] .= ' <td>'._L('User account').'</td>'; - $current_user = exec('whoami'); - if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') { - try { - if (function_exists('mb_convert_encoding')) { - $current_user = @mb_convert_encoding($current_user, "UTF-8", "cp850"); - } else if (function_exists('iconv')) { - $current_user = @iconv("cp850", "UTF-8", $current_user); - } - } catch (\Exception $e) {} - if (function_exists('mb_strtoupper')) { - $current_user = mb_strtoupper($current_user); // just cosmetics - } - } - if ($current_user == '') { - if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') { - // Windows on an IIS server: - // getenv('USERNAME') MARSCHALL$ (That is the "machine account", see https://docs.microsoft.com/en-us/iis/manage/configuring-security/application-pool-identities#accessing-the-network ) - // get_current_user() DefaultAppPool - // exec('whoami') iis apppool\defaultapppool - // Windows with XAMPP: - // getenv('USERNAME') dmarschall - // get_current_user() dmarschall (even if script has a different NTFS owner!) - // exec('whoami') hickelsoft\dmarschall - $current_user = get_current_user(); - if ($current_user == '') $current_user = getenv('USERNAME'); - } else { - // On Linux: - $current_user = exec('id -un'); - if ($current_user == '') { - // get_current_user() will get the owner of the PHP script, not the process owner! - // We want the process owner, so we use posix_geteuid(). - if (function_exists('posix_geteuid') && function_exists('posix_getpwuid')) { - $uid = posix_geteuid(); - $current_user = posix_getpwuid($uid); // receive username (required read access to /etc/passwd ) - if ($current_user !== false) $current_user = $current_user['name']; - } else { - $uid = -1; - } - if ($current_user == '') $current_user = get_current_user(); - if (($current_user == '') && ($uid >= 0)) $current_user = '#' . $uid; - } - } - } - $out['text'] .= ' <td>'.($current_user == '' ? '<i>'._L('unknown').'</i>' : htmlentities($current_user)).'</td>'; + $current_user = get_own_username(); + $out['text'] .= ' <td>'.($current_user === false ? '<i>'._L('unknown').'</i>' : htmlentities($current_user)).'</td>'; $out['text'] .= ' </tr>'; $out['text'] .= '</tbody>'; $out['text'] .= '</table>'; diff --git a/plugins/viathinksoft/adminPages/900_software_update/OIDplusPageAdminSoftwareUpdate.class.php b/plugins/viathinksoft/adminPages/900_software_update/OIDplusPageAdminSoftwareUpdate.class.php index 830e91533d87d60a3596abe4f3ab55b3f96d0756..10e2bd5fbfcfb98a299c452fc0ebdc4ca28cc857 100644 --- a/plugins/viathinksoft/adminPages/900_software_update/OIDplusPageAdminSoftwareUpdate.class.php +++ b/plugins/viathinksoft/adminPages/900_software_update/OIDplusPageAdminSoftwareUpdate.class.php @@ -141,7 +141,7 @@ class OIDplusPageAdminSoftwareUpdate extends OIDplusPagePluginAdmin } - // All OK! Now write file + // All OK! Now write the file $tmp_filename = 'update_'.generateRandomString(10).'.tmp.php'; $local_file = OIDplus::localpath().$tmp_filename; diff --git a/plugins/viathinksoft/language/dede/messages.xml b/plugins/viathinksoft/language/dede/messages.xml index c5ccb6a3b6b7dcbc94d90ac2368633047aed355e..fbda4b68010ef899517cc95e40842bc5ab0be539 100644 --- a/plugins/viathinksoft/language/dede/messages.xml +++ b/plugins/viathinksoft/language/dede/messages.xml @@ -1812,6 +1812,14 @@ Digital Object Identifier (DOI) ]]></target> </message> + <message> + <source><![CDATA[ + Directory %1 does not exist + ]]></source> + <target><![CDATA[ + Verzeichnis %1 existiert nicht + ]]></target> + </message> <message> <source><![CDATA[ Directory %1 is not writeable. Please check the permissions! @@ -6892,6 +6900,14 @@ Die E-Mail-Adresse %1 wurde nicht bestätigt. Bitte bestätigen Sie sie zuerst! ]]></target> </message> + <message> + <source><![CDATA[ + The file attachments feature is not available due to a misconfiguration + ]]></source> + <target><![CDATA[ + Datei-Anhänge sind aufgrund einer Fehlkonfiguration nicht möglich + ]]></target> + </message> <message> <source><![CDATA[ The file does not exist diff --git a/plugins/viathinksoft/publicPages/095_attachments/OIDplusPagePublicAttachments.class.php b/plugins/viathinksoft/publicPages/095_attachments/OIDplusPagePublicAttachments.class.php index 73cdf770fa9dee6dbf16f19714e01c7d67ae1d5f..ecfd0fa89b197f09f1ad784303cdcc97fc449497 100644 --- a/plugins/viathinksoft/publicPages/095_attachments/OIDplusPagePublicAttachments.class.php +++ b/plugins/viathinksoft/publicPages/095_attachments/OIDplusPagePublicAttachments.class.php @@ -26,7 +26,8 @@ namespace ViaThinkSoft\OIDplus; class OIDplusPagePublicAttachments extends OIDplusPagePluginPublic implements INTF_OID_1_3_6_1_4_1_37476_2_5_2_3_2, /* modifyContent */ INTF_OID_1_3_6_1_4_1_37476_2_5_2_3_3, /* beforeObject*, afterObject* */ - INTF_OID_1_3_6_1_4_1_37476_2_5_2_3_4 /* whois*Attributes */ + INTF_OID_1_3_6_1_4_1_37476_2_5_2_3_4, /* whois*Attributes */ + INTF_OID_1_3_6_1_4_1_37476_2_5_2_3_8 /* getNotifications */ { /** @@ -104,11 +105,10 @@ class OIDplusPagePublicAttachments extends OIDplusPagePluginPublic } /** - * @param string|null $id * @return string * @throws OIDplusException */ - public static function getUploadDir(string $id=null): string { + protected static function getUploadBaseDir(): string { // Get base path $cfg = OIDplus::config()->getValue('attachment_upload_dir', ''); $cfg = trim($cfg); @@ -117,6 +117,16 @@ class OIDplusPagePublicAttachments extends OIDplusPagePluginPublic } else { $basepath = $cfg; } + return $basepath; + } + + /** + * @param string|null $id + * @return string + * @throws OIDplusException + */ + public static function getUploadDir(string $id=null): string { + $basepath = self::getUploadBaseDir(); try { self::checkUploadDir($basepath); @@ -601,4 +611,34 @@ class OIDplusPagePublicAttachments extends OIDplusPagePluginPublic * @return void */ public function whoisRaAttributes(string $email, array &$out) {} + + /** + * Implements interface INTF_OID_1_3_6_1_4_1_37476_2_5_2_3_8 + * @param string|null $user + * @return array returns array of array($severity, $htmlMessage) + */ + public function getNotifications(string $user=null): array { + $notifications = array(); + if ((!$user || ($user == 'admin')) && OIDplus::authUtils()->isAdminLoggedIn()) { + $error = ''; + try { + $basepath = self::getUploadBaseDir(); + if (!is_dir($basepath)) { + throw new OIDplusException(_L('Directory %1 does not exist', $basepath)); + } else { + self::checkUploadDir($basepath); + if (!isFileOrPathWritable($basepath)) { + throw new OIDplusException(_L('Directory %1 is not writeable. Please check the permissions!', $basepath)); + } + } + } catch (\Exception $e) { + $error = _L('The file attachments feature is not available due to a misconfiguration'); + $error .= ': ' . $e->getMessage(); + } + if ($error) { + $notifications[] = array('WARN', $error); + } + } + return $notifications; + } }