<?php

/**
* @author: Jörg Reinholz, fastix WebDesign & Consult, Kassel - http://www.fastix.org/
* @version: 4.3
* @encoding: UTF-8
**/
declare( strict_types=1 );

### Konfiguration: #####################################################

## Bezeichnung für den gesicherten Bereich Ihrer Webseite.
# Dieses ist für die Benutzer lesbar und wird beim Login angezeigt.
# Browser verwenden diese für Auswahl gespeicherter Zugangsdaten und speichern
# diese Information also.

#original: define( 'USER_DEFINED_AUTHNAME', 'Geschlossener Bereich' );
define( 'USER_DEFINED_AUTHNAME', 'Geschlossener Bereich' );


## Wohin soll das Userfile gespeichert werden?
# Optimal ist ein Verzeichnis außerhalb des Webrootes

#original: define( 'USER_DEFINED_USERFILE', '/Verzeichnis/von/.htpasswd' );
#example:  define( 'USER_DEFINED_USERFILE', __DIR__ . '/.htpasswd' );
define( 'USER_DEFINED_USERFILE', '/Verzeichnis/von/.htpasswd' );

## Welche(r) Benutzer darf diese Benutzerverwaltung aufrufen?
# Wenn Sie einen leeren String eintragen, dann darf JEDER Benutzer verwalten
# und die Authentifizierung abschalten.
# Komma-separierte Liste. Leerzeichen vor und nach den Namen werden ignoriert.

#original: define( 'USER_DEFINED_ADMINS', 'root' );
#example:  define( 'USER_DEFINED_ADMINS', 'root,admin, usermin' );
define( 'USER_DEFINED_ADMINS', 'root' );

## Die folgende Einstellung ist auf einem Apache Webserver
## normalerweise so vorkonfiguriert. Ändern sie diese,
## dann wird das Skript zwar funktionieren - aber der
## Webserver wird Ihre Einstellungen ignorieren:

#original: define( 'USER_DEFINED_HTACCESSFILE', __DIR__ . '/.htaccess' );
#example( 'USER_DEFINED_HTACCESSFILE', '/foo/bar/.htaccess' );
define( 'USER_DEFINED_HTACCESSFILE', __DIR__ . '/.htaccess' );

## Mindestlänge für neue Passwörter:

#original: define( 'USER_DEFINED_MIN_PASSWORD_SIZE', 8 );
define( 'USER_DEFINED_MIN_PASSWORD_SIZE', 8 );


## Mindestlänge für neue Benutzernamen: (Minimum: 1)

#original: define( 'USER_DEFINED_MIN_USERNAME_SIZE', 3 );
define( 'USER_DEFINED_MIN_USERNAME_SIZE', 3 );


## Um das GEFÄHRLICHE Vorgehen zu erlauben, dass die Benutzernamen und Passwörter auch bei einer
## unverschlüsselten Verbindung  (kein HTTPS) auf einen entfernten Server (Nicht:localhost, 127.x.x.x)
## übertragen werden, geben Sie hier ZEICHENGENAU 'Ja! Passwoerter unverschluesselt uebertragen' ein:

#original: define( 'USER_ALLOW_UNSAFE_TRANSPORT', 'No' );
define( 'USER_ALLOW_UNSAFE_TRANSPORT', 'No' );

## Um das GEFÄHRLICHE Vorgehen zu erlauben, dass Konfiguationsfehler angezeigt werden, geben
## Sie hier true (Ohne Anführunsstriche) an:

#original: define( 'USER_SHOW_CONFIG_ERRORS', false );
#example: define( 'USER_SHOW_CONFIG_ERRORS', true );
define( 'USER_SHOW_CONFIG_ERRORS', false );

## Geben Sie hier die erwartete URL des Skriptes an.
# Wenn Sie z.B. 'http://localhost/htpasswd-test/htpasswd.php' erwarten, dann genau diese:

