*/ function ptcp_get_id_data( $ptcpId, $message = NULL ){ global $IdProviders; foreach ( $IdProviders as $provider ){ $idData = $provider->get_info( $ptcpId, $message ); if ( $idData ){ break; } } return $idData ?? FALSE; } function ptcp_handle_message( $message, $receipt ){ global $MessageHandlers; foreach ( $MessageHandlers as $classOrObject ){ $methodName = 'handle_' . str_replace( '-', '_', $message->get('Message-Type') ); if ( ! method_exists( $classOrObject, $methodName ) ){ continue; } $result = call_user_func( [ $classOrObject, $methodName ], $message, $receipt ); if ( $result !== FALSE ){ return $result; } } foreach ( $MessageHandlers as $classOrObject ){ if ( ! method_exists( $classOrObject, 'router' ) ){ continue; } $methodName = call_user_func( [ $classOrObject, 'router' ], $message->get('Message-Type') ); if ( $methodName !== FALSE && method_exists( $classOrObject, $methodName ) ){ $result = call_user_func( [ $classOrObject, $methodName ], $message, $receipt ); if ( $result !== FALSE ){ return $result; } } } return FALSE; } function ptcp_is_authorized( $ptcpId, $messageType, $object = NULL ){ global $AuthCheckers; foreach ( $AuthCheckers as $classOrObject ){ $result = call_user_func( [ $classOrObject, 'is_authorized' ], $ptcpId, $messageType, $object ); if ( $result !== NULL ){ return $result; } } return FALSE; } function ptcp_is_in_list( $ptcpId, $ptcpList ){ global $ServerData; if ( ! strpos( $ptcpId, '@' ) ){ $ptcpId .= '@' . $ServerData['name']; } foreach ( $ptcpList as $key => $id ){ if ( ! strpos( $id, '@' ) ){ $ptcpList[ $key ] .= '@' . $ServerData['name']; } } return in_array( $ptcpId, $ptcpList ); } function ptcp_local_decrypt( $string ){ global $ServerData; static $secret; if ( empty( $secret ) ){ $keyPair = ParTCP_Server_Key_Storage::get_keypair( $ServerData['name'] ); $secret = hash( 'sha256', $keyPair[1], TRUE ); } list( $iv, $encrypted ) = explode( ':', $string ) + [ '', '' ]; $iv = base64_decode( $iv ); if ( ! $iv || strlen( $iv ) != 16 ){ return $string; } return openssl_decrypt( $encrypted, 'aes-256-cbc', $secret, 0, $iv ); } function ptcp_local_encrypt( $value ){ global $ServerData; static $secret; if ( empty( $secret ) ){ $keyPair = ParTCP_Server_Key_Storage::get_keypair( $ServerData['name'] ); $secret = hash( 'sha256', $keyPair[1], TRUE ); } if ( is_array( $value ) ){ $value = json_encode( $value ); } $iv = openssl_random_pseudo_bytes( 16 ); $encrypted = openssl_encrypt( $value, 'aes-256-cbc', $secret, 0, $iv ); return base64_encode( $iv ) . ':' . $encrypted; } function ptcp_register_auth_checker( $classOrObject, $highPrio = FALSE ){ global $AuthCheckers; if ( $highPrio ){ array_unshift( $AuthCheckers, $classOrObject ); } else { array_push( $AuthCheckers, $classOrObject ); } } function ptcp_register_id_provider( $classOrObject, $highPrio = FALSE ){ global $IdProviders; if ( $highPrio ){ array_unshift( $IdProviders, $classOrObject ); } else { array_push( $IdProviders, $classOrObject ); } } function ptcp_register_message_handler( $classOrObject, $highPrio = FALSE ){ global $MessageHandlers; if ( $highPrio ){ array_unshift( $MessageHandlers, $classOrObject ); } else { array_push( $MessageHandlers, $classOrObject ); } } function ptcp_subdir_rules( $estimatedTotal ){ global $Config; $itemsPerDirectory = $Config['max_items_per_dir'] ?? $Config['Max-Items-Per-Directory'] ?? 9999; $directoriesNeeded = ceil( $estimatedTotal / $itemsPerDirectory ); $totalPathLength = ceil( log( $directoriesNeeded, 16 ) ); $maxDirNameLength = floor( log( $itemsPerDirectory, 16 ) ); $subdirDepth = ceil( $totalPathLength / $maxDirNameLength ); $subdirNameLength = $subdirDepth ? ceil( $totalPathLength / $subdirDepth ) : 0; return [ (int) $subdirDepth, (int) $subdirNameLength ]; } function ptcp_update_object( &$object, $newData ){ $hasChanged = FALSE; foreach ( $newData as $key => $value ){ if ( is_null( $value ) && isset( $object[ $key ] ) ){ unset( $object[ $key ] ); $hasChanged = TRUE; } elseif ( is_array( $value ) && is_string( array_keys( $value )[0] ) && isset( $object[ $key ] ) && is_array( $object[ $key ] ) ){ if ( ptcp_update_object( $object[ $key ], $value ) ){ $hasChanged = TRUE; } } elseif ( ! isset( $object[ $key ] ) || $object[ $key ] != $value ){ $object[ $key ] = $value; $hasChanged = TRUE; } } return $hasChanged; } function ptcp_yaml_emit( $data ){ $yaml = trim( yaml_emit( $data, YAML_UTF8_ENCODING ) ); if ( substr( $yaml, 0, 4 ) == "---\n" ){ $yaml = substr( $yaml, 4 ); } if ( substr( $yaml, -4 ) == "\n..." ){ $yaml = substr( $yaml, 0, -4 ); } return $yaml; } // Main script header( 'Access-Control-Allow-Origin: *' ); header( 'Access-Control-Allow-Methods: GET, POST, OPTIONS' ); header( 'Access-Control-Allow-Headers: Accept, Authorization, ' . 'Access-Control-Allow-Origin, Content-Type, Content-Length, Cookie, Origin, ' . 'User-Agent, X-Partcp-Version, X-Partcp-Kx-Method' ); include 'config.php'; $Timestamp = time(); $BaseDir = __DIR__; $RequestHeaders = function_exists('apache_request_headers') ? array_change_key_case( apache_request_headers() ) : []; $PartcpVersion = $RequestHeaders['x-partcp-version'] ?? '0.8'; $MessageHandlers = []; $AuthCheckers = []; $IdProviders = []; $Counter = NULL; $Shortcoder = NULL; $ServerData = $Config['server_data'] ?? $Config['Server-Data'] ?? []; if ( empty( $ServerData['name'] ) ){ $ServerData['name'] = $_SERVER['SERVER_NAME']; } $BaseUrl = $Config['base_url'] ?? "https://{$ServerData['name']}"; require_once 'lib/partcp-php/crypto.class.php'; ParTCP_Crypto::$useLegacyKx = empty( $RequestHeaders['x-partcp-kx-method'] ); require_once 'lib/partcp-php/key_storage_fs.class.php'; require_once 'lib/partcp-php/identity.class.php'; require_once 'lib/partcp-php/incoming_message.class.php'; require_once 'lib/partcp-php/outgoing_message.class.php'; require_once 'lib/partcp-php/partcp.class.php'; require_once 'lib/server_key_storage.class.php'; // Initialize file system $WormDir = $Config['path_to_worm'] ?? $Config['Worm-Directory'] ?? "{$BaseDir}/worm"; $DataDir = $Config['path_to_data'] ?? $Config['Data-Directory'] ?? "{$BaseDir}/data"; $rootDirs[] = $WormDir; if ( file_exists( "{$WormDir}/_continuations" ) ){ $listing = glob( "{$WormDir}/_continuations/[0-9]*" ); foreach ( $listing as $file ){ $dir = file_get_contents( $file ); if ( $dir && file_exists( $dir ) ){ array_unshift( $rootDirs, $point ); } } } require_once "{$BaseDir}/lib/file_system.class.php"; $FileSystem = new ParTCP_File_System( $rootDirs ); // Initialize Partcp module $dir = $Config['path_to_keys'] ?? $Config['Key-Directory'] ?? NULL; if ( ! $dir ){ ptcp_error( _('Key directory not specified') ); } $Partcp = new ParTCP( 'ParTCP_Server_Key_Storage', [ 'storageDir' => $dir ] ); $localId = $Partcp->set_local_id( $ServerData['name'], TRUE, TRUE ); // Load modules require_once 'lib/mtd_manager.class.php'; $MtdManager = new Mtd_Manager( [ __DIR__ . '/mtd' ] ); if ( ! empty( $ServerData['modules'] ) ){ foreach ( $ServerData['modules'] as $module ){ $path = "{$BaseDir}/modules/{$module}/init.php"; if ( file_exists( $path ) ){ include $path; } else { ptcp_error( sprintf( _('Module %s could not be initialized'), $module ) ); } } } // Initialize localisation if ( ! empty( $ServerData['locale'] ) ){ putenv( "LANG={$ServerData['locale']}" ); setlocale( LC_ALL, $ServerData['locale'] ); bindtextdomain( 'messages', "{$BaseDir}/locale" ); textdomain('messages'); } // end of file initialize.php