File: /var/www/html/triad-infosec/wp-content/plugins/wpforms/src/Pro/Access/File.php
<?php
namespace WPForms\Pro\Access;
use WPForms\Helpers\File as FileHelper;
use WPForms\Pro\Forms\Fields\FileUpload\Field as FileUploadField;
use WPForms\Pro\Db\Files\ProtectedFiles;
/**
* File class.
*
* @since 1.9.4
*/
class File {
/**
* Check if the current page is a file page.
*
* @since 1.9.4
*
* @return bool True if the current page is a file page, false otherwise.
*/
private function is_file_page(): bool {
return ! empty( $_GET['wpforms_uploaded_file'] ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended
}
/**
* Initialize.
*
* @since 1.9.4
*/
public function init(): void {
if ( ! $this->is_file_page() ) {
return;
}
$this->hooks();
}
/**
* Hooks.
*
* @since 1.9.4
*/
private function hooks(): void {
add_action( 'template_redirect', [ $this, 'download_template' ] );
add_action( 'wp_enqueue_scripts', [ $this, 'enqueue_scripts' ] );
add_filter( 'body_class', [ $this, 'body_class' ] );
add_filter( 'qm/dispatch/html', '__return_false' );
add_filter( 'show_admin_bar', '__return_false' );
}
/**
* Enqueue scripts.
*
* @since 1.9.4
*/
public function enqueue_scripts(): void {
$min = wpforms_get_min_suffix();
$styles = wp_styles();
// Dequeue all styles.
foreach ( $styles->queue as $style ) {
wp_dequeue_style( $style );
}
wp_enqueue_style(
'wpforms-download-page',
WPFORMS_PLUGIN_URL . "assets/pro/css/frontend/file-download/wpforms-protection-page{$min}.css",
[],
WPFORMS_VERSION
);
}
/**
* Download template.
*
* @since 1.9.4
*/
public function download_template(): void {
$protection_hash = $this->get_protection_hash();
$protected_file = wpforms()->obj( 'protected_files' )->get_by_hash( $protection_hash );
// If the hash is not found, redirect to the home page.
if ( ! $protected_file ) {
wp_safe_redirect( home_url() );
exit;
}
$restriction_id = $protected_file->restriction_id ?? 0;
$restriction = wpforms()->obj( 'file_restrictions' )->get( $restriction_id );
if ( ! $this->is_access_granted( $restriction ) ) {
$this->render_access_denied();
}
// Get the password page.
$password_page = $this->get_password_page( $restriction );
if ( ! empty( $password_page ) ) {
echo $password_page; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
exit;
}
/**
* Fires before the download page is rendered.
*
* @since 1.9.4
*
* @param ProtectedFiles $protected_file Protected file object.
*/
do_action( 'wpforms_pro_access_file_download_template_before_download', $protected_file );
// If all checks passed, render the download page.
$this->render_download_page( $protected_file );
}
/**
* Check if the current user has access to the file.
*
* @since 1.9.4
*
* @param object $restriction File restriction object.
*
* @return bool True if the user has access to the file, false otherwise.
*/
private function is_access_granted( $restriction ): bool {
$restriction_rules = ! empty( $restriction->rules ) ? (array) maybe_unserialize( $restriction->rules ) : [];
$user_restrictions = $restriction_rules['user_restrictions'] ?? 'none';
$only_logged_in = $user_restrictions === 'logged';
// If the file is protected and only logged-in users can access it, check if the user is logged in.
if ( $only_logged_in && ! is_user_logged_in() ) {
return false;
}
$current_user = wp_get_current_user();
// Check if the current user has access to the file by user role.
$allow_by_role = $this->allow_by_role( $current_user, $restriction_rules );
if ( $allow_by_role ) {
return true;
}
// Check if the current user has access to the file by user ID.
return $this->allow_by_name( $current_user, $restriction_rules );
}
/**
* Check if the current user has access to the file by user name.
*
* @since 1.9.4
*
* @param object $current_user Current user object.
* @param array $restriction_rules Restriction rules.
*
* @return bool True if the user has access to the file, false otherwise.
*/
private function allow_by_name( $current_user, array $restriction_rules ): bool {
$user_ids = json_decode( $restriction_rules['user_names_restrictions'] ?? '', true ) ?? [];
if ( empty( $user_ids ) ) {
return false;
}
$user_ids = array_map( 'intval', $user_ids );
// Check if the current user has access to the file by user ID.
if ( in_array( $current_user->ID, $user_ids, true ) ) {
return true;
}
return false;
}
/**
* Check if the current user has access to the file by user role.
*
* @since 1.9.4
*
* @param object $current_user Current user object.
* @param array $restriction_rules Restriction rules.
*
* @return bool True if the user has access to the file, false otherwise.
*/
private function allow_by_role( $current_user, array $restriction_rules ): bool {
$current_user_roles = $current_user->roles ?? [];
$user_roles = json_decode( $restriction_rules['user_roles_restrictions'] ?? '', true ) ?? [];
$has_role = array_intersect( $current_user_roles, $user_roles );
// Check if the current user has access to the file by user role.
if ( empty( $has_role ) && ! empty( $user_roles ) ) {
return false;
}
return true;
}
/**
* Render the access denied page.
*
* @since 1.9.4
*/
private function render_access_denied(): void {
echo wpforms_render( 'frontend/file/file-protected' ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
exit;
}
/**
* Render the file not found page.
*
* @since 1.9.4
*/
private function render_file_not_found(): void {
echo wpforms_render( 'frontend/file/file-not-found' ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
exit;
}
/**
* Get the password page.
*
* @since 1.9.4
*
* @param object $restriction File restriction object.
*
* @return string The password page.
*/
private function get_password_page( $restriction ): string {
$protected_by_password = ! empty( $restriction->password );
// Check if password protects the file.
if ( $protected_by_password ) {
$error_message = '';
$nonce = isset( $_POST['nonce'] ) ? sanitize_key( $_POST['nonce'] ) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Recommended
if ( wp_verify_nonce( $nonce, 'wpforms-file-password' ) ) {
$password = isset( $_POST['wpforms_file_password'] ) ? sanitize_text_field( wp_unslash( $_POST['wpforms_file_password'] ) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Recommended
if ( wp_check_password( $password, $restriction->password ) ) {
return '';
}
$error_message = esc_html__( 'Sorry, the password you entered is incorrect.', 'wpforms' );
}
return $this->get_password_required_form( $error_message );
}
return '';
}
/**
* Render the password required page.
*
* @since 1.9.4
*
* @param string $error_message Error message.
*/
private function get_password_required_form( string $error_message = '' ): string {
return wpforms_render( 'frontend/file/file-password-required', [ 'error' => $error_message ], true ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
}
/**
* Render the download page.
*
* @since 1.9.4
*
* @param object $protected_file Protected file object.
*/
private function render_download_page( $protected_file ): void {
$file_path = $this->get_file_path( $protected_file );
if ( ! $file_path || ! file_exists( $file_path ) ) {
$this->render_file_not_found();
}
wpforms()->obj( 'protected_files' )->update_last_usage( $protected_file->id );
header( 'Content-Description: File Transfer' );
header( 'Content-Type: application/octet-stream' );
header( 'Content-Disposition: attachment; filename="' . basename( $file_path ) . '"' );
header( 'Content-Transfer-Encoding: binary' );
header( 'Expires: 0' );
header( 'Cache-Control: must-revalidate' );
header( 'Pragma: public' );
header( 'Content-Length: ' . filesize( $file_path ) );
echo FileHelper::get_contents( $file_path ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
exit;
}
/**
* Get the protection hash from the URL.
*
* @since 1.9.4
*
* @return string The sanitized protection hash.
*/
private function get_protection_hash(): string {
return sanitize_key( $_GET['wpforms_uploaded_file'] ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended, WordPress.Security.ValidatedSanitizedInput.InputNotValidated
}
/**
* Get the file path.
*
* @since 1.9.4
*
* @param object $protected_file Protected file object.
*
* @return string The file path.
*/
private function get_file_path( $protected_file ): string {
$form_id = $protected_file->form_id;
$file_name = $protected_file->file;
$form_file_path = FileUploadField::get_form_files_path( $form_id );
return FileUploadField::get_file_path( 0, $file_name, $form_file_path );
}
/**
* Add custom body class.
*
* @since 1.9.4
*
* @param array $classes Body classes.
*
* @return array
*/
public function body_class( $classes ): array {
$classes = (array) $classes;
$classes[] = 'wpforms-file-download';
return $classes;
}
}