#original: define( 'USER_EXPECTED_REFERER', 'http://localhost/htpasswd-test/htpasswd.php' );
define( 'USER_EXPECTED_REFERER', 'http://localhost/htpasswd-test/htpasswd.php' );

## Geben Sie hier eine gültige CSS-Farbangabe für Alarmmeldungen an:

#original: define( 'USER_ALARM_COLOR', '#a00000' );
define( 'USER_ALARM_COLOR', '#a00000' );


## Geben Sie hier eine gültige CSS-Farbangabe für OK-Meldungen an:
#original: define( 'USER_OK_COLOR', '#008000' );
define( 'USER_OK_COLOR', '#008000' );

## Geben Sie hier ZEICHENGENAU 'Ja! Alles ueberprueft' an, wenn Sie die Konfiguration bearbeitet haben:

#original: define( 'YES_I_HAVE_THE_CONFIG_EDITED_AND_CHECKED', 'No' );
define( 'YES_I_HAVE_THE_CONFIG_EDITED_AND_CHECKED', 'No' );

########################################################################
#                                                                      #
#     Definitionen, die nur erfahrene Programmierer verändern:         #
#                                                                      #
########################################################################

error_reporting( E_ALL );
ini_set( 'display_errors', '0' );

define( 'FTX_PHP_MIN_VERSION',    7.0 );
define( 'FTX_APACHE_MIN_VERSION', 2.4 );
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 ;
define( 'FTX_NONCE_SCRIPT', bin2hex( random_bytes( 12 ) ) ) ;
define( 'FTX_NONCE_STYLE' , bin2hex( random_bytes( 12 ) ) ) ;
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\'' );
define( 'FTX_STS_TIME', ( 1 * 24 * 60 * 60 ) ); # +1 Tag nur per https

# Das Favicon:
define( 'FTX_FAVICON_MIME_TYPE',  'image/gif' );
define( 'FTX_FAVICON_BASE64'   ,'R0lGODlhEAAQAOMHAAAAAAgICBUVFc/Pz9DQ0NjY2Ofn5////////////////////////////////////yH5BAEKAAgALAAAAAAQABAAAAQd8MhJq704600H4JIHHiJIfGARjIYwviTKlXBtTxEAOw==');


# Disable all caches:
header( 'Cache-Control: max-age=0' );
header( 'Cache-Control: no-cache' );
header( 'Pragma: no-cache' );

# Safety-Vodoo 
header( 'X-XSS-Protection: 1; mode=block' );
header( 'X-Frame-Options: deny' );
header( 'Origin: ' . $_SERVER['REQUEST_SCHEME'] . '://' . $_SERVER['HTTP_HOST'] );
header( 'Access-Control-Allow-Origin: ' . $_SERVER['REQUEST_SCHEME'] . '://' . $_SERVER['HTTP_HOST'] );
header( 'Content-Security-Policy: '    . FTX_CONTENT_SECURITY_POLICY );
header( 'X-Content-Security-Policy: '  . FTX_CONTENT_SECURITY_POLICY );
header( 'X-WebKit-CSP: '               . FTX_CONTENT_SECURITY_POLICY );
header( 'Referrer-Policy: strict-origin-when-cross-origin');

if ( realpath( __FILE__ ) !== realpath( $_SERVER['SCRIPT_FILENAME'] ) ) {
	EXIT_ON_CONFIG_ERROR( 'Versuch, ' . __FILE__ . 'includiert auszuführen' );
}


if ( isset( $_SERVER['PHP_AUTH_USER'] ) ) {
	$access_denied = false;
	$admins = explode(',', USER_DEFINED_ADMINS );
	if ( count( $admins ) ) {
		$access_denied = true;
		foreach ( $admins as $admin ) {
			if ( trim($admin) == $_SERVER['PHP_AUTH_USER'] ) {
				$access_denied = false;
			}
		}
	}
    if ( $access_denied ) {
		EXIT_ON_CONFIG_ERROR('Fatal: Der Benutzer ' . $_SERVER['PHP_AUTH_USER'] . ' darf dieses Skript nicht aufrufen.' );
	}
}

