X7ROOT File Manager
Current Path:
/home/gfecatvj/4abetter.us/wp-content/plugins/zapier
home
/
gfecatvj
/
4abetter.us
/
wp-content
/
plugins
/
zapier
/
📁
..
📄
LICENSE.txt
(1.04 KB)
📄
readme.txt
(5.06 KB)
📁
trunk
📁
vendor
📄
zapier.php
(17.45 KB)
Editing: zapier.php
<?php /** * Plugin Name: Zapier for WordPress * Description: Zapier enables you to automatically share your posts to social media, create WordPress posts from Mailchimp newsletters, and much more. Visit https://zapier.com/apps/wordpress/integrations for more details. * Version: 1.5.3 * Author: Zapier * Author URI: https://zapier.com * License: Expat (MIT License) * License URI: https://spdx.org/licenses/MIT.html */ require_once dirname(__FILE__) . '/vendor/autoload.php'; use \Firebase\JWT\JWT; use \Firebase\JWT\Key; class Zapier_Auth_Loader { protected $actions; protected $filters; public function __construct() { $this->actions = array(); $this->filters = array(); } public function add_plugin_action($hook, $component, $callback, $priority = 10, $accepted_args = 1) { $this->actions = $this->add($this->actions, $hook, $component, $callback, $priority, $accepted_args); } public function add_plugin_filter($hook, $component, $callback, $priority = 10, $accepted_args = 1) { $this->filters = $this->add($this->filters, $hook, $component, $callback, $priority, $accepted_args); } private function add($hooks, $hook, $component, $callback, $priority, $accepted_args) { $hooks[] = array( 'hook' => $hook, 'component' => $component, 'callback' => $callback, 'priority' => $priority, 'accepted_args' => $accepted_args, ); return $hooks; } public function run() { foreach ($this->filters as $hook) { add_filter($hook['hook'], array($hook['component'], $hook['callback']), $hook['priority'], $hook['accepted_args']); } foreach ($this->actions as $hook) { add_action($hook['hook'], array($hook['component'], $hook['callback']), $hook['priority'], $hook['accepted_args']); } } } class Zapier_Auth { private $error = null; protected $namespace; protected $loader; public function __construct() { $this->namespace = 'zapier/v1'; $this->loader = new Zapier_Auth_Loader(); $this->define_public_hooks(); } private function define_public_hooks() { $this->loader->add_plugin_action('rest_api_init', $this, 'add_api_routes'); $this->loader->add_plugin_filter('rest_pre_dispatch', $this, 'rest_pre_dispatch'); $this->loader->add_plugin_filter('determine_current_user', $this, 'determine_current_user'); // Webhooks $this->loader->add_plugin_action('wp_update_user', $this, 'updated_user'); $this->loader->add_plugin_action('post_updated', $this, 'updated_post', 10, 3); } public function run() { $this->loader->run(); } /** * Verify user has proper authorization for webhook management * * @param WP_REST_Request $request * @return bool|WP_Error */ private function verify_webhook_authorization($request) { // Check if user is logged in if (!is_user_logged_in()) { return new WP_Error( 'not_logged_in', 'You are not logged in', array('status' => 401) ); } // Check if user has proper capabilities - only administrators should manage webhooks if (!current_user_can('manage_options')) { return new WP_Error( 'insufficient_permissions', 'You do not have sufficient permissions to manage webhooks', array('status' => 403) ); } // CSRF protection: Different approaches for different auth methods $is_jwt_auth = isset($_SERVER['HTTP_X_ZAPIER_AUTH']) && isset($_SERVER['HTTP_USER_AGENT']) && $_SERVER['HTTP_USER_AGENT'] === 'Zapier'; if ($is_jwt_auth) { // For JWT: Verify the token includes proper origin validation // JWT tokens should only be used by Zapier's servers, not browsers // The User-Agent check provides additional CSRF protection if (!isset($_SERVER['HTTP_USER_AGENT']) || $_SERVER['HTTP_USER_AGENT'] !== 'Zapier') { return new WP_Error( 'invalid_user_agent', 'Invalid request source', array('status' => 403) ); } } else { // For browser-based requests: Use WordPress nonce $nonce = $request->get_header('X-WP-Nonce'); if (!$nonce || !wp_verify_nonce($nonce, 'wp_rest')) { return new WP_Error( 'invalid_nonce', 'Invalid security token', array('status' => 403) ); } } return true; } /** * Verify user authorization for read-only operations * * @param WP_REST_Request $request * @return bool|WP_Error */ private function verify_read_authorization($request) { // Check if user is logged in if (!is_user_logged_in()) { return new WP_Error( 'not_logged_in', 'You are not logged in', array('status' => 401) ); } // For read operations, we can allow users with edit_posts capability if (!current_user_can('edit_posts')) { return new WP_Error( 'insufficient_permissions', 'You do not have sufficient permissions to access this resource', array('status' => 403) ); } return true; } public function add_api_routes() { register_rest_route($this->namespace, '/token', array( 'methods' => "POST", 'callback' => array($this, 'generate_token'), 'permission_callback' => '__return_true' )); register_rest_route($this->namespace, '/(?P<type>[a-zA-Z0-9_-]+)/supports', array( 'methods' => "GET", 'callback' => array($this, 'get_custom_type_supports'), 'permission_callback' => array($this, 'check_read_permission') )); register_rest_route($this->namespace, '/roles', array( 'methods' => "GET", 'callback' => array($this, 'get_roles'), 'permission_callback' => array($this, 'check_read_permission') )); register_rest_route($this->namespace, '/webhook', array( 'methods' => "POST", 'callback' => array($this, 'add_webhook'), 'permission_callback' => array($this, 'check_webhook_permission') )); register_rest_route($this->namespace, '/webhook', array( 'methods' => "DELETE", 'callback' => array($this, 'remove_webhook'), 'permission_callback' => array($this, 'check_webhook_permission') )); } /** * Permission callback for webhook operations */ public function check_webhook_permission($request) { $auth_result = $this->verify_webhook_authorization($request); return !is_wp_error($auth_result); } /** * Permission callback for read operations */ public function check_read_permission($request) { // Check if user is logged in (Application Password authentication should work here) if (!is_user_logged_in()) { return false; } // For read operations, allow users with edit_posts capability (editors and admins) if (!current_user_can('edit_posts')) { return false; } return true; } public function generate_token($request) { $secret_key = get_option('zapier_secret'); $username = $request->get_param('username'); $password = $request->get_param('password'); $user = wp_authenticate($username, $password); if (is_wp_error($user)) { $error_code = $user->get_error_code(); return new WP_Error( $error_code, $user->get_error_message($error_code), array( 'status' => 401, ) ); } $issuedAt = time(); $token = array( 'iss' => get_bloginfo('url'), 'iat' => $issuedAt, 'nbf' => $issuedAt, 'exp' => $issuedAt + (60 * 20), 'data' => array( 'user_id' => $user->data->ID, ), ); return array( 'token' => JWT::encode($token, $secret_key, 'HS256'), ); } public function get_custom_type_supports($request) { // Authorization is handled by permission_callback $type = $request['type']; $types = get_post_types(array()); if(!in_array($type, $types)) { return new WP_Error( 'invalid_post_type', 'Invalid post type', array( 'status' => 404, ) ); } return array('supports' => get_all_post_type_supports($type)); } public function get_roles($request = null) { // Authorization is handled by permission_callback $roles = array(); foreach (wp_roles()->roles as $key => $role) { $roles[] = (array('id' => $key, 'name' => $role['name'])); } return array('roles' => $roles); } public function add_webhook($request) { // Authorization is handled by permission_callback $auth_result = $this->verify_webhook_authorization($request); if (is_wp_error($auth_result)) { return $auth_result; } $ALLOWED_ACTIONS = array('wp_update_user','post_updated'); $action = $request->get_param("action"); $endpoint_url = $request->get_param("endpoint_url"); if(!in_array($action, $ALLOWED_ACTIONS)) { return new WP_Error( 'invalid_action', 'Invalid action', array( 'status' => 400, ) ); } if(empty($endpoint_url)) { return new WP_Error( 'invalid_endpoint_url', 'Invalid endpoint url', array( 'status' => 400, ) ); } // Enhanced URL validation if (!$this->is_safe_url($endpoint_url)) { return new WP_Error( 'unsafe_endpoint_url', 'The provided endpoint URL is not allowed for security reasons', array( 'status' => 400, ) ); } $option_key = "zapier_hooks_$action"; $hooks = get_option($option_key, []); if(!in_array($endpoint_url, $hooks)) { $hooks[] = $endpoint_url; update_option($option_key, $hooks); } return array('success' => true); } public function remove_webhook($request) { // Authorization is handled by permission_callback $auth_result = $this->verify_webhook_authorization($request); if (is_wp_error($auth_result)) { return $auth_result; } $action = $request->get_param("action"); $endpoint_url = $request->get_param("endpoint_url"); $option_key = "zapier_hooks_$action"; $hooks = get_option($option_key, []); if(($key = array_search($endpoint_url, $hooks)) !== false) { unset($hooks[$key]); update_option($option_key, $hooks); } return array('success' => true); } public function updated_user($user_id) { $option_key = "zapier_hooks_wp_update_user"; $hooks = get_option($option_key, []); foreach ($hooks as $hook) { // Validate the URL if (!$this->is_safe_url($hook)) { continue; // Skip unsafe URLs } // Use wp_safe_remote_post to ensure secure requests $response = wp_safe_remote_post($hook, [ 'body' => json_encode(['user_id' => $user_id]), 'headers' => ['Content-Type' => 'application/json'], ]); } } public function updated_post($post_id, $post_after, $post_before) { $option_key = "zapier_hooks_post_updated"; $rest_base = get_post_type_object($post_after->post_type)->rest_base; $changed_properties = $this->compareObjects($post_after, $post_before); $hooks = get_option($option_key, []); foreach($hooks as $hook) { $response = wp_remote_post($hook, array( 'body' => json_encode(array( 'post_id' => $post_id, 'rest_base' => $rest_base, 'post_after_status' => $post_after->post_status, 'post_before_status' => $post_before->post_status, 'post_changed_properties' => $changed_properties )), 'headers' => array('Content-Type' => 'application/json'), )); } } public function get_user_from_token() { try { JWT::$leeway = 240; // $leeway in seconds $token = JWT::decode( $_SERVER['HTTP_X_ZAPIER_AUTH'], new Key(get_option('zapier_secret'), 'HS256') ); if ($token->iss != get_bloginfo('url')) { $this->error = new WP_Error( 'bad_issuer', 'The issuer does not match with this server', array( 'status' => 401, ) ); } elseif (!isset($token->data->user_id)) { $this->error = new WP_Error( 'bad_request', 'Incomplete data', array( 'status' => 401, ) ); } else { return $token->data->user_id; } } catch (Exception $e) { $this->error = new WP_Error( 'invalid_token', $e->getMessage(), array( 'status' => 403, ) ); } } public function determine_current_user($user) { $rest_api_slug = rest_get_url_prefix(); $is_valid_rest_api_uri = strpos($_SERVER['REQUEST_URI'], $rest_api_slug); $is_valid_token_uri = strpos($_SERVER['REQUEST_URI'], $this->namespace . '/token'); $is_zapier_request = isset($_SERVER['HTTP_USER_AGENT']) && $_SERVER['HTTP_USER_AGENT'] === 'Zapier' && isset($_SERVER['HTTP_X_ZAPIER_AUTH']); if ($is_zapier_request && $is_valid_rest_api_uri && !$is_valid_token_uri) { $user_id = $this->get_user_from_token(); if ($user_id) { return $user_id; } } return $user; } public function rest_pre_dispatch($request) { if (is_wp_error($this->error)) { return $this->error; } return $request; } private function compareObjects($obj1, $obj2) { $reflect1 = new ReflectionClass($obj1); $reflect2 = new ReflectionClass($obj2); if ($reflect1->getName() !== $reflect2->getName()) { throw new Exception('Objects must be instances of the same class'); } $properties1 = $reflect1->getProperties(); $changed_properties = []; foreach ($properties1 as $property) { // Make property accessible if it's private or protected $property->setAccessible(true); $value1 = $property->getValue($obj1); $value2 = $property->getValue($obj2); if ($value1 !== $value2) { $changed_properties[] = str_replace('post_', '', $property->getName()); } } return $changed_properties; } // Helper function to ensure only safe URLs are used private function is_safe_url($url) { // Validate URL format if (!wp_http_validate_url($url)) { return false; } // Ensure the URL is not internal (localhost, private IPs) if ($this->is_internal_url($url)) { return false; } // Allow only sanctioned domains (modify this list as needed) $allowed_domains = ['zapier.com', 'hooks.zapier.com']; $parsed_url = parse_url($url); if (!isset($parsed_url['host'])) { return false; } foreach ($allowed_domains as $allowed_domain) { if (str_ends_with($parsed_url['host'], $allowed_domain)) { return true; } } return false; } // Helper function to block internal/private addresses private function is_internal_url($url) { $parsed = parse_url($url); if (!$parsed || empty($parsed['host'])) { return true; } $ip = gethostbyname($parsed['host']); return filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE) === false; } } register_activation_hook(__FILE__, 'zapier_add_secret_key'); register_deactivation_hook(__FILE__, 'zapier_delete_secret_key'); function zapier_add_secret_key() { // the resulting value for the zapier_secret is 256 in length add_option('zapier_secret', bin2hex(random_bytes(128))); } function zapier_delete_secret_key() { delete_option('zapier_secret'); } $plugin = new Zapier_Auth(); $plugin->run();
Upload File
Create Folder