code.fastix.org

Dateiansicht:

Datei:Projekte -> Apache,PHP:htpasswd -> htpasswd.php
md5:93cb38be52001cd9a322d244175688c8
sha1:118b82df0a8624813313722012005dd16c718291
Download-Link:Download
  1. <?php
  2.  
  3. /**
  4. * @author: Jörg Reinholz, fastix WebDesign & Consult, Kassel - http://www.fastix.org/
  5. * @version: 4.3
  6. * @encoding: UTF-8
  7. **/
  8. declare( strict_types=1 );
  9.  
  10. ### Konfiguration: #####################################################
  11.  
  12. ## Bezeichnung für den gesicherten Bereich Ihrer Webseite.
  13. # Dieses ist für die Benutzer lesbar und wird beim Login angezeigt.
  14. # Browser verwenden diese für Auswahl gespeicherter Zugangsdaten und speichern
  15. # diese Information also.
  16.  
  17. #original: define( 'USER_DEFINED_AUTHNAME', 'Geschlossener Bereich' );
  18. define( 'USER_DEFINED_AUTHNAME', 'Geschlossener Bereich' );
  19.  
  20.  
  21. ## Wohin soll das Userfile gespeichert werden?
  22. # Optimal ist ein Verzeichnis außerhalb des Webrootes
  23.  
  24. #original: define( 'USER_DEFINED_USERFILE', '/Verzeichnis/von/.htpasswd' );
  25. #example:  define( 'USER_DEFINED_USERFILE', __DIR__ . '/.htpasswd' );
  26. define( 'USER_DEFINED_USERFILE', '/Verzeichnis/von/.htpasswd' );
  27.  
  28. ## Welche(r) Benutzer darf diese Benutzerverwaltung aufrufen?
  29. # Wenn Sie einen leeren String eintragen, dann darf JEDER Benutzer verwalten
  30. # und die Authentifizierung abschalten.
  31. # Komma-separierte Liste. Leerzeichen vor und nach den Namen werden ignoriert.
  32.  
  33. #original: define( 'USER_DEFINED_ADMINS', 'root' );
  34. #example:  define( 'USER_DEFINED_ADMINS', 'root,admin, usermin' );
  35. define( 'USER_DEFINED_ADMINS', 'root' );
  36.  
  37. ## Die folgende Einstellung ist auf einem Apache Webserver
  38. ## normalerweise so vorkonfiguriert. Ändern sie diese,
  39. ## dann wird das Skript zwar funktionieren - aber der
  40. ## Webserver wird Ihre Einstellungen ignorieren:
  41.  
  42. #original: define( 'USER_DEFINED_HTACCESSFILE', __DIR__ . '/.htaccess' );
  43. #example( 'USER_DEFINED_HTACCESSFILE', '/foo/bar/.htaccess' );
  44. define( 'USER_DEFINED_HTACCESSFILE', __DIR__ . '/.htaccess' );
  45.  
  46. ## Mindestlänge für neue Passwörter:
  47.  
  48. #original: define( 'USER_DEFINED_MIN_PASSWORD_SIZE', 8 );
  49. define( 'USER_DEFINED_MIN_PASSWORD_SIZE', 8 );
  50.  
  51.  
  52. ## Mindestlänge für neue Benutzernamen: (Minimum: 1)
  53.  
  54. #original: define( 'USER_DEFINED_MIN_USERNAME_SIZE', 3 );
  55. define( 'USER_DEFINED_MIN_USERNAME_SIZE', 3 );
  56.  
  57.  
  58. ## Um das GEFÄHRLICHE Vorgehen zu erlauben, dass die Benutzernamen und Passwörter auch bei einer
  59. ## unverschlüsselten Verbindung  (kein HTTPS) auf einen entfernten Server (Nicht:localhost, 127.x.x.x)
  60. ## übertragen werden, geben Sie hier ZEICHENGENAU 'Ja! Passwoerter unverschluesselt uebertragen' ein:
  61.  
  62. #original: define( 'USER_ALLOW_UNSAFE_TRANSPORT', 'No' );
  63. define( 'USER_ALLOW_UNSAFE_TRANSPORT', 'No' );
  64.  
  65. ## Um das GEFÄHRLICHE Vorgehen zu erlauben, dass Konfiguationsfehler angezeigt werden, geben
  66. ## Sie hier true (Ohne Anführunsstriche) an:
  67.  
  68. #original: define( 'USER_SHOW_CONFIG_ERRORS', false );
  69. #example: define( 'USER_SHOW_CONFIG_ERRORS', true );
  70. define( 'USER_SHOW_CONFIG_ERRORS', false );
  71.  
  72. ## Geben Sie hier die erwartete URL des Skriptes an.
  73. # Wenn Sie z.B. 'http://localhost/htpasswd-test/htpasswd.php' erwarten, dann genau diese:
  74.  
  75. #original: define( 'USER_EXPECTED_REFERER', 'http://localhost/htpasswd-test/htpasswd.php' );
  76. define( 'USER_EXPECTED_REFERER', 'http://localhost/htpasswd-test/htpasswd.php' );
  77.  
  78. ## Geben Sie hier eine gültige CSS-Farbangabe für Alarmmeldungen an:
  79.  
  80. #original: define( 'USER_ALARM_COLOR', '#a00000' );
  81. define( 'USER_ALARM_COLOR', '#a00000' );
  82.  
  83.  
  84. ## Geben Sie hier eine gültige CSS-Farbangabe für OK-Meldungen an:
  85. #original: define( 'USER_OK_COLOR', '#008000' );
  86. define( 'USER_OK_COLOR', '#008000' );
  87.  
  88. ## Geben Sie hier ZEICHENGENAU 'Ja! Alles ueberprueft' an, wenn Sie die Konfiguration bearbeitet haben:
  89.  
  90. #original: define( 'YES_I_HAVE_THE_CONFIG_EDITED_AND_CHECKED', 'No' );
  91. define( 'YES_I_HAVE_THE_CONFIG_EDITED_AND_CHECKED', 'No' );
  92.  
  93. ########################################################################
  94. #                                                                      #
  95. #     Definitionen, die nur erfahrene Programmierer verändern:         #
  96. #                                                                      #
  97. ########################################################################
  98.  
  99. error_reporting( E_ALL );
  100. ini_set( 'display_errors', '0' );
  101.  
  102. define( 'FTX_PHP_MIN_VERSION',    7.0 );
  103. define( 'FTX_APACHE_MIN_VERSION', 2.4 );
  104. define( 'FTX_BCRYPT_COST', 'auto' ); #integer ( 5 .. 16 ) or 'auto' Hints: Apache 2.4-Default is 5; PHP-7.4-Max is 16! @PHP-7.4-Default is 10 ;
  105. define( 'FTX_NONCE_SCRIPT', bin2hex( random_bytes( 12 ) ) ) ;
  106. define( 'FTX_NONCE_STYLE' , bin2hex( random_bytes( 12 ) ) ) ;
  107. define( 'FTX_CONTENT_SECURITY_POLICY', 'default-src \'none\'; style-src \'nonce-' . FTX_NONCE_STYLE . '\'; script-src \'nonce-' . FTX_NONCE_SCRIPT . '\'; img-src data:; form-action \'self\'; base-uri \'self\'' );
  108. define( 'FTX_STS_TIME', ( 1 * 24 * 60 * 60 ) ); # +1 Tag nur per https
  109.  
  110. # Das Favicon:
  111. define( 'FTX_FAVICON_MIME_TYPE',  'image/gif' );
  112. define( 'FTX_FAVICON_BASE64'   ,'R0lGODlhEAAQAOMHAAAAAAgICBUVFc/Pz9DQ0NjY2Ofn5////////////////////////////////////yH5BAEKAAgALAAAAAAQABAAAAQd8MhJq704600H4JIHHiJIfGARjIYwviTKlXBtTxEAOw==');
  113.  
  114.  
  115. # Disable all caches:
  116. header( 'Cache-Control: max-age=0' );
  117. header( 'Cache-Control: no-cache' );
  118. header( 'Pragma: no-cache' );
  119.  
  120. # Safety-Vodoo
  121. header( 'X-XSS-Protection: 1; mode=block' );
  122. header( 'X-Frame-Options: deny' );
  123. header( 'Origin: ' . $_SERVER['REQUEST_SCHEME'] . '://' . $_SERVER['HTTP_HOST'] );
  124. header( 'Access-Control-Allow-Origin: ' . $_SERVER['REQUEST_SCHEME'] . '://' . $_SERVER['HTTP_HOST'] );
  125. header( 'Content-Security-Policy: '    . FTX_CONTENT_SECURITY_POLICY );
  126. header( 'X-Content-Security-Policy: '  . FTX_CONTENT_SECURITY_POLICY );
  127. header( 'X-WebKit-CSP: '               . FTX_CONTENT_SECURITY_POLICY );
  128. header( 'Referrer-Policy: strict-origin-when-cross-origin');
  129.  
  130. if ( realpath( __FILE__ ) !== realpath( $_SERVER['SCRIPT_FILENAME'] ) ) {
  131.         EXIT_ON_CONFIG_ERROR( 'Versuch, ' . __FILE__ . 'includiert auszuführen' );
  132. }
  133.  
  134.  
  135. if ( isset( $_SERVER['PHP_AUTH_USER'] ) ) {
  136.         $access_denied = false;
  137.         $admins = explode(',', USER_DEFINED_ADMINS );
  138.         if ( count( $admins ) ) {
  139.                 $access_denied = true;
  140.                 foreach ( $admins as $admin ) {
  141.                         if ( trim($admin) == $_SERVER['PHP_AUTH_USER'] ) {
  142.                                 $access_denied = false;
  143.                         }
  144.                 }
  145.         }
  146.     if ( $access_denied ) {
  147.                 EXIT_ON_CONFIG_ERROR('Fatal: Der Benutzer ' . $_SERVER['PHP_AUTH_USER'] . ' darf dieses Skript nicht aufrufen.' );
  148.         }
  149. }
  150.  
  151. if ( YES_I_HAVE_THE_CONFIG_EDITED_AND_CHECKED != 'Ja! Alles ueberprueft' ) {
  152.         header ( 'Content-Type: text/plain; charset=utf-8' );
  153.         EXIT_ON_CONFIG_ERROR('Bitte lesen und bearbeiten Sie zunächst die Konfiguration dieses Skriptes!' );
  154. }
  155.  
  156. if (
  157.            ( isset ( $_SERVER['REQUEST_SCHEME'] ) and 'https' == $_SERVER['REQUEST_SCHEME'] )
  158.     or ( isset ( $_SERVER['HTTPS'] ) and 'on' == $_SERVER['HTTPS'] )
  159. ) {
  160.         header( 'Strict-Transport-Security: max-age=' . FTX_STS_TIME );
  161.         define( 'FTX_COOKIE_RESTRICTIONS', 'SameSite=Strict; secure'  );
  162. } elseif (
  163.                 '127.' != substr( $_SERVER['REMOTE_ADDR'], 0, 4 )
  164.         and USER_ALLOW_UNSAFE_TRANSPORT != 'Ja! Passwoerter unverschluesselt uebertragen'
  165. ) {
  166.         header ( 'Content-Type: text/plain; charset=utf-8' );
  167.         EXIT_ON_CONFIG_ERROR( 'Die Konfiguration darf nur mit SSL/TLS (via HTTPS erfolgen)!' );
  168. } else {
  169.         #Unsichere Verbindung
  170.         define( 'FTX_COOKIE_RESTRICTIONS', 'SameSite=Strict'  );
  171. }
  172.  
  173. if ( function_exists( 'apache_get_version' ) ) {
  174.         $apacheVersion = apache_get_version();
  175.         $apacheVersion = preg_replace( '/[^0-9.]/', '', $apacheVersion );
  176.         $apacheVersion = (float) preg_replace('/^([0-9]+\.[0-9]+).*/','$1', $apacheVersion );
  177. } else {
  178.         $apacheVersion = false;
  179. }
  180.  
  181. if ( FTX_APACHE_MIN_VERSION > $apacheVersion ) {
  182.         if ( false === $apacheVersion ) $apacheVersion = 'unbekanntem Webserver';
  183.         header ( 'Content-Type: text/plain; charset=utf-8' );
  184.         EXIT_ON_CONFIG_ERROR( 'Auf einer Maschine mit ' . $apacheVersion . ' wird der Dienst zuverlässig verweigert.' );
  185. }
  186.  
  187. if (
  188.         ! defined( 'PHP_VERSION_ID' )
  189.         or PHP_VERSION_ID < ( FTX_PHP_MIN_VERSION * 10000 )
  190.         or ! function_exists( 'password_hash')
  191. ) {
  192.         header ( 'Content-Type: text/plain; charset=utf-8' );
  193.         EXIT_ON_CONFIG_ERROR( 'Auf einer Maschine mit einer völlig veralteten PHP-Version ' . phpversion() . ' wird der Dienst verweigert.' );
  194. }
  195.  
  196. if ( ! file_exists( USER_DEFINED_USERFILE ) ) {
  197.         touch ( USER_DEFINED_USERFILE );
  198. }
  199.  
  200. if ( ! file_exists( USER_DEFINED_HTACCESSFILE ) ) {
  201.         touch ( USER_DEFINED_HTACCESSFILE );
  202. }
  203.  
  204. if ( ! file_exists( USER_DEFINED_USERFILE ) ) {
  205.         header ( 'Content-Type: text/plain; charset=utf-8' );
  206.         EXIT_ON_CONFIG_ERROR( 'Fatal: Die Datei "' . USER_DEFINED_USERFILE . '" konnte nicht angelegt werden. Überprüfen Sie, ob der Webserver Schreibrechte am Verzeichnis "' . dirname($_SERVER['SCRIPT_FILENAME']) . '" hat.' );
  207. }
  208.  
  209. if ( ! file_exists( USER_DEFINED_HTACCESSFILE ) ) {
  210.         header ( 'Content-Type: text/plain; charset=utf-8' );
  211.         EXIT_ON_CONFIG_ERROR( 'Fatal: Die Datei "'.USER_DEFINED_HTACCESSFILE .'" konnte nicht angelegt werden. Überprüfen Sie, ob der Webserver Schreibrechte am Verzeichnis "' . dirname($_SERVER['SCRIPT_FILENAME']) . '" hat.' );
  212. }
  213.  
  214. if ( ! is_readable( USER_DEFINED_USERFILE ) ) {
  215.         header ( 'Content-Type: text/plain; charset=utf-8' );
  216.         EXIT_ON_CONFIG_ERROR( 'Fatal: Die Datei "' . USER_DEFINED_USERFILE . '" existiert, der Webserver hat aber keine Leserechte. (Lösung: Setzen mit "chmod 666 ' . USER_DEFINED_USERFILE . '"' );
  217. }
  218.  
  219. if ( ! is_readable( USER_DEFINED_HTACCESSFILE ) ) {
  220.         header ( 'Content-Type: text/plain; charset=utf-8' );
  221.         EXIT_ON_CONFIG_ERROR('Fatal: Die Datei "' . USER_DEFINED_HTACCESSFILE . '" existiert, der Webserver hat aber keine Leserechte. (Lösung: Setzen mit "chmod 666 '.USER_DEFINED_HTACCESSFILE.'"' );
  222. }
  223.  
  224. if ( ! is_writable( USER_DEFINED_USERFILE ) ) {
  225.         header ( 'Content-Type: text/plain; charset=utf-8' );  
  226.         EXIT_ON_CONFIG_ERROR('Fatal: Die Datei "' . USER_DEFINED_USERFILE . '" existiert, der Webserver hat aber keine Schreibrechte. (Lösung: Setzen mit "chmod 666 ' . USER_DEFINED_USERFILE . '"' );
  227. }
  228.  
  229. if ( ! is_writable( USER_DEFINED_HTACCESSFILE ) ) {
  230.         header ( 'Content-Type: text/plain; charset=utf-8' );
  231.         EXIT_ON_CONFIG_ERROR( 'Fatal: Die Datei "' . USER_DEFINED_HTACCESSFILE . '" existiert, der Webserver hat aber keine Schreibrechte. (Lösung: Setzen mit "chmod 666 ' . USER_DEFINED_HTACCESSFILE . '"' );
  232. }
  233.  
  234. $warnung = '';
  235.  
  236. if ( isset( $_POST['user'] ) && $_POST['user'] && isset( $_POST['pass'] ) && ( $_POST['pass'] ) ) {
  237.         $user = trim( $_POST['user'] );
  238.         $pass = trim( $_POST['pass'] );
  239.        
  240.         if ( USER_DEFINED_MIN_PASSWORD_SIZE > strlen( $pass ) ) {
  241.                 $warnung = 'alert( "Der Benutzer „' . trim( json_encode($user), '"') . '“ wurde nicht angelegt.\nGrund: Das Passwort ist zu kurz.\n\nDie Mindestlänge beträgt ' . USER_DEFINED_MIN_PASSWORD_SIZE . ' Zeichen." );';              
  242.         } elseif (! AddUser( $user, $pass ) ) {
  243.                 $warnung = 'alert("Der Benutzer „' . trim( json_encode($user), '"') . '“ wurde nicht angelegt.\n(Enthält der Benutzername unzulässige Zeichen?\nErlaubt sind Buchstaben, Ziffern, der Punkt, das Minus und der Unterstrich.)")';
  244.         } else {
  245.                 $warnung = 'alert( "Der Benutzer „' . trim( json_encode($user), '"') . '“ wurde angelegt oder geändert." )';
  246.         }
  247. }
  248.  
  249. if ( isset( $_COOKIE['userToDelete'] ) and trim( $_COOKIE['userToDelete'] ) ) {
  250.  
  251.         $strUser = trim( $_COOKIE['userToDelete'] );
  252.         setcookie( 'userToDelete', '', time() - 1, '', '', true );
  253.         if (
  254.                 ! CheckHtaccess( USER_DEFINED_HTACCESSFILE )
  255.                 or (
  256.                         isset( $_SERVER['PHP_AUTH_USER'] )
  257.                         and $strUser != $_SERVER['PHP_AUTH_USER']
  258.                 )
  259.         ) {
  260.                 RemoveUser( $strUser );
  261.         } else {
  262.                 $warnung = 'alert( "Sie können sich selbst nicht löschen! Sie können aber Ihr Passwort ändern." );';
  263.         }
  264. }
  265.  
  266. if ( isset( $_POST['Ein'] ) && $_POST['Ein'] ) {
  267.  
  268.         $arUsers = GetUserArray();
  269.         if ( isset( $arUsers[0] )  && $arUsers[0] ) {
  270.                 AddToHtaccess();
  271.                 header( 'Location: ' . $_SERVER['REQUEST_URI'] );
  272.                 exit;
  273.         } else {
  274.                 $warnung = 'alert( "Der Schutz kann nicht aktiviert werden, weil (noch) keine Benutzer existieren. Legen Sie mindestens einen Benutzer an." );';
  275.  
  276.         }
  277. }
  278.  
  279. if ( isset( $_POST['Aus'] ) && $_POST['Aus'] ) {
  280.         DelFromHtaccess();
  281. }
  282.  
  283. if ( CheckHtaccess() ) {
  284.         $strSchutz = '<span class="status_ok">Gesichert:<br>Der Verzeichnisschutz ist eingeschaltet.</span>';
  285.         $strShowEinbutton = 'none';
  286.         $strShowAusbutton = 'inline';
  287.         $status_color     = USER_OK_COLOR;
  288. } else {
  289.         $strSchutz = '<span class="status_alarm">ACHTUNG!<br>Der Verzeichnisschutz ist ausgeschaltet.</span>';
  290.         $strShowEinbutton = 'inline';
  291.         $strShowAusbutton = 'none';
  292.         $status_color     = USER_ALARM_COLOR;
  293. }
  294.  
  295. /*
  296. *       Funktionen *********************************************************
  297. */
  298.  
  299. function GetUserArray() {
  300.         $users = array();
  301.         $arLines = file( USER_DEFINED_USERFILE );
  302.         foreach ( $arLines as $strLine ) {
  303.                 $parts = array();
  304.                 $parts = explode( ':', $strLine, 2 );
  305.                 $parts[0] = trim($parts[0] );
  306.                 if ( '' != $parts[0] ) {
  307.                         $users[] = $parts[0];
  308.                 }
  309.         }
  310.         $dummy = sort( $users );
  311.         return $users;
  312. }
  313.  
  314. function PrintUserList() {
  315.         $arUsers = GetUserArray();
  316.         echo '         <ul type="none">' . PHP_EOL;
  317.         foreach ( $arUsers as $strUser ) {
  318.                 $strUser = trim( $strUser );
  319.                 if (
  320.                         ! CheckHtaccess()
  321.                         or (
  322.                                 isset( $_SERVER['PHP_AUTH_USER'] )
  323.                                 and $strUser != $_SERVER['PHP_AUTH_USER']
  324.                         )
  325.                 ) {
  326.                         echo '                 <li class="deletable_user" title="Diesen Benutzer löschen ...">' . htmlspecialchars( $strUser, ENT_QUOTES ) . '</li>' . PHP_EOL;
  327.                 } else {
  328.                         echo '                 <li class="not_deletable_user"  title="Der aktuell angemeldete Benutzer ist nicht löschbar.">' . htmlspecialchars( $strUser, ENT_QUOTES ) . '</li>' . PHP_EOL;
  329.                 }
  330.         }
  331.         echo '         </ul>' . PHP_EOL;
  332. }
  333.  
  334. function RemoveUser( $user ) {
  335.         if ( USER_EXPECTED_REFERER !== $_SERVER['HTTP_REFERER'] ) {
  336.                 EXIT_ON_REFERER_MISMATCH( 'Funktion: ' . __FUNCTION__ . ' Zeile: ' . __LINE__ );
  337.         }              
  338.         $newFile = '';
  339.         $arFile = file( USER_DEFINED_USERFILE );
  340.         foreach ( $arFile as $strLine ) {
  341.                 $arLine = explode( ':' , $strLine , 2 );
  342.                 if ( $arLine[0] != $user && $arLine[0] != '' && isset( $arLine[1] ) ) {
  343.                         $newFile .= $arLine[0] . ':' . trim( $arLine[1] ) . PHP_EOL;
  344.                 }
  345.         }
  346.         file_put_contents( USER_DEFINED_USERFILE, $newFile, LOCK_EX );
  347. }
  348.  
  349. function AddUser( $user, $password ) {
  350.         if ( USER_EXPECTED_REFERER !== $_SERVER['HTTP_REFERER'] ) {
  351.                 EXIT_ON_REFERER_MISMATCH( 'Funktion: ' . __FUNCTION__ . ' Zeile: ' . __LINE__ );
  352.         }              
  353.         if ( 255 > strlen( $user ) )        $user = substr( $user, 0, 255 );
  354.         if ( 255 > strlen( $password ) )    $password = substr( $password, 0, 255 );
  355.        
  356.         $z = USER_DEFINED_MIN_USERNAME_SIZE - 1;
  357.         if ( $z < 0 ) {
  358.                 $z = 0;
  359.         }
  360.         $regex='/^[A-Za-z][A-Za-z0-9._-]{'. $z . ',255}$/';
  361.  
  362.         if ( false === preg_match( $regex, $user ) ) {
  363.                 return false;
  364.         }
  365.        
  366.         $regex='/^.{' . USER_DEFINED_MIN_PASSWORD_SIZE . ',}$/';
  367.         if ( USER_DEFINED_MIN_PASSWORD_SIZE > strlen( $password ) ) {
  368.                 return false;
  369.         }      
  370.        
  371.         RemoveUser( $user );
  372.         if ( defined ( 'FTX_BCRYPT_COST' ) and intval( FTX_BCRYPT_COST ) ) {
  373.                 $options['cost'] = FTX_BCRYPT_COST;
  374.         } else {
  375.                 $options=[];
  376.         }
  377.         $apachepassword  = password_hash( $password, PASSWORD_BCRYPT , $options );
  378.         $newline = $user . ':' . $apachepassword ;
  379.         file_put_contents( USER_DEFINED_USERFILE, $newline = $user . ':' . $apachepassword, FILE_APPEND | LOCK_EX );
  380.         return true;
  381. }
  382.  
  383. function AddToHtaccess() {
  384.         if ( USER_EXPECTED_REFERER !== $_SERVER['HTTP_REFERER'] ) {
  385.                 EXIT_ON_REFERER_MISMATCH( 'Funktion: ' . __FUNCTION__ . ' Zeile: ' . __LINE__ );;
  386.         }              
  387.         $text='
  388. AuthType basic
  389. AuthName "' . USER_DEFINED_AUTHNAME . '"
  390. AuthUserFile "' . USER_DEFINED_USERFILE . '"
  391. Require valid-user';
  392.         file_put_contents( USER_DEFINED_HTACCESSFILE, $text, FILE_APPEND | LOCK_EX );
  393. }
  394.  
  395. function DelFromHtaccess() {
  396.         if ( USER_EXPECTED_REFERER !== $_SERVER['HTTP_REFERER'] ) {
  397.                 EXIT_ON_REFERER_MISMATCH( 'Funktion: ' . __FUNCTION__ . ' Zeile: ' . __LINE__ );
  398.         }              
  399.         $text = [];
  400.         $arFile = file( USER_DEFINED_HTACCESSFILE );
  401.         foreach ( $arFile as $strLine ) {
  402.                 $s = trim( $strLine );
  403.                 if (
  404.                         $s
  405.                         and     false === strpos( $s , 'AuthType basic' )
  406.                         and     false === strpos( $s , 'AuthName "' . USER_DEFINED_AUTHNAME )
  407.                         and     false === strpos( $s , 'AuthUserFile "' . USER_DEFINED_USERFILE )
  408.                         and false === strpos( $s , 'Require valid-user' )
  409.                 ) {
  410.                         $text[] = $strLine;
  411.                 }
  412.         }
  413.         file_put_contents( USER_DEFINED_HTACCESSFILE, implode( PHP_EOL, $text ), LOCK_EX );
  414. }
  415.  
  416. function CheckHtaccess() {
  417.         $arFile = file( USER_DEFINED_HTACCESSFILE );
  418.         foreach ( $arFile as $strLine ) {
  419.                 $s = trim( $strLine );
  420.                 if ( $s ) {
  421.                         if ( 0 === strpos( $s, 'AuthType basic' ) )                        { return true; }
  422.                         if ( 0 === strpos( $s, 'AuthName "' . USER_DEFINED_AUTHNAME ) )    { return true; }
  423.                         if ( 0 === strpos( $s, 'AuthUserFile "' . USER_DEFINED_USERFILE ) ){ return true; }
  424.                         if ( 0 === strpos( $s, 'Require valid-user' ) )                        { return true; }
  425.                 }
  426.         }
  427.         return false;
  428. }
  429.  
  430. function EXIT_ON_CONFIG_ERROR ( $str ) {
  431.         http_response_code( 500 );
  432.         header ( 'Content-Type: text/html; charset=utf-8' );
  433.         if ( true === USER_SHOW_CONFIG_ERRORS ) {
  434.                 echo '<h1>Config-Error</h1><hr><p>' . htmlspecialchars( $str ) . '</p>';
  435.         } else {
  436.                 echo '<h1>Error</h1><hr><p>The Server made a boo boo.</p>';
  437.         }
  438.         error_log( 'Fatal: ' .  $str );
  439.         exit;
  440. }
  441.  
  442. function EXIT_ON_REFERER_MISMATCH ( $str ) {
  443.         http_response_code( 500 );
  444.         header ( 'Content-Type: text/html; charset=utf-8' );
  445.         echo '<h1>Error</h1><hr><p>The Server made a boo boo.</p>';
  446.         error_log( 'Fatal: Nicht erwarteter Referer: ' . $_SERVER['HTTP_REFERER'] . ' ' . $str );
  447.         exit;
  448. }
  449.  
  450.  
  451. /*
  452.  * HTML-Output *********************************************************
  453. */
  454.  
  455.  
  456. header( 'Content-Type:text/html; charset=UTF-8' );
  457. ?><!DOCTYPE html>
  458. <html lang="de">
  459.         <head>
  460.                 <title>Passwortverwaltung</title>
  461.                 <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">
  462.                 <meta charset="utf-8"/>
  463.                 <meta name="Author" content="Jörg Reinholz, fastix Webdesign &amp; Consult">
  464.                 <meta name="Publisher" content="Jörg Reinholz, fastix Webdesign &amp; Consult">
  465.                 <meta name="Copyright" content="Jörg Reinholz, fastix Webdesign &amp; Consult">
  466.                 <meta name="Robots" content="NOINDEX,NOFOLLOW">
  467.                 <link rel="shortcut icon" href="data:<?=FTX_FAVICON_MIME_TYPE . ';base64,' . FTX_FAVICON_BASE64; ?>" type="<?=FTX_FAVICON_MIME_TYPE; ?>" />
  468.                 <style nonce="<?=FTX_NONCE_STYLE;?>">
  469.                         body, html, form {
  470.                                 padding:0;
  471.                                 margin:0;
  472.                                 font-family:sans-serif;
  473.                                 background-color:#f0f0f0;
  474.                                 font-size:1rem;
  475.                         }
  476.  
  477.                         header {
  478.                                 padding-left:1rem;
  479.                                 background-color: <?=$status_color;?>;
  480.                                 color: #fafafa;
  481.                                 border-bottom:2px solid #000;
  482.                                 font-family: serif;
  483.                                 font-weight:bold;
  484.                         }
  485.  
  486.                         h1 {
  487.                                 margin-top:0;
  488.                                 margin-bottom:0;
  489.                                 font-size:1.7rem;
  490.                                 padding-left:1rem;
  491.                                 padding-top:.2rem;
  492.                                 padding-bottom:.2rem;
  493.                                 font-family: serif;
  494.                         }
  495.                         .subline {
  496.                                 line-height:1rem;
  497.                                 padding-left:1rem;
  498.                                 padding-bottom:.3rem;
  499.                         }
  500.                         #inhalt {
  501.                                 position:absolute;
  502.                                 top:6em;
  503.                                 left:1.4rem;
  504.                                 bottom:4rem;
  505.                                 width:30rem;
  506.                                 padding:.25rem;
  507.                                 overflow:auto;
  508.                         }
  509.  
  510.                         .t1 {
  511.                                 display:block;
  512.                                 width:6rem;
  513.                                 float:left;
  514.                         }
  515.                         .deletable_user {
  516.                                 background-color:#fff;
  517.                                 padding:.3rem;
  518.                                 border:1px solid #cc0;
  519.                                 margin-top:-1px;
  520.                                 cursor:pointer;
  521.                         }
  522.  
  523.                         .deletable_user:hover {
  524.                                 background-color:#ffa;
  525.                         }
  526.                         .not_deletable_user {
  527.                                 background-color:#ddd;
  528.                                 color:888;
  529.                                 padding:.3rem;
  530.                                 border:1px solid #cc0;
  531.                                 margin-top:-1px;
  532.                         }
  533.                        
  534.                         .status {
  535.                                 text-align:center;
  536.                                 font-weight:bold;
  537.                         }
  538.                         .status_alarm {
  539.                                         color: <?=USER_ALARM_COLOR;?>;
  540.                         }
  541.                         .status_ok {
  542.                                         color: <?=USER_OK_COLOR;?>;
  543.                         }
  544.                                                
  545.                         legend {
  546.                                 font-weight:bold;
  547.                                 font-size:.8rem;
  548.                                 font-family:serif;
  549.                         }
  550.                         fieldset {
  551.                                 margin-bottom:2rem;
  552.                                 border-radius:.1rem;
  553.                         }
  554.                         #fastix {
  555.                                 position:absolute;
  556.                                 top:100%;
  557.                                 left:0;
  558.                                 right:0;
  559.                                 margin-top:-3.2rem;
  560.                                 font-size:.8rem;
  561.                                 padding:.7rem;
  562.                                 padding-left:1rem;
  563.                                 background-color:<?=$status_color;?>;
  564.                                 color:#fff;
  565.                                 border-top:.2rem solid #000;
  566.                         }
  567.  
  568.                         input {
  569.                                 font-family:sans-serif;
  570.                         }
  571.                         #Ein {
  572.                                 width:10em;
  573.                                 display:<?=$strShowEinbutton;?>
  574.                         }
  575.                         #Aus {
  576.                                 width:10em;
  577.                                 display:<?=$strShowAusbutton;?>
  578.                         }
  579.                         #SicherheitsHinweis {
  580.                                 margin: auto;
  581.                         }
  582.                         #SicherheitsHinweis h1 {
  583.                                 color: <?=USER_ALARM_COLOR;?>;
  584.                         }
  585.                        
  586.                         #SicherheitsHinweis p {
  587.                                 color: <?=USER_ALARM_COLOR;?>;
  588.                                 margin-left: 1rem;
  589.                         }
  590.                        
  591.                         #header, #inhalt {
  592.                                 display: none;
  593.                         }
  594.                        
  595.                        
  596.                 </style>
  597.                 <script nonce="<?=FTX_NONCE_SCRIPT;?>">
  598.  
  599.                         window.onload = function () {
  600.                                
  601.                                 if ( ! areCookiesEnabled() ) {
  602.                                         alert( 'Sie müssen Cookies für "' + document.location.href + '" erlauben, um Benutzer löschen zu können.' );
  603.                                 } else {
  604.                                         document.cookie = "UserToDelete=; expires=Thu, 01 Jan 1970 00:00:00 UTC; <?=FTX_COOKIE_RESTRICTIONS;?>;";
  605.                                 }
  606.                                
  607.                                 if ( -1 !== document.cookie.indexOf( 'SicherheitsHinweisAusblenden=YES' ) ) {
  608.                                         document.getElementById( 'SicherheitsHinweis' ).style.display = 'none';
  609.                                         document.getElementById( 'header'  ).style.display = 'block';
  610.                                         document.getElementById( 'inhalt' ).style.display = 'block';
  611.                                         document.getElementById( 'user'   ).focus();
  612.                                 }
  613.                                
  614.                                 var arr = document.getElementsByClassName ('deletable_user');
  615.                                 for (var i = 0; i < arr.length; i++) {
  616.                                         arr[i].addEventListener("click",
  617.                                                 function () {
  618.                                                         Ask4Delete( this.innerText );
  619.                                                 }
  620.                                         );
  621.                                 }
  622.                                
  623.                                 document.getElementById('Verzeichnisschutz').addEventListener("submit",
  624.                                         function () {
  625.                                                 return confirm( 'Verzeichnisschutz ein oder ausschalten\nWollen das wirklich tun? ' );
  626.                                         }
  627.                                 );
  628.                                
  629.                                 document.getElementById('SicherheitsHinweisButton').addEventListener("click",
  630.                                         function () {
  631.                                                 document.cookie = 'SicherheitsHinweisAusblenden=YES; <?=FTX_COOKIE_RESTRICTIONS;?>;';
  632.                                                 document.getElementById( 'SicherheitsHinweis' ).style.display = 'none';
  633.                                                 document.getElementById( 'header'  ).style.display = 'block';
  634.                                                 document.getElementById( 'inhalt' ).style.display = 'block';
  635.                                                 document.getElementById( 'user'   ).focus();
  636.                                         }
  637.                                 );
  638.                                 document.getElementById('Zufall').addEventListener("click",
  639.                                         async function () {
  640.                                                 // Crypto-Random not really works.
  641.                                                 // Why? With window.crypto.getRandomValues() the browser ( firefox, chromium @linux ) wait a VERRY long time for entropie from OS...
  642.                                                 // In this case is pseudo-random better then nothing.
  643.                                                 var dummy;
  644.                                                 var excludes = new Array(34,39,44,46,58,59,94,96);
  645.                                                 var ra = <?=(USER_DEFINED_MIN_PASSWORD_SIZE);?> + Math.floor( Math.random() * ( <?=(USER_DEFINED_MIN_PASSWORD_SIZE);?> * 2  - <?=(USER_DEFINED_MIN_PASSWORD_SIZE);?> ) );
  646.                                                 document.getElementById('pass').value ='';
  647.                                                 for ( var i=0; i < ra; i++ ) {
  648.                                                         var z = 0;
  649.                                                         while ( 0 == z  ) {
  650.                                                                 for ( var k=0; k<( new Date().getMilliseconds() ) % 127; k++ ) {
  651.                                                                         dummy = Math.random();
  652.                                                                 }
  653.                                                                 var z = 33 + Math.floor( Math.random() * ( 122 - 33 ) );
  654.                                                                 if ( excludes.includes( z, 0 ) ) { z = 0; }
  655.                                                         }
  656.                                                         // not crypto, but a niceoptical  effect
  657.                                                         document.getElementById('pass').value = document.getElementById('pass').value.split('').sort(function(){return 0.5-Math.random()}).join('');
  658.                                                         document.getElementById('pass').value += String.fromCharCode( z );
  659.                                                         await sleep(37);
  660.                                                 }
  661.                                                 //document.getElementById('pass').value = document.getElementById('pass').value.split('').sort(function(){return 0.5-Math.random()}).join('');
  662.                                         }
  663.                                 );
  664.                                
  665.                                 // Warnung?
  666.                                 <?=$warnung;?>                                 
  667.                         }      
  668.  
  669.                         function areCookiesEnabled() {
  670.                                 try {
  671.                                   document.cookie = 'cookietest=1; SameSite=Strict;';
  672.                                   var cookiesEnabled = ( -1 !== document.cookie.indexOf('cookietest=') );
  673.                                   document.cookie = 'cookietest=1; expires=Thu, 01-Jan-1970 00:00:01 GMT; <?=FTX_COOKIE_RESTRICTIONS;?>;';
  674.                                   return cookiesEnabled;
  675.                                 } catch (e) {
  676.                                   return false;
  677.                                 }
  678.                         }
  679.                
  680.                         function Ask4Delete( user ) {
  681.                                 if ( confirm( 'Wollen Sie den Benutzer „' + user + '" wirklich löschen?' ) ) {
  682.                                         var d = new Date();
  683.                                         d.setTime( d.getTime() + ( 1 * 1000 ) );
  684.                                         document.cookie = "userToDelete=" + user.replace( ";", "\u003B" ) + "; expires=" + d.toUTCString() + "; <?=FTX_COOKIE_RESTRICTIONS;?>;";
  685.                                         location.href=location.href;
  686.                                 } else {
  687.                                         return 0;
  688.                                 }
  689.                         }
  690.                        
  691.                        
  692.                         function sleep(ms) {
  693.                                 return new Promise( resolve => setTimeout( resolve, ms ) );
  694.                         }
  695.                        
  696.                 </script>
  697.                
  698.         </head>
  699.         <body>
  700.                 <header id="header">
  701.                         <h1>Benutzerverwaltung</h1>
  702.                         <div class="subline">für das Verzeichnis: <?=htmlspecialchars( dirname( $_SERVER['SCRIPT_FILENAME'] ) );?></div>
  703.                 </header>
  704.                        
  705.                 <noscript><h1>Bitte aktivieren Sie Java-Script!</h1><p class="subline">(Sonst wird dieses Tool nicht funktionieren...)</p></noscript>
  706.  
  707.                 <div id="SicherheitsHinweis">
  708.                         <h1>Sicherheitshinweis:</h1>
  709.                         <p>Sie müssen dieses Browserfenster schließen um sich abzumelden.</p>
  710.                         <p>Tun Sie das nicht besteht die Gefahr, dass Dritte dieses Skript benutzen.</p>
  711.                         <p><button id="SicherheitsHinweisButton">Verstanden</button></p>
  712.                 </div>
  713.  
  714.                 <div id="inhalt">
  715.                         <p><strong>Hinweis:</strong> Um einem Benutzer ein neues Passwort zuzuweisen legen Sie diesen neu an. Vorheriges Löschen ist <em>nicht</em> notwendig.</p>
  716.                         <form id="Verzeichnisschutz" method="post">
  717.                                 <fieldset><legend>Verzeichnisschutz:</legend>
  718.                                 <div class='status'><?=$strSchutz;?><br>
  719.                                 <input id="Ein" type="submit" name="Ein" value="Einschalten"><input id="Aus" type="submit" name="Aus" value="Ausschalten"></div>
  720.                                 </fieldset>
  721.                         </form>
  722.                         <form method="post">
  723.                                 <fieldset><legend>Neuen Benutzer anlegen:</legend>
  724.                                         <label class="t1">Benutzer:</label><input type="text" value="" id="user" name="user" required pattern="[A-Za-z][A-Za-z0-9._-]{<?=(USER_DEFINED_MIN_USERNAME_SIZE-1);?>,254}" minlength="<?=USER_DEFINED_MIN_USERNAME_SIZE;?>" maxlength="255" title="Mindestens <?=USER_DEFINED_MIN_USERNAME_SIZE;?>, höchstens 255 Zeichen: Buchstaben (keine Umlaute), Ziffern, Unterstrich, Punkt oder Minus; erstes Zeichen: ein Buchstabe"><br>
  725.                                         <label class="t1">Passwort:</label><input type="text" value="" id="pass" name="pass" required pattern=".{<?=(USER_DEFINED_MIN_PASSWORD_SIZE);?>,255}" minlength="<?=USER_DEFINED_MIN_PASSWORD_SIZE;?>" maxlength="255" title="Mindestens <?=USER_DEFINED_MIN_PASSWORD_SIZE;?>, höchstens 255 Zeichen." autocomplete="off">
  726.                                         <button id="Zufall" type="button">Zufall</button>
  727.                                         <br>
  728.                                         <label class="t1">&nbsp;</label><button>Eintragen</button>
  729.                                 </fieldset>
  730.                         </form>
  731.                         <fieldset><legend>Benutzer löschen:</legend>
  732. <?=PrintUserList();?>
  733.                         </fieldset>
  734.                 </div>
  735.  
  736.                 <p id="fastix">Version 4.3 von Jörg Reinholz, https://www.fastix.org</p>
  737.         </body>
  738. </html>