if ( YES_I_HAVE_THE_CONFIG_EDITED_AND_CHECKED != 'Ja! Alles ueberprueft' ) {
	header ( 'Content-Type: text/plain; charset=utf-8' );
	EXIT_ON_CONFIG_ERROR('Bitte lesen und bearbeiten Sie zunächst die Konfiguration dieses Skriptes!' );
}

if ( 
	   ( isset ( $_SERVER['REQUEST_SCHEME'] ) and 'https' == $_SERVER['REQUEST_SCHEME'] )
    or ( isset ( $_SERVER['HTTPS'] ) and 'on' == $_SERVER['HTTPS'] )
) {
	header( 'Strict-Transport-Security: max-age=' . FTX_STS_TIME );
	define( 'FTX_COOKIE_RESTRICTIONS', 'SameSite=Strict; secure'  );
} elseif ( 
		'127.' != substr( $_SERVER['REMOTE_ADDR'], 0, 4 )
	and USER_ALLOW_UNSAFE_TRANSPORT != 'Ja! Passwoerter unverschluesselt uebertragen'
) {
	header ( 'Content-Type: text/plain; charset=utf-8' );
	EXIT_ON_CONFIG_ERROR( 'Die Konfiguration darf nur mit SSL/TLS (via HTTPS erfolgen)!' );
} else {
	#Unsichere Verbindung
	define( 'FTX_COOKIE_RESTRICTIONS', 'SameSite=Strict'  );
}

if ( function_exists( 'apache_get_version' ) ) { 
	$apacheVersion = apache_get_version(); 
	$apacheVersion = preg_replace( '/[^0-9.]/', '', $apacheVersion );
	$apacheVersion = (float) preg_replace('/^([0-9]+\.[0-9]+).*/','$1', $apacheVersion );
} else {
	$apacheVersion = false;
}

if ( FTX_APACHE_MIN_VERSION > $apacheVersion ) {
	if ( false === $apacheVersion ) $apacheVersion = 'unbekanntem Webserver';
	header ( 'Content-Type: text/plain; charset=utf-8' );
	EXIT_ON_CONFIG_ERROR( 'Auf einer Maschine mit ' . $apacheVersion . ' wird der Dienst zuverlässig verweigert.' );
}

if ( 
	! defined( 'PHP_VERSION_ID' ) 
	or PHP_VERSION_ID < ( FTX_PHP_MIN_VERSION * 10000 )
	or ! function_exists( 'password_hash')
) {
	header ( 'Content-Type: text/plain; charset=utf-8' );
	EXIT_ON_CONFIG_ERROR( 'Auf einer Maschine mit einer völlig veralteten PHP-Version ' . phpversion() . ' wird der Dienst verweigert.' );
}

if ( ! file_exists( USER_DEFINED_USERFILE ) ) {
	touch ( USER_DEFINED_USERFILE );
}

if ( ! file_exists( USER_DEFINED_HTACCESSFILE ) ) {
	touch ( USER_DEFINED_HTACCESSFILE );
}

if ( ! file_exists( USER_DEFINED_USERFILE ) ) {
	header ( 'Content-Type: text/plain; charset=utf-8' );
	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.' );
}

if ( ! file_exists( USER_DEFINED_HTACCESSFILE ) ) {
	header ( 'Content-Type: text/plain; charset=utf-8' );
	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.' );
}

if ( ! is_readable( USER_DEFINED_USERFILE ) ) {
	header ( 'Content-Type: text/plain; charset=utf-8' );
	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 . '"' );
}

if ( ! is_readable( USER_DEFINED_HTACCESSFILE ) ) {
	header ( 'Content-Type: text/plain; charset=utf-8' );
	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.'"' );
}

if ( ! is_writable( USER_DEFINED_USERFILE ) ) {
	header ( 'Content-Type: text/plain; charset=utf-8' );	
	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 . '"' );
}

