芝麻web文件管理V1.00
编辑当前文件:/home/projzpbv/public_html/wp-content/plugins/ninja-forms/blocks/bootstrap.php
esc_attr__('Ninja Form', 'ninja-forms'), 'render_callback' => function ($atts) { $formID = isset($atts['formID']) ? $atts['formID'] : 1; ob_start(); Ninja_Forms()->display( absint($formID), true ); return ob_get_clean(); }, 'editor_script' => 'ninja-forms/form' ])); /** * Views Block */ // automatically load dependencies and version $block_asset_file = include dirname(__DIR__) . '/build/sub-table-block.asset.php'; wp_register_script( 'ninja-forms/submissions-table/block', plugins_url('../build/sub-table-block.js', __FILE__), $block_asset_file['dependencies'], $block_asset_file['version'] ); // Note: Token will be generated per-page in render_callback with specific form IDs $render_asset_file = include dirname(__DIR__) . '/build/sub-table-render.asset.php'; wp_register_script( 'ninja-forms/submissions-table/render', plugins_url('../build/sub-table-render.js', __FILE__), $render_asset_file['dependencies'], $render_asset_file['version'] ); register_block_type('ninja-forms/submissions-table', array( 'editor_script' => 'ninja-forms/submissions-table/block', 'render_callback' => function ($attributes, $content) { if (isset($attributes['formID']) && $attributes['formID']) { wp_enqueue_script('ninja-forms/submissions-table/render'); // Generate a token bound to THIS specific form ID only $formId = absint($attributes['formID']); $token = NinjaForms\Blocks\Authentication\TokenFactory::make(); $publicKey = NinjaForms\Blocks\Authentication\KeyFactory::make(); // Create token with form ID binding and expiration wp_localize_script('ninja-forms/submissions-table/render', 'ninjaFormsViews', [ 'token' => $token->create($publicKey, array($formId)), ]); $className = 'ninja-forms-views-submissions-table'; if (isset($attributes['alignment'])) { $className .= ' align' . $attributes['alignment']; } return sprintf("
", esc_attr($className), esc_attr(wp_json_encode($attributes))); } } )); /** * Have Translations set in scripts via i18n package * https://developer.wordpress.org/block-editor/packages/packages-i18n/ * https://developer.wordpress.org/reference/functions/wp_set_script_translations/ * https://developer.wordpress.org/block-editor/developers/internationalization/ */ wp_set_script_translations( "ninja-forms/form", "ninja-forms", plugin_dir_path( __FILE__ ) . 'lang' ); wp_set_script_translations( "ninja-forms/submissions-table/block", "ninja-forms", plugin_dir_path( __FILE__ ) . 'lang' ); wp_set_script_translations( "ninja-forms/submissions-table/render", "ninja-forms", plugin_dir_path( __FILE__ ) . 'lang' ); }); /** * Localize data for blocks */ add_action('admin_enqueue_scripts', function () { //Conditionally load data for Blocks $screen = get_current_screen(); if( is_null( $screen ) ) return; if( ! $screen->is_block_editor() ) return; //Get all forms, to base form selector on. $formsBuilder = (new NinjaForms\Blocks\DataBuilder\FormsBuilderFactory)->make(); $forms = $formsBuilder->get(); if (!empty($forms)) { //Escape for use in JavaScript foreach ($forms as $key => $form) { $forms[$key] = [ 'formID' => absint($form['formID']), 'formTitle' => esc_textarea($form['formTitle']) ]; } } wp_localize_script('ninja-forms/form', 'nfFormsBlock', [ 'forms' => $forms,//array keys escaped above 'homeUrl' => esc_url_raw( home_url() ), //URL to serve the iFrame that displays the form in blocks editor 'previewToken' => wp_create_nonce('nf_iframe' ) ]); // For block editor, provide a token that allows access to all forms // This is safe because it's only loaded in admin context with proper capability checks $token = NinjaForms\Blocks\Authentication\TokenFactory::make(); $publicKey = NinjaForms\Blocks\Authentication\KeyFactory::make(); $allFormIds = array_map(function($form) { return absint($form['formID']); }, $forms); wp_localize_script('ninja-forms/submissions-table/block', 'ninjaFormsViews', [ 'token' => $token->create($publicKey, $allFormIds), ]); }); /** * Register REST API routes related to blocks */ add_action('rest_api_init', function () { /** * Enhanced permission callback that validates token and checks form-level authorization. * * Security improvements: * - Rate limiting to prevent DoS attacks * - Validates token authenticity (hash, expiration) * - Checks if token is authorized for the requested form ID * - Falls back to WordPress capability check for admin users * * @param WP_REST_Request $request * @return bool|WP_Error */ $tokenAuthenticationCallback = function (WP_REST_Request $request) { // Check rate limit first (lightweight check) $endpoint = $request->get_route(); $rateLimitCheck = NinjaForms\Blocks\Authentication\RateLimiter::check($endpoint); if (is_wp_error($rateLimitCheck)) { return $rateLimitCheck; } $tokenValidator = NinjaForms\Blocks\Authentication\TokenFactory::make(); $tokenHeader = $request->get_header('X-NinjaFormsViews-Auth'); $formId = $request->get_param('id'); // If user is logged in and has manage_options capability, allow access // This provides fallback for admin users if (is_user_logged_in() && current_user_can('manage_options')) { return true; } // Validate token with form ID authorization if ($formId) { return $tokenValidator->validate($tokenHeader, intval($formId)); } // For routes without a specific form ID (like /forms list), only validate token structure // The token must still be valid (not expired, proper signature) return $tokenValidator->validate($tokenHeader); }; register_rest_route('ninja-forms-views', 'forms', array( 'methods' => 'GET', 'callback' => function (WP_REST_Request $request) { $tokenValidator = NinjaForms\Blocks\Authentication\TokenFactory::make(); $tokenHeader = $request->get_header('X-NinjaFormsViews-Auth'); // Get all forms $formsBuilder = (new NinjaForms\Blocks\DataBuilder\FormsBuilderFactory)->make(); $allForms = $formsBuilder->get(); // If user has manage_options capability, return all forms if (is_user_logged_in() && current_user_can('manage_options')) { return $allForms; } // Otherwise, filter forms based on token authorization $authorizedFormIds = $tokenValidator->getFormIds($tokenHeader); if ($authorizedFormIds === false) { return new WP_Error('invalid_token', 'Invalid token', array('status' => 403)); } // Filter to only return forms the token has access to $filteredForms = array_filter($allForms, function($form) use ($authorizedFormIds) { return in_array(intval($form['formID']), $authorizedFormIds, true); }); return array_values($filteredForms); }, 'permission_callback' => $tokenAuthenticationCallback, )); register_rest_route('ninja-forms-views', 'forms/(?P
\d+)/fields', [ 'methods' => 'GET', 'args' => [ 'id' => [ 'required' => true, 'description' => esc_attr__('Unique identifier for the object.', 'ninja-forms'), 'type' => 'integer', 'validate_callback' => 'rest_validate_request_arg', ], ], 'callback' => function (WP_REST_Request $request) { $fieldsBuilder = (new NinjaForms\Blocks\DataBuilder\FieldsBuilderFactory)->make( $request->get_param('id') ); return $fieldsBuilder->get(); }, 'permission_callback' => $tokenAuthenticationCallback, ]); register_rest_route('ninja-forms-views', 'forms/(?P
\d+)/submissions', [ 'methods' => 'GET', 'args' => [ 'id' => [ 'required' => true, 'description' => esc_attr__('Unique identifier for the object.', 'ninja-forms'), 'type' => 'integer', 'validate_callback' => 'rest_validate_request_arg', ], 'perPage' => [ 'description' => esc_attr__('Maximum number of items to be returned in result set.', 'ninja-forms'), 'type' => 'integer', 'minimum' => 1, 'maximum' => 100, 'sanitize_callback' => 'absint', 'validate_callback' => 'rest_validate_request_arg', ], 'page' => [ 'description' => esc_attr__('Current page of the collection.', 'ninja-forms'), 'type' => 'integer', 'default' => 1, 'sanitize_callback' => 'absint', 'validate_callback' => 'rest_validate_request_arg', 'minimum' => 1, ] ], 'callback' => function (WP_REST_Request $request) { $submissionsBuilder = (new NinjaForms\Blocks\DataBuilder\SubmissionsBuilderFactory)->make( $request->get_param('id'), $request->get_param('perPage'), $request->get_param('page') ); return $submissionsBuilder->get(); }, 'permission_callback' => $tokenAuthenticationCallback, ]); /** * Token Refresh Endpoint * * Generates a new token scoped to requested form IDs. * Used for automatic token refresh when tokens expire or after secret rotation. * * FIX: Restricts token generation to single forms and validates form access */ register_rest_route('ninja-forms-views', 'token/refresh', array( 'methods' => 'POST', 'callback' => function (WP_REST_Request $request) { // REFACTOR: Accept single formID instead of formIds array $formId = $request->get_param('formID'); // Check for legacy formIds parameter for backward compatibility if (!$formId && $request->get_param('formIds')) { $formIds = $request->get_param('formIds'); if (is_array($formIds) && !empty($formIds)) { // Only accept single form from legacy array if (count($formIds) > 1) { return new WP_Error( 'too_many_form_ids', __('Token generation is limited to one form at a time. Please use formID parameter instead.', 'ninja-forms'), array('status' => 400) ); } $formId = $formIds[0]; } } // Sanitize and validate form ID $formId = absint($formId); if (!$formId) { return new WP_Error( 'invalid_form_id', __('Valid form ID is required', 'ninja-forms'), array('status' => 400) ); } // FIX: Validate that the form exists and is accessible $form = Ninja_Forms()->form( $formId )->get(); if (!$form) { return new WP_Error( 'form_not_found', __('The requested form does not exist', 'ninja-forms'), array('status' => 404) ); } // FIX: Validate that user has permission to access this form // This prevents users from generating tokens for arbitrary forms $referer = wp_get_referer(); if (!$referer) { return new WP_Error( 'invalid_request', __('Request must come from a valid page with submissions table block', 'ninja-forms'), array('status' => 403) ); } // Parse the referring page to validate block authorization $post_id = url_to_postid($referer); if (!$post_id) { // Handle front page, archives, etc. $parsed_url = parse_url($referer); if ($parsed_url['path'] === '/' || $parsed_url['path'] === home_url('/')) { $post_id = get_option('page_on_front'); } } // Check if the form is actually embedded in a submissions table block on this page if ($post_id) { $post = get_post($post_id); $is_public = is_post_publicly_viewable( $post ); // If post is public _and_ password-protected, but user hasn't provided a valid password if( $is_public && post_password_required( $post ) ) { return new WP_Error( 'unauthorized_form_access', __('You do not have permission to access this form via this page', 'ninja-forms'), array('status' => 403) ); } // If post is private or just generally not public, and logged-in user cannot read it if( ! $is_public && ! current_user_can( 'read_post', $post ) ) { return new WP_Error( 'unauthorized_form_access', __('You do not have permission to access this form via this page', 'ninja-forms'), array('status' => 403) ); } if ($post && has_blocks($post->post_content)) { $blocks = parse_blocks($post->post_content); $found_authorized_form = false; // Recursively search for ninja-forms/submissions-table blocks $search_blocks = function($blocks) use ($formId, &$found_authorized_form, &$search_blocks) { foreach ($blocks as $block) { if ($block['blockName'] === 'ninja-forms/submissions-table') { if (isset($block['attrs']['formID']) && intval($block['attrs']['formID']) === $formId) { $found_authorized_form = true; return; } } // Search inner blocks recursively if (!empty($block['innerBlocks'])) { $search_blocks($block['innerBlocks']); } } }; $search_blocks($blocks); if (!$found_authorized_form) { return new WP_Error( 'unauthorized_form_access', __('You do not have permission to access this form via this page', 'ninja-forms'), array('status' => 403) ); } } } else { // If we can't determine the post ID, return an error return new WP_Error( 'post_id_not_found', __('The requested data could not be related to a valid page', 'ninja-forms'), array('status' => 403) ); } // Generate new token scoped to the single requested form $publicKey = NinjaForms\Blocks\Authentication\KeyFactory::make(32); $tokenGenerator = NinjaForms\Blocks\Authentication\TokenFactory::make(); $newToken = $tokenGenerator->create($publicKey, array($formId)); return array( 'token' => $newToken, 'publicKey' => $publicKey, 'expiresIn' => 900, // 15 minutes in seconds 'formID' => $formId, // Changed from formIds to formID ); }, 'permission_callback' => function (WP_REST_Request $request) { // Apply stricter rate limiting to refresh endpoint $rateLimitCheck = NinjaForms\Blocks\Authentication\RateLimiter::check( '/ninja-forms-views/token/refresh', 50, // limit: 50 requests 300 // window: 5 minutes ); if (is_wp_error($rateLimitCheck)) { return $rateLimitCheck; // Returns 429 Too Many Requests } return true; // Public endpoint (rate-limited) but with form validation }, )); }); /** * Handler for form preview iFrame used in Forms block */ add_action( 'wp_head', function () { // check for preview and iframe get parameters if( isset( $_GET[ 'nf_preview_form' ] ) && isset( $_GET[ 'nf_iframe' ] ) ){ if( ! wp_verify_nonce( $_GET['nf_iframe'], 'nf_iframe') ){ wp_die( esc_html__('Preview token failed validation', 'ninja-forms')); exit; } //Attempt to get theme background color $background = '#fff'; $supports = get_theme_support('editor-color-palette','background'); if( is_array($supports) ){ foreach($supports[0] as $index => $support ){ if( 'background' === $support['slug']){ $background = $support['color']; break; } } } $js_lib_dir = Ninja_Forms::$url . 'assets/js/lib/'; $form_id = absint( $_GET[ 'nf_preview_form' ] ); // Style below: update width and height for particular form ?> $form_id ) ); wp_enqueue_script( 'ninja-forms-block-setup' ); } }); /** * Schedule WP-Cron job for automatic secret rotation */ add_action('init', function() { if (!wp_next_scheduled('ninja_forms_views_check_rotation')) { wp_schedule_event(time(), 'daily', 'ninja_forms_views_check_rotation'); } }); /** * WP-Cron callback: Check if secret should be rotated and rotate if needed */ add_action('ninja_forms_views_check_rotation', function() { if (NinjaForms\Blocks\Authentication\SecretStore::shouldRotate()) { NinjaForms\Blocks\Authentication\SecretStore::rotate(); } }); /** * Clear scheduled events on plugin deactivation */ register_deactivation_hook(__FILE__, function() { $timestamp = wp_next_scheduled('ninja_forms_views_check_rotation'); if ($timestamp) { wp_unschedule_event($timestamp, 'ninja_forms_views_check_rotation'); } });