PluginProbe
SureForms – Contact Form Builder, AI Forms, Payment Form, Survey & Quiz / 2.12.8
SureForms – Contact Form Builder, AI Forms, Payment Form, Survey & Quiz v2.12.8
2.12.8 2.12.7 2.12.6 2.12.5 2.12.4 2.12.3 2.12.2 2.12.1 2.12.0 2.11.1 2.11.0 2.10.1 2.10.0 2.9.1 2.9.0 2.8.2 2.8.1 2.7.0 2.7.1 2.8.0 trunk 0.0.10 0.0.11 0.0.12 0.0.13 All 98 releases
sureforms / inc / ai-form-builder / ai-auth.php

ai-auth.php in SureForms – Contact Form Builder, AI Forms, Payment Form, Survey & Quiz 2.12.8, at inc/ai-form-builder/ai-auth.php

209 lines 6.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * SureForms - AI Auth.
4 *
5 * @package sureforms
6 * @since 0.0.8
7 */
8
9 namespace SRFM\Inc\AI_Form_Builder;
10
11 use SRFM\Inc\Helper;
12 use SRFM\Inc\Traits\Get_Instance;
13
14 // Exit if accessed directly.
15 if ( ! defined( 'ABSPATH' ) ) {
16 exit;
17 }
18
19 /**
20 * SureForms AI Form Builder Class.
21 */
22 class AI_Auth {
23 use Get_Instance;
24
25 /**
26 * The key for encryption and decryption.
27 *
28 * @since 0.0.8
29 * @var string
30 */
31 private $key = '';
32
33 /**
34 * Initiates the auth process.
35 *
36 * @param \WP_REST_Request $request The request object.
37 * @since 0.0.8
38 * @return void
39 */
40 public function get_auth_url( $request ) {
41
42 $nonce = Helper::get_string_value( $request->get_header( 'X-WP-Nonce' ) );
43
44 if ( ! wp_verify_nonce( sanitize_text_field( $nonce ), 'wp_rest' ) ) {
45 wp_send_json_error( __( 'Nonce verification failed.', 'sureforms' ) );
46 }
47
48 // Generate a random key of 16 characters.
49 $this->key = wp_generate_password( 16, false );
50 // Persist key for decryption in handle_access_key (10 min TTL).
51 set_transient( 'srfm_ai_auth_key_' . get_current_user_id(), $this->key, 10 * MINUTE_IN_SECONDS );
52
53 // Get the source parameter from the query.
54 $source = sanitize_text_field( Helper::get_string_value( $request->get_param( 'source' ) ?? '' ) );
55 switch ( $source ) {
56 case 'onboarding':
57 $redirect_back = site_url() . '/wp-admin/admin.php?page=sureforms_menu#/onboarding/email-delivery';
58 break;
59 default:
60 $redirect_back = site_url() . '/wp-admin/admin.php?page=add-new-form';
61 }
62
63 // Prepare the token data.
64 $token_data = [
65 'redirect-back' => $redirect_back,
66 'key' => $this->key,
67 'site-url' => site_url(),
68 'nonce' => wp_create_nonce( 'ai_auth_nonce' ),
69 ];
70
71 $encoded_token_data = wp_json_encode( $token_data );
72
73 if ( empty( $encoded_token_data ) ) {
74 wp_send_json_error( [ 'message' => __( 'Failed to encode the token data.', 'sureforms' ) ] );
75 }
76
77 // Send the token data to the frontend for redirection.
78 wp_send_json_success( SRFM_BILLING_PORTAL . 'auth/?token=' . base64_encode( $encoded_token_data ) ); // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_encode
79 }
80
81 /**
82 * Handles the access key.
83 *
84 * @param \WP_REST_Request $request The request object.
85 * @since 0.0.8
86 * @return void
87 */
88 public function handle_access_key( $request ) {
89
90 $nonce = Helper::get_string_value( $request->get_header( 'X-WP-Nonce' ) );
91
92 if ( ! wp_verify_nonce( sanitize_text_field( $nonce ), 'wp_rest' ) ) {
93 wp_send_json_error( __( 'Nonce verification failed.', 'sureforms' ) );
94 }
95
96 // get body data.
97 // get_body() is null for an empty request, and passing null to json_decode()
98 // is deprecated on PHP 8.1+ - the notice lands in the response body and makes
99 // the JSON unparseable wherever display_errors is on.
100 $body = json_decode( Helper::get_string_value( $request->get_body() ), true );
101
102 if ( empty( $body ) ) {
103 wp_send_json_error( [ 'message' => __( 'Error processing Access Key.', 'sureforms' ) ] );
104 }
105
106 // get access key.
107 $access_key = is_array( $body ) && ! empty(
108 $body['accessKey']
109 ) ? Helper::get_string_value( $body['accessKey'] ) : '';
110
111 $stored_key = Helper::get_string_value( get_transient( 'srfm_ai_auth_key_' . get_current_user_id() ) );
112
113 if ( empty( $stored_key ) ) {
114 wp_send_json_error( [ 'message' => __( 'Authentication session expired. Please try again.', 'sureforms' ) ] );
115 }
116
117 // decrypt the access key.
118 if ( ! empty( $access_key ) ) {
119 $this->decrypt_access_key( $access_key, $stored_key );
120 } else {
121 wp_send_json_error( [ 'message' => __( 'No access key provided.', 'sureforms' ) ] );
122 }
123 }
124
125 /**
126 * Decrypts a string using OpenSSL decryption.
127 *
128 * @param string $data The data to decrypt.
129 * @param string $key The encryption key.
130 * @param string $method The encryption method (e.g., AES-256-CBC).
131 * @since 0.0.8
132 * @return string|false The decrypted string or false on failure.
133 */
134 public function decrypt_access_key( $data, $key, $method = 'AES-256-CBC' ) {
135 // Decode the data and split IV and encrypted data.
136 $decoded_data = base64_decode( $data ); // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_decode
137
138 // if the data is not base64 encoded then return false.
139 if ( empty( $decoded_data ) ) {
140 return false;
141 }
142
143 // Extract the IV and encrypted data (billing portal sends IV::ENCRYPTED_DATA format).
144 $parts = explode( '::', $decoded_data, 2 );
145
146 if ( ! isset( $parts[1] ) ) {
147 wp_send_json_error( [ 'message' => __( 'Invalid access key format.', 'sureforms' ) ] );
148 }
149
150 $iv = $parts[0];
151 $encrypted = $parts[1];
152
153 // Decrypt the data using the server-stored key and the billing-portal-supplied IV.
154 $decrypted = openssl_decrypt( $encrypted, $method, $key, 0, $iv );
155
156 // if the decryption returns false then send error.
157 if ( empty( $decrypted ) ) {
158 wp_send_json_error( [ 'message' => __( 'Failed to decrypt the access key.', 'sureforms' ) ] );
159 }
160
161 // json decode the decrypted data.
162 $decrypted_data_array = json_decode( $decrypted, true );
163
164 if ( ! is_array( $decrypted_data_array ) || empty( $decrypted_data_array ) ) {
165 wp_send_json_error( [ 'message' => __( 'Failed to json decode the decrypted data.', 'sureforms' ) ] );
166 }
167
168 // verify the nonce that comes in $encrypted_email_array.
169 if ( empty( $decrypted_data_array['nonce'] ) || ! wp_verify_nonce( $decrypted_data_array['nonce'], 'ai_auth_nonce' ) ) {
170 wp_send_json_error( [ 'message' => __( 'Nonce verification failed.', 'sureforms' ) ] );
171 }
172
173 // check if the user email is present in the decrypted data.
174 if ( empty( $decrypted_data_array['user_email'] ) ) {
175 wp_send_json_error( [ 'message' => __( 'No user email found in the decrypted data.', 'sureforms' ) ] );
176 }
177
178 // Extract is_subscribed value if present.
179 $is_subscribed = false;
180 if ( isset( $decrypted_data_array['is_subscribed'] ) ) {
181 // Convert string 'true'/'false' to boolean if needed.
182 if ( is_string( $decrypted_data_array['is_subscribed'] ) ) {
183 $is_subscribed = 'true' === $decrypted_data_array['is_subscribed'];
184 } else {
185 $is_subscribed = (bool) $decrypted_data_array['is_subscribed'];
186 }
187
188 // Update the analytics option based on the preference.
189 // Set 'yes' if opted in, empty string if not.
190 $enable_contribution = $is_subscribed ? 'yes' : '';
191 update_option( 'sureforms_usage_optin', $enable_contribution );
192
193 // Remove is_subscribed from the decrypted data.
194 unset( $decrypted_data_array['is_subscribed'] );
195 }
196
197 // remove the nonce from the decrypted data before saving it to the options.
198 unset( $decrypted_data_array['nonce'] );
199
200 // Clean up the auth key transient.
201 delete_transient( 'srfm_ai_auth_key_' . get_current_user_id() );
202
203 // save the user email to the options.
204 update_option( 'srfm_ai_auth_user_email', $decrypted_data_array );
205
206 wp_send_json_success();
207 }
208 }
209