if ( ! is_writable( USER_DEFINED_HTACCESSFILE ) ) {
	header ( 'Content-Type: text/plain; charset=utf-8' );
	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 . '"' );
}

$warnung = '';

if ( isset( $_POST['user'] ) && $_POST['user'] && isset( $_POST['pass'] ) && ( $_POST['pass'] ) ) {
	$user = trim( $_POST['user'] );
	$pass = trim( $_POST['pass'] );
	
	if ( USER_DEFINED_MIN_PASSWORD_SIZE > strlen( $pass ) ) {
		$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." );';		
	} elseif (! AddUser( $user, $pass ) ) {
		$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.)")';
	} else {
		$warnung = 'alert( "Der Benutzer „' . trim( json_encode($user), '"') . '“ wurde angelegt oder geändert." )';
	}
}

if ( isset( $_COOKIE['userToDelete'] ) and trim( $_COOKIE['userToDelete'] ) ) {

	$strUser = trim( $_COOKIE['userToDelete'] );
	setcookie( 'userToDelete', '', time() - 1, '', '', true );
	if (
		! CheckHtaccess( USER_DEFINED_HTACCESSFILE )
		or (
			isset( $_SERVER['PHP_AUTH_USER'] )
			and $strUser != $_SERVER['PHP_AUTH_USER']
		)
	) {
		RemoveUser( $strUser );
	} else {
		$warnung = 'alert( "Sie können sich selbst nicht löschen! Sie können aber Ihr Passwort ändern." );';
	}
}

if ( isset( $_POST['Ein'] ) && $_POST['Ein'] ) {

	$arUsers = GetUserArray();
	if ( isset( $arUsers[0] )  && $arUsers[0] ) {
		AddToHtaccess();
		header( 'Location: ' . $_SERVER['REQUEST_URI'] );
		exit;
	} else {
		$warnung = 'alert( "Der Schutz kann nicht aktiviert werden, weil (noch) keine Benutzer existieren. Legen Sie mindestens einen Benutzer an." );';

	}
}

if ( isset( $_POST['Aus'] ) && $_POST['Aus'] ) {
	DelFromHtaccess();
}

if ( CheckHtaccess() ) {
	$strSchutz = '<span class="status_ok">Gesichert:<br>Der Verzeichnisschutz ist eingeschaltet.</span>';
	$strShowEinbutton = 'none';
	$strShowAusbutton = 'inline';
	$status_color     = USER_OK_COLOR;
} else {
	$strSchutz = '<span class="status_alarm">ACHTUNG!<br>Der Verzeichnisschutz ist ausgeschaltet.</span>';
	$strShowEinbutton = 'inline';
	$strShowAusbutton = 'none';
	$status_color     = USER_ALARM_COLOR;
}

/*
*	Funktionen *********************************************************
*/

function GetUserArray() {
	$users = array();
	$arLines = file( USER_DEFINED_USERFILE );
	foreach ( $arLines as $strLine ) {
		$parts = array();
		$parts = explode( ':', $strLine, 2 );
		$parts[0] = trim($parts[0] );
		if ( '' != $parts[0] ) {
			$users[] = $parts[0];
		}
	}
	$dummy = sort( $users );
	return $users;
}

function PrintUserList() {
	$arUsers = GetUserArray();
	echo '         <ul type="none">' . PHP_EOL;
	foreach ( $arUsers as $strUser ) {
		$strUser = trim( $strUser );
		if (
			! CheckHtaccess()
			or (
				isset( $_SERVER['PHP_AUTH_USER'] )
				and $strUser != $_SERVER['PHP_AUTH_USER']
			)
		) {
			echo '                 <li class="deletable_user" title="Diesen Benutzer löschen ...">' . htmlspecialchars( $strUser, ENT_QUOTES ) . '</li>' . PHP_EOL;
		} else {
			echo '                 <li class="not_deletable_user"  title="Der aktuell angemeldete Benutzer ist nicht löschbar.">' . htmlspecialchars( $strUser, ENT_QUOTES ) . '</li>' . PHP_EOL;
		}
	}
	echo '         </ul>' . PHP_EOL;
}

