2022-09-01 02:21:17 +00:00
< ? php
2023-04-19 12:59:07 +00:00
umask ( 0077 );
2023-06-01 13:14:42 +00:00
set_error_handler ( function ( $level , $message , $file = '' , $line = 0 ) {
throw new ErrorException ( $message , 0 , $level , $file , $line );
});
set_exception_handler ( function ( $e ) {
error_log ( $e );
http_response_code ( 500 );
echo '<h1>Error</h1>An error occured.' ;
});
register_shutdown_function ( function () { // Also catch fatal errors
if (( $error = error_get_last ()) !== NULL )
throw new ErrorException ( $error [ 'message' ], 0 , $error [ 'type' ], $error [ 'file' ], $error [ 'line' ]);
});
2023-03-09 13:47:14 +00:00
const ROOT_PATH = __DIR__ ;
define ( 'CONF' , parse_ini_file ( ROOT_PATH . '/config.ini' , true , INI_SCANNER_TYPED ));
2022-09-01 02:21:17 +00:00
2023-03-09 13:47:14 +00:00
define ( 'DB' , new PDO ( 'sqlite:' . ROOT_PATH . '/db/servnest.db' ));
2023-03-25 15:26:05 +00:00
DB -> exec ( 'PRAGMA foreign_keys = ON;' );
DB -> setAttribute ( PDO :: ATTR_ERRMODE , PDO :: ERRMODE_EXCEPTION );
date_default_timezone_set ( 'UTC' );
2022-12-20 23:14:55 +00:00
2023-04-19 12:59:07 +00:00
foreach ( explode ( ',' , preg_replace ( '/[A-Z0-9]|q=|;|-|\./' , '' , $_SERVER [ 'HTTP_ACCEPT_LANGUAGE' ] ? ? '' )) as $client_locale )
2023-04-09 22:50:42 +00:00
if ( in_array ( $client_locale , array_diff ( scandir ( ROOT_PATH . '/locales' ), [ '..' , '.' ]), true )) {
2023-02-16 22:06:12 +00:00
$locale = $client_locale ;
break ;
2023-01-21 00:27:52 +00:00
}
2023-04-19 12:59:07 +00:00
define ( 'LOCALE' , $locale ? ? 'en' );
2023-05-03 22:40:50 +00:00
putenv ( 'LANG=C.UTF-8' );
2023-01-21 00:27:52 +00:00
setlocale ( LC_MESSAGES , 'C.UTF-8' );
2023-04-19 12:59:07 +00:00
bindtextdomain ( 'messages' , ROOT_PATH . '/locales/' . LOCALE );
2023-01-21 00:27:52 +00:00
header ( 'Content-Language: ' . LOCALE );
2022-09-01 02:21:17 +00:00
2023-03-09 00:35:30 +00:00
const SERVICES_USER = [ 'reg' , 'ns' , 'ht' ];
2022-11-20 14:11:54 +00:00
const LF = " \n " ;
2022-09-01 02:21:17 +00:00
2022-09-12 23:09:40 +00:00
const PLACEHOLDER_DOMAIN = 'example' ; // From RFC2606: Reserved Top Level DNS Names > 2. TLDs for Testing, & Documentation Examples
const PLACEHOLDER_IPV6 = '2001:db8::3' ; // From RFC3849: IPv6 Address Prefix Reserved for Documentation
const PLACEHOLDER_IPV4 = '203.0.113.42' ; // From RFC5737: IPv4 Address Blocks Reserved for Documentation
2022-09-01 02:21:17 +00:00
2023-03-09 13:47:14 +00:00
foreach ( array_diff ( scandir ( ROOT_PATH . '/fn' ), [ '..' , '.' ]) as $file )
require ROOT_PATH . '/fn/' . $file ;
2023-01-21 00:27:52 +00:00
2023-04-09 22:50:42 +00:00
require ROOT_PATH . '/pages.php' ;
2023-01-21 00:27:52 +00:00
2022-09-01 02:21:17 +00:00
if ( $_SERVER [ 'REQUEST_URI' ] === '/sftpgo-auth.php' )
return ;
$pageAddress = substr ( $_SERVER [ 'REQUEST_URI' ], strlen ( CONF [ 'common' ][ 'prefix' ]) + 1 );
2022-11-20 14:11:54 +00:00
if ( strpos ( $pageAddress , '?' ) !== false ) {
parse_str ( substr ( $pageAddress , strpos ( $pageAddress , '?' ) + 1 ), $_GET );
$pageAddress = substr ( $pageAddress , 0 , strpos ( $pageAddress , '?' ));
2022-09-01 02:21:17 +00:00
}
2022-11-20 14:11:54 +00:00
define ( 'PAGE_URL' , $pageAddress );
define ( 'PAGE_ADDRESS' , $pageAddress . (( substr ( $pageAddress , - 1 ) === '/' OR $pageAddress === '' ) ? 'index' : '' ));
define ( 'PAGE_LINEAGE' , explode ( '/' , PAGE_ADDRESS ));
define ( 'SERVICE' , dirname ( PAGE_ADDRESS ));
2022-09-01 02:21:17 +00:00
2022-09-16 22:49:07 +00:00
function getPageInformations ( $pages , $pageElements ) {
2022-10-12 22:40:19 +00:00
if ( ! isset ( $pages [ 'index' ]) OR $pageElements [ 0 ] === 'index' )
2022-09-16 22:49:07 +00:00
return [
'titles_lineage' => [ $pages [ $pageElements [ 0 ]][ 'title' ] ? ? false ],
2022-12-20 20:17:03 +00:00
'page_metadata' => $pages [ $pageElements [ 0 ]] ? ? NULL ,
'terminal' => $pageElements [ 0 ] !== 'index'
2022-09-16 22:49:07 +00:00
];
2022-09-15 19:23:49 +00:00
$result = $pages [ 'index' ][ 'title' ];
2022-09-09 18:16:48 +00:00
if ( ! isset ( $pageElements [ 1 ]))
2022-09-15 19:23:49 +00:00
unset ( $pages [ 'index' ]);
2022-09-09 18:16:48 +00:00
else
2022-09-15 19:23:49 +00:00
$pages = $pages [ array_shift ( $pageElements )] ? ? false ;
2022-09-16 22:49:07 +00:00
$results = getPageInformations ( $pages , $pageElements );
$results [ 'titles_lineage' ][] = $result ;
2022-09-09 18:16:48 +00:00
return $results ;
2022-09-09 18:15:10 +00:00
}
2022-09-16 22:49:07 +00:00
$pageInformations = getPageInformations ( PAGES , PAGE_LINEAGE );
define ( 'TITLES_LINEAGE' , array_reverse ( $pageInformations [ 'titles_lineage' ]));
define ( 'PAGE_METADATA' , $pageInformations [ 'page_metadata' ]);
2022-12-20 20:17:03 +00:00
define ( 'PAGE_TERMINAL' , $pageInformations [ 'terminal' ]);
2022-09-09 18:15:10 +00:00
2022-09-09 20:15:52 +00:00
if ( ! TITLES_LINEAGE [ array_key_last ( TITLES_LINEAGE )]) {
http_response_code ( 404 );
exit ( 'Page not found.' );
}
2023-03-27 22:18:37 +00:00
if ( isset ( $_SERVER [ 'SERVER_NAME' ]) !== true )
exit ( 'Missing <code>$_SERVER[\'SERVER_NAME\']</code>' );
if ( in_array ( $_SERVER [ 'SERVER_NAME' ], CONF [ 'common' ][ 'public_domains' ], true ) !== true )
exit ( 'The current <code>$_SERVER[\'SERVER_NAME\']</code> is not allowed in configuration.' );
define ( 'SERVER_NAME' , $_SERVER [ 'SERVER_NAME' ]);
2023-01-29 20:09:00 +00:00
const SESSION_COOKIE_NAME = 'servnest-session-key' ;
2022-12-20 20:17:03 +00:00
function startSession () {
2022-09-09 19:53:31 +00:00
session_start ([
2022-11-26 19:10:37 +00:00
'name' => SESSION_COOKIE_NAME ,
2022-09-09 19:53:31 +00:00
'sid_length' => 64 ,
'sid_bits_per_character' => 6 ,
'cookie_secure' => true ,
'cookie_httponly' => true ,
'cookie_samesite' => 'Strict' ,
'cookie_path' => CONF [ 'common' ][ 'prefix' ] . '/' ,
'cookie_lifetime' => 432000 , // = 60*60*24*5 = 5 days
'gc_maxlifetime' => 10800 ,
'use_strict_mode' => true ,
'use_cookies' => true ,
'use_only_cookies' => true ,
]);
}
2022-12-20 20:17:03 +00:00
if ( isset ( $_COOKIE [ SESSION_COOKIE_NAME ]))
startSession (); // Resume session
2022-09-09 19:53:31 +00:00
2023-01-21 03:14:40 +00:00
if ( isset ( $_SESSION [ 'id' ])) {
2023-03-09 00:35:30 +00:00
// Decrypt display username
2023-01-21 03:14:40 +00:00
if ( ! isset ( $_COOKIE [ 'display-username-decryption-key' ]))
output ( 403 , 'The display username decryption key has not been sent.' );
$decryption_result = htmlspecialchars ( sodium_crypto_aead_xchacha20poly1305_ietf_decrypt (
$_SESSION [ 'display-username-cyphertext' ],
2023-02-07 21:25:16 +00:00
'' ,
2023-01-21 03:14:40 +00:00
$_SESSION [ 'display-username-nonce' ],
base64_decode ( $_COOKIE [ 'display-username-decryption-key' ])
));
if ( $decryption_result === false )
output ( 403 , 'Unable to decrypt display username.' );
define ( 'DISPLAY_USERNAME' , $decryption_result );
2023-03-09 00:35:30 +00:00
// Enable not already enabled services for this user
$user_services = array_filter ( explode ( ',' , query ( 'select' , 'users' , [ 'id' => $_SESSION [ 'id' ]], 'services' )[ 0 ]));
if ( in_array ( SERVICE , SERVICES_USER , true ) AND ! in_array ( SERVICE , $user_services , true ) AND CONF [ 'common' ][ 'services' ][ SERVICE ] === 'enabled' ) {
$user_services [] = SERVICE ;
2022-09-09 19:53:31 +00:00
2023-03-09 00:35:30 +00:00
DB -> prepare ( 'UPDATE users SET services = :services WHERE id = :id' )
-> execute ([ ':services' => implode ( ',' , $user_services ), ':id' => $_SESSION [ 'id' ]]);
if ( SERVICE === 'ht' )
htSetupUserFs ( $_SESSION [ 'id' ]);
}
2022-11-21 23:28:19 +00:00
}
2022-12-20 20:17:03 +00:00
function displayFinalMessage ( $data ) {
if ( isset ( $data [ 'final_message' ])) {
echo $data [ 'final_message' ];
unset ( $data [ 'final_message' ]);
}
2022-11-20 00:05:03 +00:00
}
2022-12-20 20:17:03 +00:00
if ( $_POST !== []) {
2023-05-09 23:34:45 +00:00
if ( ! in_array ( CONF [ 'common' ][ 'services' ][ 'auth' ], [ 'enabled' , 'no-registration' ], true ) OR ( in_array ( SERVICE , SERVICES_USER , true ) AND CONF [ 'common' ][ 'services' ][ SERVICE ] !== 'enabled' ))
2023-03-09 00:35:30 +00:00
output ( 503 , _ ( 'This service is currently under maintenance. No action can be taken on it until an administrator finishes repairing it.' ));
// Protect against cross-site request forgery if a POST request is received
if ( isset ( $_SERVER [ 'HTTP_SEC_FETCH_SITE' ]) !== true )
output ( 403 , 'The <code>Sec-Fetch-Site</code> HTTP header is required when submitting a POST request to prevent Cross-Site Request Forgery (<abbr>CSRF</abbr>).' );
2023-03-18 17:40:04 +00:00
if ( ! in_array ( $_SERVER [ 'HTTP_SEC_FETCH_SITE' ], [ 'none' , 'same-origin' ], true ))
output ( 403 , 'The <code>Sec-Fetch-Site</code> HTTP header must be <code>same-origin</code> or <code>none</code> when submitting a POST request to prevent Cross-Site Request Forgery (<abbr>CSRF</abbr>).' );
2023-03-09 00:35:30 +00:00
2022-12-20 20:17:03 +00:00
if ( PAGE_METADATA [ 'require-login' ] ? ? true !== false ) {
if ( isset ( $_SESSION [ 'id' ]) !== true )
2023-01-21 00:27:52 +00:00
output ( 403 , _ ( 'You need to be logged in to do this.' ));
2022-12-20 20:17:03 +00:00
if ( isset ( query ( 'select' , 'users' , [ 'id' => $_SESSION [ 'id' ]], 'id' )[ 0 ]) !== true )
2023-01-21 00:27:52 +00:00
output ( 403 , _ ( 'This account doesn\'t exist anymore. Log out to end this ghost session.' ));
2022-12-20 20:17:03 +00:00
}
2023-03-09 00:35:30 +00:00
2023-04-09 22:50:42 +00:00
if ( file_exists ( ROOT_PATH . '/pg-act/' . PAGE_ADDRESS . '.php' ))
require ROOT_PATH . '/pg-act/' . PAGE_ADDRESS . '.php' ;
2022-12-20 20:17:03 +00:00
}
2022-09-09 19:53:31 +00:00
2022-12-20 20:17:03 +00:00
function displayPage ( $data ) {
2023-04-09 22:50:42 +00:00
require ROOT_PATH . '/view.php' ;
2022-09-09 19:53:31 +00:00
exit ();
2022-09-07 16:44:49 +00:00
}
2022-12-20 20:17:03 +00:00
displayPage ( $data ? ? = NULL );