Changeset 3399346
- Timestamp:
- 11/20/2025 03:38:02 AM (4 months ago)
- Location:
- easy-invoice
- Files:
-
- 8 edited
- 1 copied
-
tags/2.1.5 (copied) (copied from easy-invoice/trunk)
-
tags/2.1.5/easy-invoice.php (modified) (2 diffs)
-
tags/2.1.5/includes/Controllers/InvoiceController.php (modified) (4 diffs)
-
tags/2.1.5/includes/Controllers/QuoteController.php (modified) (3 diffs)
-
tags/2.1.5/readme.txt (modified) (2 diffs)
-
trunk/easy-invoice.php (modified) (2 diffs)
-
trunk/includes/Controllers/InvoiceController.php (modified) (4 diffs)
-
trunk/includes/Controllers/QuoteController.php (modified) (3 diffs)
-
trunk/readme.txt (modified) (2 diffs)
Legend:
- Unmodified
- Added
- Removed
-
easy-invoice/tags/2.1.5/easy-invoice.php
r3393362 r3399346 4 4 * Plugin URI: https://matrixaddons.com/plugins/easy-invoice 5 5 * Description: A beautiful, full-featured invoicing solution for WordPress. Create professional invoices, quotes, and manage payments with ease. 6 * Version: 2.1. 46 * Version: 2.1.5 7 7 * Author: MatrixAddons 8 8 * Author URI: https://matrixaddons.com … … 25 25 26 26 // Define plugin constants. 27 define( 'EASY_INVOICE_VERSION', '2.1. 4' );27 define( 'EASY_INVOICE_VERSION', '2.1.5' ); 28 28 define( 'EASY_INVOICE_PLUGIN_FILE', __FILE__ ); 29 29 define( 'EASY_INVOICE_PLUGIN_DIR', plugin_dir_path( __FILE__ ) ); -
easy-invoice/tags/2.1.5/includes/Controllers/InvoiceController.php
r3377511 r3399346 795 795 } 796 796 797 // Get template name 797 // Get template name and validate it securely 798 798 $template = isset($_POST['template']) ? sanitize_text_field($_POST['template']) : 'standard'; 799 $template = $this->validateTemplateName($template, 'invoice'); 799 800 $invoice_id = isset($_POST['invoice_id']) ? intval($_POST['invoice_id']) : 0; 801 802 // Get secure template file path 803 $template_file = $this->getSecureTemplatePath($template, 'invoice'); 804 805 if (!$template_file) { 806 wp_send_json_error(array('message' => __('Invalid template', 'easy-invoice'))); 807 } 800 808 801 809 // For new invoices (no ID), just return the template without invoice data 802 810 if ($invoice_id === 0) { 803 // Get template file path804 $template_file = EASY_INVOICE_PLUGIN_DIR . 'templates/invoice-templates/' . $template . '.php';805 806 if (!file_exists($template_file)) {807 $template_file = EASY_INVOICE_PLUGIN_DIR . 'templates/invoice-templates/standard.php';808 }809 810 811 // Start output buffering 811 812 ob_start(); … … 815 816 $formatter = null; 816 817 817 818 818 include_once $template_file; 819 819 $html = ob_get_clean(); … … 834 834 // Initialize formatter for currency formatting 835 835 $formatter = new \EasyInvoice\Helpers\InvoiceFormatter($invoice); 836 837 // Get template file path838 $template_file = EASY_INVOICE_PLUGIN_DIR . 'templates/invoice-templates/' . $template . '.php';839 840 if (!file_exists($template_file)) {841 $template_file = EASY_INVOICE_PLUGIN_DIR . 'templates/invoice-templates/standard.php';842 }843 836 844 837 // Start output buffering … … 849 842 // Send response 850 843 wp_send_json_success(array('html' => $html)); 844 } 845 846 /** 847 * Validate and sanitize template name to prevent directory traversal attacks 848 * 849 * @param string $template The template name to validate 850 * @param string $type Either 'invoice' or 'quote' 851 * @return string Validated template name or 'standard' as fallback 852 */ 853 private function validateTemplateName($template, $type = 'invoice') { 854 // Whitelist of allowed template names 855 $allowed_templates = array( 856 'invoice' => array('classic', 'corporate', 'creative', 'elegant', 'legacy', 'minimal', 'modern', 'professional', 'standard'), 857 'quote' => array('legacy', 'minimal', 'minimalist', 'modern', 'standard') 858 ); 859 860 // Strip any directory components using basename 861 $template = basename($template); 862 863 // Remove any file extension 864 $template = preg_replace('/\.(php|html|htm)$/i', '', $template); 865 866 // Remove any non-alphanumeric characters except hyphens and underscores 867 $template = preg_replace('/[^a-z0-9_-]/i', '', $template); 868 869 // Check if template is in whitelist 870 if (isset($allowed_templates[$type]) && in_array($template, $allowed_templates[$type], true)) { 871 return $template; 872 } 873 874 // Return default template if not in whitelist 875 return 'standard'; 876 } 877 878 /** 879 * Get secure template file path with directory traversal protection 880 * 881 * @param string $template The validated template name 882 * @param string $type Either 'invoice' or 'quote' 883 * @return string|false The secure template file path or false if invalid 884 */ 885 private function getSecureTemplatePath($template, $type = 'invoice') { 886 // Define template directories 887 $template_dirs = array( 888 'invoice' => EASY_INVOICE_PLUGIN_DIR . 'templates/invoice-templates/', 889 'quote' => EASY_INVOICE_PLUGIN_DIR . 'templates/quote-templates/' 890 ); 891 892 if (!isset($template_dirs[$type])) { 893 return false; 894 } 895 896 $template_dir = $template_dirs[$type]; 897 898 // Ensure template directory exists and is a directory 899 if (!is_dir($template_dir)) { 900 return false; 901 } 902 903 // Get the real path of the template directory (resolves any symlinks) 904 $real_template_dir = realpath($template_dir); 905 if ($real_template_dir === false) { 906 return false; 907 } 908 909 // Construct the template file path 910 $template_file = $real_template_dir . DIRECTORY_SEPARATOR . $template . '.php'; 911 912 // Get the real path of the template file (resolves any .. or . components) 913 $real_template_file = realpath($template_file); 914 915 // Verify that the resolved path is within the template directory 916 // This prevents directory traversal attacks 917 if ($real_template_file === false || strpos($real_template_file, $real_template_dir) !== 0) { 918 // If template doesn't exist or is outside the directory, use default 919 $default_file = $real_template_dir . DIRECTORY_SEPARATOR . 'standard.php'; 920 $real_default_file = realpath($default_file); 921 922 if ($real_default_file !== false && strpos($real_default_file, $real_template_dir) === 0) { 923 return $real_default_file; 924 } 925 926 return false; 927 } 928 929 // Verify the file exists and is readable 930 if (!is_file($real_template_file) || !is_readable($real_template_file)) { 931 // Fallback to standard template 932 $default_file = $real_template_dir . DIRECTORY_SEPARATOR . 'standard.php'; 933 $real_default_file = realpath($default_file); 934 935 if ($real_default_file !== false && strpos($real_default_file, $real_template_dir) === 0 && is_file($real_default_file) && is_readable($real_default_file)) { 936 return $real_default_file; 937 } 938 939 return false; 940 } 941 942 return $real_template_file; 851 943 } 852 944 -
easy-invoice/tags/2.1.5/includes/Controllers/QuoteController.php
r3393362 r3399346 567 567 } 568 568 569 // Validate template name securely 570 $template_id = $this->validateTemplateName($template_id, 'quote'); 571 572 // Get secure template file path 573 $template_file = $this->getSecureTemplatePath($template_id, 'quote'); 574 575 if (!$template_file) { 576 wp_send_json_error(['message' => __('Template not found.', 'easy-invoice')]); 577 } 578 569 579 // Load quote if provided 570 580 $quote = null; … … 573 583 } 574 584 575 // Check if template file exists576 $template_file = EASY_INVOICE_PLUGIN_DIR . 'templates/quote-templates/' . $template_id . '.php';577 578 if (!file_exists($template_file)) {579 wp_send_json_error(['message' => __('Template not found.', 'easy-invoice')]);580 }581 582 585 // Start output buffering to capture template HTML 583 586 ob_start(); … … 590 593 591 594 wp_send_json_success(['html' => $html]); 595 } 596 597 /** 598 * Validate and sanitize template name to prevent directory traversal attacks 599 * 600 * @param string $template The template name to validate 601 * @param string $type Either 'invoice' or 'quote' 602 * @return string Validated template name or 'standard' as fallback 603 */ 604 private function validateTemplateName($template, $type = 'quote') { 605 // Whitelist of allowed template names 606 $allowed_templates = array( 607 'invoice' => array('classic', 'corporate', 'creative', 'elegant', 'legacy', 'minimal', 'modern', 'professional', 'standard'), 608 'quote' => array('legacy', 'minimal', 'minimalist', 'modern', 'standard') 609 ); 610 611 // Strip any directory components using basename 612 $template = basename($template); 613 614 // Remove any file extension 615 $template = preg_replace('/\.(php|html|htm)$/i', '', $template); 616 617 // Remove any non-alphanumeric characters except hyphens and underscores 618 $template = preg_replace('/[^a-z0-9_-]/i', '', $template); 619 620 // Check if template is in whitelist 621 if (isset($allowed_templates[$type]) && in_array($template, $allowed_templates[$type], true)) { 622 return $template; 623 } 624 625 // Return default template if not in whitelist 626 return 'standard'; 627 } 628 629 /** 630 * Get secure template file path with directory traversal protection 631 * 632 * @param string $template The validated template name 633 * @param string $type Either 'invoice' or 'quote' 634 * @return string|false The secure template file path or false if invalid 635 */ 636 private function getSecureTemplatePath($template, $type = 'quote') { 637 // Define template directories 638 $template_dirs = array( 639 'invoice' => EASY_INVOICE_PLUGIN_DIR . 'templates/invoice-templates/', 640 'quote' => EASY_INVOICE_PLUGIN_DIR . 'templates/quote-templates/' 641 ); 642 643 if (!isset($template_dirs[$type])) { 644 return false; 645 } 646 647 $template_dir = $template_dirs[$type]; 648 649 // Ensure template directory exists and is a directory 650 if (!is_dir($template_dir)) { 651 return false; 652 } 653 654 // Get the real path of the template directory (resolves any symlinks) 655 $real_template_dir = realpath($template_dir); 656 if ($real_template_dir === false) { 657 return false; 658 } 659 660 // Construct the template file path 661 $template_file = $real_template_dir . DIRECTORY_SEPARATOR . $template . '.php'; 662 663 // Get the real path of the template file (resolves any .. or . components) 664 $real_template_file = realpath($template_file); 665 666 // Verify that the resolved path is within the template directory 667 // This prevents directory traversal attacks 668 if ($real_template_file === false || strpos($real_template_file, $real_template_dir) !== 0) { 669 // If template doesn't exist or is outside the directory, use default 670 $default_file = $real_template_dir . DIRECTORY_SEPARATOR . 'standard.php'; 671 $real_default_file = realpath($default_file); 672 673 if ($real_default_file !== false && strpos($real_default_file, $real_template_dir) === 0) { 674 return $real_default_file; 675 } 676 677 return false; 678 } 679 680 // Verify the file exists and is readable 681 if (!is_file($real_template_file) || !is_readable($real_template_file)) { 682 // Fallback to standard template 683 $default_file = $real_template_dir . DIRECTORY_SEPARATOR . 'standard.php'; 684 $real_default_file = realpath($default_file); 685 686 if ($real_default_file !== false && strpos($real_default_file, $real_template_dir) === 0 && is_file($real_default_file) && is_readable($real_default_file)) { 687 return $real_default_file; 688 } 689 690 return false; 691 } 692 693 return $real_template_file; 592 694 } 593 695 -
easy-invoice/tags/2.1.5/readme.txt
r3393362 r3399346 5 5 Tested up to: 6.8 6 6 Requires PHP: 7.4 7 Stable tag: 2.1. 47 Stable tag: 2.1.5 8 8 License: GPLv2 or later 9 9 License URI: https://www.gnu.org/licenses/gpl-2.0.html … … 138 138 == Changelog == 139 139 140 = 2.1.5 - 2025-11-20 = 141 * Fixed - Template loading issue fixed 142 140 143 = 2.1.4 - 2025-11-11 = 141 144 * Fixed - Email issue fixed -
easy-invoice/trunk/easy-invoice.php
r3393362 r3399346 4 4 * Plugin URI: https://matrixaddons.com/plugins/easy-invoice 5 5 * Description: A beautiful, full-featured invoicing solution for WordPress. Create professional invoices, quotes, and manage payments with ease. 6 * Version: 2.1. 46 * Version: 2.1.5 7 7 * Author: MatrixAddons 8 8 * Author URI: https://matrixaddons.com … … 25 25 26 26 // Define plugin constants. 27 define( 'EASY_INVOICE_VERSION', '2.1. 4' );27 define( 'EASY_INVOICE_VERSION', '2.1.5' ); 28 28 define( 'EASY_INVOICE_PLUGIN_FILE', __FILE__ ); 29 29 define( 'EASY_INVOICE_PLUGIN_DIR', plugin_dir_path( __FILE__ ) ); -
easy-invoice/trunk/includes/Controllers/InvoiceController.php
r3377511 r3399346 795 795 } 796 796 797 // Get template name 797 // Get template name and validate it securely 798 798 $template = isset($_POST['template']) ? sanitize_text_field($_POST['template']) : 'standard'; 799 $template = $this->validateTemplateName($template, 'invoice'); 799 800 $invoice_id = isset($_POST['invoice_id']) ? intval($_POST['invoice_id']) : 0; 801 802 // Get secure template file path 803 $template_file = $this->getSecureTemplatePath($template, 'invoice'); 804 805 if (!$template_file) { 806 wp_send_json_error(array('message' => __('Invalid template', 'easy-invoice'))); 807 } 800 808 801 809 // For new invoices (no ID), just return the template without invoice data 802 810 if ($invoice_id === 0) { 803 // Get template file path804 $template_file = EASY_INVOICE_PLUGIN_DIR . 'templates/invoice-templates/' . $template . '.php';805 806 if (!file_exists($template_file)) {807 $template_file = EASY_INVOICE_PLUGIN_DIR . 'templates/invoice-templates/standard.php';808 }809 810 811 // Start output buffering 811 812 ob_start(); … … 815 816 $formatter = null; 816 817 817 818 818 include_once $template_file; 819 819 $html = ob_get_clean(); … … 834 834 // Initialize formatter for currency formatting 835 835 $formatter = new \EasyInvoice\Helpers\InvoiceFormatter($invoice); 836 837 // Get template file path838 $template_file = EASY_INVOICE_PLUGIN_DIR . 'templates/invoice-templates/' . $template . '.php';839 840 if (!file_exists($template_file)) {841 $template_file = EASY_INVOICE_PLUGIN_DIR . 'templates/invoice-templates/standard.php';842 }843 836 844 837 // Start output buffering … … 849 842 // Send response 850 843 wp_send_json_success(array('html' => $html)); 844 } 845 846 /** 847 * Validate and sanitize template name to prevent directory traversal attacks 848 * 849 * @param string $template The template name to validate 850 * @param string $type Either 'invoice' or 'quote' 851 * @return string Validated template name or 'standard' as fallback 852 */ 853 private function validateTemplateName($template, $type = 'invoice') { 854 // Whitelist of allowed template names 855 $allowed_templates = array( 856 'invoice' => array('classic', 'corporate', 'creative', 'elegant', 'legacy', 'minimal', 'modern', 'professional', 'standard'), 857 'quote' => array('legacy', 'minimal', 'minimalist', 'modern', 'standard') 858 ); 859 860 // Strip any directory components using basename 861 $template = basename($template); 862 863 // Remove any file extension 864 $template = preg_replace('/\.(php|html|htm)$/i', '', $template); 865 866 // Remove any non-alphanumeric characters except hyphens and underscores 867 $template = preg_replace('/[^a-z0-9_-]/i', '', $template); 868 869 // Check if template is in whitelist 870 if (isset($allowed_templates[$type]) && in_array($template, $allowed_templates[$type], true)) { 871 return $template; 872 } 873 874 // Return default template if not in whitelist 875 return 'standard'; 876 } 877 878 /** 879 * Get secure template file path with directory traversal protection 880 * 881 * @param string $template The validated template name 882 * @param string $type Either 'invoice' or 'quote' 883 * @return string|false The secure template file path or false if invalid 884 */ 885 private function getSecureTemplatePath($template, $type = 'invoice') { 886 // Define template directories 887 $template_dirs = array( 888 'invoice' => EASY_INVOICE_PLUGIN_DIR . 'templates/invoice-templates/', 889 'quote' => EASY_INVOICE_PLUGIN_DIR . 'templates/quote-templates/' 890 ); 891 892 if (!isset($template_dirs[$type])) { 893 return false; 894 } 895 896 $template_dir = $template_dirs[$type]; 897 898 // Ensure template directory exists and is a directory 899 if (!is_dir($template_dir)) { 900 return false; 901 } 902 903 // Get the real path of the template directory (resolves any symlinks) 904 $real_template_dir = realpath($template_dir); 905 if ($real_template_dir === false) { 906 return false; 907 } 908 909 // Construct the template file path 910 $template_file = $real_template_dir . DIRECTORY_SEPARATOR . $template . '.php'; 911 912 // Get the real path of the template file (resolves any .. or . components) 913 $real_template_file = realpath($template_file); 914 915 // Verify that the resolved path is within the template directory 916 // This prevents directory traversal attacks 917 if ($real_template_file === false || strpos($real_template_file, $real_template_dir) !== 0) { 918 // If template doesn't exist or is outside the directory, use default 919 $default_file = $real_template_dir . DIRECTORY_SEPARATOR . 'standard.php'; 920 $real_default_file = realpath($default_file); 921 922 if ($real_default_file !== false && strpos($real_default_file, $real_template_dir) === 0) { 923 return $real_default_file; 924 } 925 926 return false; 927 } 928 929 // Verify the file exists and is readable 930 if (!is_file($real_template_file) || !is_readable($real_template_file)) { 931 // Fallback to standard template 932 $default_file = $real_template_dir . DIRECTORY_SEPARATOR . 'standard.php'; 933 $real_default_file = realpath($default_file); 934 935 if ($real_default_file !== false && strpos($real_default_file, $real_template_dir) === 0 && is_file($real_default_file) && is_readable($real_default_file)) { 936 return $real_default_file; 937 } 938 939 return false; 940 } 941 942 return $real_template_file; 851 943 } 852 944 -
easy-invoice/trunk/includes/Controllers/QuoteController.php
r3393362 r3399346 567 567 } 568 568 569 // Validate template name securely 570 $template_id = $this->validateTemplateName($template_id, 'quote'); 571 572 // Get secure template file path 573 $template_file = $this->getSecureTemplatePath($template_id, 'quote'); 574 575 if (!$template_file) { 576 wp_send_json_error(['message' => __('Template not found.', 'easy-invoice')]); 577 } 578 569 579 // Load quote if provided 570 580 $quote = null; … … 573 583 } 574 584 575 // Check if template file exists576 $template_file = EASY_INVOICE_PLUGIN_DIR . 'templates/quote-templates/' . $template_id . '.php';577 578 if (!file_exists($template_file)) {579 wp_send_json_error(['message' => __('Template not found.', 'easy-invoice')]);580 }581 582 585 // Start output buffering to capture template HTML 583 586 ob_start(); … … 590 593 591 594 wp_send_json_success(['html' => $html]); 595 } 596 597 /** 598 * Validate and sanitize template name to prevent directory traversal attacks 599 * 600 * @param string $template The template name to validate 601 * @param string $type Either 'invoice' or 'quote' 602 * @return string Validated template name or 'standard' as fallback 603 */ 604 private function validateTemplateName($template, $type = 'quote') { 605 // Whitelist of allowed template names 606 $allowed_templates = array( 607 'invoice' => array('classic', 'corporate', 'creative', 'elegant', 'legacy', 'minimal', 'modern', 'professional', 'standard'), 608 'quote' => array('legacy', 'minimal', 'minimalist', 'modern', 'standard') 609 ); 610 611 // Strip any directory components using basename 612 $template = basename($template); 613 614 // Remove any file extension 615 $template = preg_replace('/\.(php|html|htm)$/i', '', $template); 616 617 // Remove any non-alphanumeric characters except hyphens and underscores 618 $template = preg_replace('/[^a-z0-9_-]/i', '', $template); 619 620 // Check if template is in whitelist 621 if (isset($allowed_templates[$type]) && in_array($template, $allowed_templates[$type], true)) { 622 return $template; 623 } 624 625 // Return default template if not in whitelist 626 return 'standard'; 627 } 628 629 /** 630 * Get secure template file path with directory traversal protection 631 * 632 * @param string $template The validated template name 633 * @param string $type Either 'invoice' or 'quote' 634 * @return string|false The secure template file path or false if invalid 635 */ 636 private function getSecureTemplatePath($template, $type = 'quote') { 637 // Define template directories 638 $template_dirs = array( 639 'invoice' => EASY_INVOICE_PLUGIN_DIR . 'templates/invoice-templates/', 640 'quote' => EASY_INVOICE_PLUGIN_DIR . 'templates/quote-templates/' 641 ); 642 643 if (!isset($template_dirs[$type])) { 644 return false; 645 } 646 647 $template_dir = $template_dirs[$type]; 648 649 // Ensure template directory exists and is a directory 650 if (!is_dir($template_dir)) { 651 return false; 652 } 653 654 // Get the real path of the template directory (resolves any symlinks) 655 $real_template_dir = realpath($template_dir); 656 if ($real_template_dir === false) { 657 return false; 658 } 659 660 // Construct the template file path 661 $template_file = $real_template_dir . DIRECTORY_SEPARATOR . $template . '.php'; 662 663 // Get the real path of the template file (resolves any .. or . components) 664 $real_template_file = realpath($template_file); 665 666 // Verify that the resolved path is within the template directory 667 // This prevents directory traversal attacks 668 if ($real_template_file === false || strpos($real_template_file, $real_template_dir) !== 0) { 669 // If template doesn't exist or is outside the directory, use default 670 $default_file = $real_template_dir . DIRECTORY_SEPARATOR . 'standard.php'; 671 $real_default_file = realpath($default_file); 672 673 if ($real_default_file !== false && strpos($real_default_file, $real_template_dir) === 0) { 674 return $real_default_file; 675 } 676 677 return false; 678 } 679 680 // Verify the file exists and is readable 681 if (!is_file($real_template_file) || !is_readable($real_template_file)) { 682 // Fallback to standard template 683 $default_file = $real_template_dir . DIRECTORY_SEPARATOR . 'standard.php'; 684 $real_default_file = realpath($default_file); 685 686 if ($real_default_file !== false && strpos($real_default_file, $real_template_dir) === 0 && is_file($real_default_file) && is_readable($real_default_file)) { 687 return $real_default_file; 688 } 689 690 return false; 691 } 692 693 return $real_template_file; 592 694 } 593 695 -
easy-invoice/trunk/readme.txt
r3393362 r3399346 5 5 Tested up to: 6.8 6 6 Requires PHP: 7.4 7 Stable tag: 2.1. 47 Stable tag: 2.1.5 8 8 License: GPLv2 or later 9 9 License URI: https://www.gnu.org/licenses/gpl-2.0.html … … 138 138 == Changelog == 139 139 140 = 2.1.5 - 2025-11-20 = 141 * Fixed - Template loading issue fixed 142 140 143 = 2.1.4 - 2025-11-11 = 141 144 * Fixed - Email issue fixed
Note: See TracChangeset
for help on using the changeset viewer.