function RemoveUser( $user ) {
	if ( USER_EXPECTED_REFERER !== $_SERVER['HTTP_REFERER'] ) {
		EXIT_ON_REFERER_MISMATCH( 'Funktion: ' . __FUNCTION__ . ' Zeile: ' . __LINE__ );
	}		
	$newFile = '';
	$arFile = file( USER_DEFINED_USERFILE );
	foreach ( $arFile as $strLine ) {
		$arLine = explode( ':' , $strLine , 2 );
		if ( $arLine[0] != $user && $arLine[0] != '' && isset( $arLine[1] ) ) {
			$newFile .= $arLine[0] . ':' . trim( $arLine[1] ) . PHP_EOL;
		}
	}
	file_put_contents( USER_DEFINED_USERFILE, $newFile, LOCK_EX );
}

function AddUser( $user, $password ) {
	if ( USER_EXPECTED_REFERER !== $_SERVER['HTTP_REFERER'] ) {
		EXIT_ON_REFERER_MISMATCH( 'Funktion: ' . __FUNCTION__ . ' Zeile: ' . __LINE__ );
	}		
	if ( 255 > strlen( $user ) )        $user = substr( $user, 0, 255 );
	if ( 255 > strlen( $password ) )    $password = substr( $password, 0, 255 );
	
	$z = USER_DEFINED_MIN_USERNAME_SIZE - 1;
	if ( $z < 0 ) {
		$z = 0;
	}
	$regex='/^[A-Za-z][A-Za-z0-9._-]{'. $z . ',255}$/';

	if ( false === preg_match( $regex, $user ) ) {
		return false;
	}
	
	$regex='/^.{' . USER_DEFINED_MIN_PASSWORD_SIZE . ',}$/';
	if ( USER_DEFINED_MIN_PASSWORD_SIZE > strlen( $password ) ) {
		return false;
	}	
	
	RemoveUser( $user );
	if ( defined ( 'FTX_BCRYPT_COST' ) and intval( FTX_BCRYPT_COST ) ) {
		$options['cost'] = FTX_BCRYPT_COST;
	} else {
		$options=[];
	}
	$apachepassword  = password_hash( $password, PASSWORD_BCRYPT , $options );
	$newline = $user . ':' . $apachepassword ;
	file_put_contents( USER_DEFINED_USERFILE, $newline = $user . ':' . $apachepassword, FILE_APPEND | LOCK_EX );
	return true;
}

function AddToHtaccess() {
	if ( USER_EXPECTED_REFERER !== $_SERVER['HTTP_REFERER'] ) {
		EXIT_ON_REFERER_MISMATCH( 'Funktion: ' . __FUNCTION__ . ' Zeile: ' . __LINE__ );;
	}		
	$text='
AuthType basic
AuthName "' . USER_DEFINED_AUTHNAME . '"
AuthUserFile "' . USER_DEFINED_USERFILE . '"
Require valid-user';
	file_put_contents( USER_DEFINED_HTACCESSFILE, $text, FILE_APPEND | LOCK_EX );
}

function DelFromHtaccess() {
	if ( USER_EXPECTED_REFERER !== $_SERVER['HTTP_REFERER'] ) {
		EXIT_ON_REFERER_MISMATCH( 'Funktion: ' . __FUNCTION__ . ' Zeile: ' . __LINE__ );
	}		
	$text = [];
	$arFile = file( USER_DEFINED_HTACCESSFILE );
	foreach ( $arFile as $strLine ) {
		$s = trim( $strLine );
		if ( 
			$s 
			and	false === strpos( $s , 'AuthType basic' )
			and	false === strpos( $s , 'AuthName "' . USER_DEFINED_AUTHNAME )
			and	false === strpos( $s , 'AuthUserFile "' . USER_DEFINED_USERFILE )
			and false === strpos( $s , 'Require valid-user' )
		) {
			$text[] = $strLine;
		}
	}
	file_put_contents( USER_DEFINED_HTACCESSFILE, implode( PHP_EOL, $text ), LOCK_EX );
}

