PluginProbe ʕ •ᴥ•ʔ
JetFormBuilder — Dynamic Blocks Form Builder / 3.2.1
JetFormBuilder — Dynamic Blocks Form Builder v3.2.1
3.6.3.1 3.6.3 3.6.2.2 3.6.2.1 3.6.2 3.6.1.1 3.6.1 3.6.0.1 trunk 1.0.0 1.0.1 1.0.2 1.0.3 1.1.0 1.1.1 1.1.2 1.1.3 1.1.4 1.1.5 1.1.6 1.1.7 1.2.0 1.2.1 1.2.2 1.2.3 1.2.4 1.2.5 1.2.6 1.2.7 1.3.0 1.3.1 1.3.2 1.3.3 1.4.0 1.4.1 1.4.2 1.4.3 1.5.0 1.5.1 1.5.2 1.5.3 1.5.4 1.5.5 2.0.0 2.0.1 2.0.2 2.0.3 2.0.4 2.0.5 2.0.6 2.1.0 2.1.1 2.1.10 2.1.11 2.1.2 2.1.3 2.1.4 2.1.5 2.1.6 2.1.7 2.1.8 2.1.9 3.0.0 3.0.0.1 3.0.0.2 3.0.0.3 3.0.1 3.0.1.1 3.0.2 3.0.3 3.0.4 3.0.5 3.0.6 3.0.7 3.0.8 3.0.9 3.1.0 3.1.0.1 3.1.1 3.1.2 3.1.3 3.1.4 3.1.5 3.1.6 3.1.7 3.1.8 3.1.9 3.2.0 3.2.1 3.2.2 3.2.3 3.3.0 3.3.1 3.3.2 3.3.3 3.3.3.1 3.3.4 3.3.4.1 3.3.4.2 3.4.0 3.4.1 3.4.2 3.4.3 3.4.4 3.4.5 3.4.5.1 3.4.5.2 3.4.6 3.4.7 3.4.7.1 3.5.0 3.5.1 3.5.1.1 3.5.1.2 3.5.2 3.5.2.1 3.5.3 3.5.4 3.5.5 3.5.6 3.5.6.1 3.5.6.2 3.5.6.3 3.6.0
jetformbuilder / modules / webhook / module.php
jetformbuilder / modules / webhook Last commit date
db 2 years ago module.php 2 years ago
module.php
229 lines
1 <?php
2
3
4 namespace JFB_Modules\Webhook;
5
6 use Jet_Form_Builder\Admin\Single_Pages\Meta_Containers\Base_Meta_Container;
7 use Jet_Form_Builder\Db_Queries\Query_Conditions_Builder;
8 use Jet_Form_Builder\Exceptions\Query_Builder_Exception;
9 use JFB_Components\Module\Base_Module_After_Install_It;
10 use JFB_Components\Module\Base_Module_It;
11 use JFB_Modules\Logger\Empty_Logger;
12 use JFB_Modules\Logger\Interfaces\Logger_It;
13 use JFB_Modules\Webhook\Db\Models\Tokens_Model;
14 use JFB_Modules\Webhook\Db\Views\Tokens_View;
15 use JFB_Modules\Security;
16
17 // If this file is called directly, abort.
18 if ( ! defined( 'WPINC' ) ) {
19 die;
20 }
21
22 class Module implements Base_Module_It, Base_Module_After_Install_It {
23
24 const GET_TOKEN_ID = 'jfb_token_id';
25 const GET_TOKEN = 'jfb_token';
26
27 /**
28 * @var Logger_It
29 */
30 private $logger;
31
32 private $verified = false;
33 private $token_row = array();
34
35 /**
36 * Has value while webhook is processed
37 *
38 * @var string
39 */
40 private $token = '';
41
42 public function rep_item_id() {
43 return 'webhook';
44 }
45
46 public function condition(): bool {
47 return true;
48 }
49
50 public function init_hooks() {
51 if ( $this->is_webhook_request() ) {
52 add_action( 'parse_request', array( $this, 'try_to_catch' ) );
53 }
54 }
55
56 public function remove_hooks() {
57 if ( $this->is_webhook_request() ) {
58 remove_action( 'parse_request', array( $this, 'try_to_catch' ) );
59 }
60 }
61
62 public function on_install() {
63 $this->set_logger( new Empty_Logger() );
64 }
65
66 public function on_uninstall() {
67 }
68
69 public function try_to_catch() {
70 global $wpdb;
71
72 $view = new Tokens_View();
73
74 // phpcs:disable WordPress.Security.NonceVerification.Recommended
75 $id = absint( $_GET[ self::GET_TOKEN_ID ] ?? '' );
76 $this->token = sanitize_key( $_GET[ self::GET_TOKEN ] ?? '' );
77 // phpcs:enable WordPress.Security.NonceVerification.Recommended
78
79 $expire_conditions = new Query_Conditions_Builder();
80 $expire_conditions->set_relation_or();
81 $expire_conditions->set_condition(
82 array(
83 'type' => Query_Conditions_Builder::TYPE_MORE_STATIC,
84 'values' => array( 'expire_at', current_time( 'mysql', true ) ),
85 )
86 );
87 $expire_conditions->set_condition(
88 array(
89 'type' => Query_Conditions_Builder::TYPE_IS_NULL,
90 'values' => array( 'expire_at' ),
91 )
92 );
93
94 $conditions = array(
95 array(
96 'type' => Query_Conditions_Builder::TYPE_EQUAL,
97 'values' => array( 'id', $id ),
98 ),
99 $expire_conditions,
100 );
101
102 try {
103 $this->token_row = $view::findOne( $conditions )->query()->query_one();
104 } catch ( Query_Builder_Exception $exception ) {
105 $this->logger->log(
106 $exception->getMessage(),
107 $conditions
108 );
109
110 return;
111 }
112
113 $table = Tokens_Model::table();
114 $action = $this->token_row['action'];
115
116 if ( ! Security\Module::get_hasher()->CheckPassword(
117 $this->token,
118 $this->token_row['hash']
119 ) ) {
120 $this->logger->log(
121 sprintf(
122 /* translators: %d - primary id of token row */
123 __( 'Invalid token for %d (primary ID) row', 'jet-form-builder' ),
124 $id
125 )
126 );
127 do_action( "jet-form-builder/webhook/{$action}", $this );
128
129 return;
130 }
131
132 // custom query to prevent race-condition
133 // phpcs:disabled WordPress.DB
134 $wpdb->query(
135 $wpdb->prepare(
136 "UPDATE {$table} SET
137 {$table}.exec_count = {$table}.exec_count + 1,
138 {$table}.updated_at = %s
139 WHERE 1=1
140 AND {$table}.exec_count < {$table}.limit_exec
141 AND {$table}.id = %d
142 ;
143 ",
144 current_time( 'mysql', 1 ),
145 $id
146 )
147 );
148 // phpcs:enabled WordPress.DB
149
150 if ( ! $wpdb->rows_affected ) {
151 $this->logger->log(
152 sprintf(
153 /* translators: %d - primary id of token row */
154 __( 'Failed to increment `exec_count` column in %d (primary ID) row', 'jet-form-builder' ),
155 $id
156 )
157 );
158 do_action( "jet-form-builder/webhook/{$action}", $this );
159
160 return;
161 }
162
163 $this->logger->log(
164 sprintf(
165 /* translators: %d - primary id of token row */
166 __( 'Successfully verified webhook (primary ID -> %d)', 'jet-form-builder' ),
167 $id
168 ),
169 sprintf( 'hook: jet-form-builder/webhook/%s', $action )
170 );
171
172 $this->verified = true;
173
174 do_action( "jet-form-builder/webhook/{$action}", $this );
175 }
176
177 public function redirect( string $url ) {
178 // make sure we don't have such parameters
179 $url = remove_query_arg( self::GET_TOKEN_ID, $url );
180 $url = remove_query_arg( self::GET_TOKEN, $url );
181
182 // phpcs:ignore WordPress.Security.SafeRedirect.wp_redirect_wp_redirect
183 wp_redirect( $url );
184 die;
185 }
186
187 public function set_logger( Logger_It $logger ) {
188 $this->logger = $logger;
189 }
190
191 /**
192 * @return Logger_It
193 */
194 public function get_logger(): Logger_It {
195 return $this->logger;
196 }
197
198 /**
199 * @return bool
200 */
201 public function is_webhook_request(): bool {
202 // phpcs:disable WordPress.Security.NonceVerification.Recommended
203 return (
204 array_key_exists( self::GET_TOKEN_ID, $_GET ) &&
205 array_key_exists( self::GET_TOKEN, $_GET ) &&
206 is_numeric( $_GET[ self::GET_TOKEN_ID ] )
207 );
208 // phpcs:enable WordPress.Security.NonceVerification.Recommended
209 }
210
211 /**
212 * @return bool
213 */
214 public function is_verified(): bool {
215 return $this->verified;
216 }
217
218 public function get_token_id(): int {
219 return absint( $this->token_row['id'] ?? '' );
220 }
221
222 /**
223 * @return string
224 */
225 public function get_token(): string {
226 return $this->token;
227 }
228 }
229