function CheckHtaccess() {
	$arFile = file( USER_DEFINED_HTACCESSFILE );
	foreach ( $arFile as $strLine ) {
		$s = trim( $strLine );
		if ( $s ) {
			if ( 0 === strpos( $s, 'AuthType basic' ) )                        { return true; }
			if ( 0 === strpos( $s, 'AuthName "' . USER_DEFINED_AUTHNAME ) )    { return true; }
			if ( 0 === strpos( $s, 'AuthUserFile "' . USER_DEFINED_USERFILE ) ){ return true; }
			if ( 0 === strpos( $s, 'Require valid-user' ) ) 	               { return true; }
		}
	}
	return false;
}

function EXIT_ON_CONFIG_ERROR ( $str ) {
	http_response_code( 500 );
	header ( 'Content-Type: text/html; charset=utf-8' );
	if ( true === USER_SHOW_CONFIG_ERRORS ) {
		echo '<h1>Config-Error</h1><hr><p>' . htmlspecialchars( $str ) . '</p>';
	} else {
		echo '<h1>Error</h1><hr><p>The Server made a boo boo.</p>';
	}
	error_log( 'Fatal: ' .  $str );
	exit;
}

function EXIT_ON_REFERER_MISMATCH ( $str ) {
	http_response_code( 500 );
	header ( 'Content-Type: text/html; charset=utf-8' );
	echo '<h1>Error</h1><hr><p>The Server made a boo boo.</p>';
	error_log( 'Fatal: Nicht erwarteter Referer: ' . $_SERVER['HTTP_REFERER'] . ' ' . $str );
	exit;
}


/* 
 * HTML-Output *********************************************************
*/


header( 'Content-Type:text/html; charset=UTF-8' );
?><!DOCTYPE html>
<html lang="de">
	<head>
		<title>Passwortverwaltung</title>
		<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">
		<meta charset="utf-8"/>
		<meta name="Author" content="Jörg Reinholz, fastix Webdesign &amp; Consult">
		<meta name="Publisher" content="Jörg Reinholz, fastix Webdesign &amp; Consult">
		<meta name="Copyright" content="Jörg Reinholz, fastix Webdesign &amp; Consult">
		<meta name="Robots" content="NOINDEX,NOFOLLOW">
		<link rel="shortcut icon" href="data:<?=FTX_FAVICON_MIME_TYPE . ';base64,' . FTX_FAVICON_BASE64; ?>" type="<?=FTX_FAVICON_MIME_TYPE; ?>" />
		<style nonce="<?=FTX_NONCE_STYLE;?>">
			body, html, form {
				padding:0;
				margin:0;
				font-family:sans-serif;
				background-color:#f0f0f0;
				font-size:1rem;
			}

			header {
				padding-left:1rem;
				background-color: <?=$status_color;?>;
				color: #fafafa;
				border-bottom:2px solid #000;
				font-family: serif;
				font-weight:bold;
			}

			h1 {
				margin-top:0;
				margin-bottom:0;
				font-size:1.7rem;
				padding-left:1rem;
				padding-top:.2rem;
				padding-bottom:.2rem;
				font-family: serif;
			}
			.subline {
				line-height:1rem;
				padding-left:1rem;
				padding-bottom:.3rem;
			}
			#inhalt {
				position:absolute;
				top:6em;
				left:1.4rem;
				bottom:4rem;
				width:30rem;
				padding:.25rem;
				overflow:auto;
			}

			.t1 {
				display:block;
				width:6rem;
				float:left;
			}
			.deletable_user {
				background-color:#fff;
				padding:.3rem;
				border:1px solid #cc0;
				margin-top:-1px;
				cursor:pointer;
			}

			.deletable_user:hover {
				background-color:#ffa;
			}
			.not_deletable_user {
				background-color:#ddd;
				color:888;
				padding:.3rem;
				border:1px solid #cc0;
				margin-top:-1px;
			}
			
			.status {
				text-align:center;
				font-weight:bold;
			}
			.status_alarm {
					color: <?=USER_ALARM_COLOR;?>;
			}
			.status_ok {
					color: <?=USER_OK_COLOR;?>;
			}
						
			legend {
				font-weight:bold;
				font-size:.8rem;
				font-family:serif;
			}
			fieldset {
				margin-bottom:2rem;
				border-radius:.1rem;
			}
			#fastix {
				position:absolute;
				top:100%;
				left:0;
				right:0;
				margin-top:-3.2rem;
				font-size:.8rem;
				padding:.7rem;
				padding-left:1rem;
				background-color:<?=$status_color;?>;
				color:#fff;
				border-top:.2rem solid #000;
			}

			input {
				font-family:sans-serif;
			}
			#Ein {
				width:10em;
				display:<?=$strShowEinbutton;?>
			}
			#Aus {
				width:10em;
				display:<?=$strShowAusbutton;?>
			}
			#SicherheitsHinweis {
				margin: auto;
			}
			#SicherheitsHinweis h1 {
				color: <?=USER_ALARM_COLOR;?>;
			}
			
			#SicherheitsHinweis p {
				color: <?=USER_ALARM_COLOR;?>;
				margin-left: 1rem;
			}
			
			#header, #inhalt {
				display: none;
			}
			
			
		</style>
		<script nonce="<?=FTX_NONCE_SCRIPT;?>">

			window.onload = function () {
				
				if ( ! areCookiesEnabled() ) {
					alert( 'Sie müssen Cookies für "' + document.location.href + '" erlauben, um Benutzer löschen zu können.' );
				} else { 
					document.cookie = "UserToDelete=; expires=Thu, 01 Jan 1970 00:00:00 UTC; <?=FTX_COOKIE_RESTRICTIONS;?>;";
				}
				
				if ( -1 !== document.cookie.indexOf( 'SicherheitsHinweisAusblenden=YES' ) ) {
					document.getElementById( 'SicherheitsHinweis' ).style.display = 'none'; 
					document.getElementById( 'header'  ).style.display = 'block';
					document.getElementById( 'inhalt' ).style.display = 'block';
					document.getElementById( 'user'   ).focus();
				}
				
				var arr = document.getElementsByClassName ('deletable_user');
				for (var i = 0; i < arr.length; i++) {
					arr[i].addEventListener("click",
						function () {
							Ask4Delete( this.innerText );
						}
					);
				}
				
				document.getElementById('Verzeichnisschutz').addEventListener("submit",
					function () {
						return confirm( 'Verzeichnisschutz ein oder ausschalten\nWollen das wirklich tun? ' );
					}
				);
				
				document.getElementById('SicherheitsHinweisButton').addEventListener("click",
					function () {
						document.cookie = 'SicherheitsHinweisAusblenden=YES; <?=FTX_COOKIE_RESTRICTIONS;?>;';
						document.getElementById( 'SicherheitsHinweis' ).style.display = 'none'; 
						document.getElementById( 'header'  ).style.display = 'block';
						document.getElementById( 'inhalt' ).style.display = 'block';
						document.getElementById( 'user'   ).focus();
					}
				);
				document.getElementById('Zufall').addEventListener("click",
					async function () {
						// Crypto-Random not really works.
						// Why? With window.crypto.getRandomValues() the browser ( firefox, chromium @linux ) wait a VERRY long time for entropie from OS...
						// In this case is pseudo-random better then nothing.
						var dummy;
						var excludes = new Array(34,39,44,46,58,59,94,96);
						var ra = <?=(USER_DEFINED_MIN_PASSWORD_SIZE);?> + Math.floor( Math.random() * ( <?=(USER_DEFINED_MIN_PASSWORD_SIZE);?> * 2  - <?=(USER_DEFINED_MIN_PASSWORD_SIZE);?> ) );
						document.getElementById('pass').value ='';
						for ( var i=0; i < ra; i++ ) {
							var z = 0;
							while ( 0 == z  ) {
								for ( var k=0; k<( new Date().getMilliseconds() ) % 127; k++ ) {
									dummy = Math.random();
								}
								var z = 33 + Math.floor( Math.random() * ( 122 - 33 ) );
								if ( excludes.includes( z, 0 ) ) { z = 0; }
							}
							// not crypto, but a niceoptical  effect
							document.getElementById('pass').value = document.getElementById('pass').value.split('').sort(function(){return 0.5-Math.random()}).join('');
							document.getElementById('pass').value += String.fromCharCode( z );
							await sleep(37);
						}
						//document.getElementById('pass').value = document.getElementById('pass').value.split('').sort(function(){return 0.5-Math.random()}).join('');
					}
				);
				
				// Warnung?
				<?=$warnung;?>					
			}	

			function areCookiesEnabled() {
				try {
				  document.cookie = 'cookietest=1; SameSite=Strict;';
				  var cookiesEnabled = ( -1 !== document.cookie.indexOf('cookietest=') );
				  document.cookie = 'cookietest=1; expires=Thu, 01-Jan-1970 00:00:01 GMT; <?=FTX_COOKIE_RESTRICTIONS;?>;';
				  return cookiesEnabled;
				} catch (e) {
				  return false;
				}
			}
		
			function Ask4Delete( user ) {
				if ( confirm( 'Wollen Sie den Benutzer „' + user + '" wirklich löschen?' ) ) {
					var d = new Date();
					d.setTime( d.getTime() + ( 1 * 1000 ) );
					document.cookie = "userToDelete=" + user.replace( ";", "\u003B" ) + "; expires=" + d.toUTCString() + "; <?=FTX_COOKIE_RESTRICTIONS;?>;";
					location.href=location.href;
				} else {
					return 0;
				}
			}
			
			
			function sleep(ms) {
				return new Promise( resolve => setTimeout( resolve, ms ) );
			}
			
		</script>
		
	</head>
	<body>
		<header id="header">
			<h1>Benutzerverwaltung</h1>
			<div class="subline">für das Verzeichnis: <?=htmlspecialchars( dirname( $_SERVER['SCRIPT_FILENAME'] ) );?></div>
		</header>
			
		<noscript><h1>Bitte aktivieren Sie Java-Script!</h1><p class="subline">(Sonst wird dieses Tool nicht funktionieren...)</p></noscript>

		<div id="SicherheitsHinweis">
			<h1>Sicherheitshinweis:</h1>
			<p>Sie müssen dieses Browserfenster schließen um sich abzumelden.</p>
			<p>Tun Sie das nicht besteht die Gefahr, dass Dritte dieses Skript benutzen.</p>
			<p><button id="SicherheitsHinweisButton">Verstanden</button></p>
		</div>

		<div id="inhalt">
			<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>
			<form id="Verzeichnisschutz" method="post">
				<fieldset><legend>Verzeichnisschutz:</legend>
				<div class='status'><?=$strSchutz;?><br>
				<input id="Ein" type="submit" name="Ein" value="Einschalten"><input id="Aus" type="submit" name="Aus" value="Ausschalten"></div>
				</fieldset>
			</form>
			<form method="post">
				<fieldset><legend>Neuen Benutzer anlegen:</legend>
					<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>
					<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">
					<button id="Zufall" type="button">Zufall</button>
					<br>
					<label class="t1">&nbsp;</label><button>Eintragen</button>
				</fieldset>
			</form>
			<fieldset><legend>Benutzer löschen:</legend>
<?=PrintUserList();?>
			</fieldset>
		</div>

		<p id="fastix">Version 4.3 von Jörg Reinholz, https://www.fastix.org</p>
	</body>
</html>