PluginProbe
Passster – Password Protect Pages and Content / 4.3.17
Passster – Password Protect Pages and Content v4.3.17
4.3.17 4.3.16 4.3.15 4.3.14 4.3.12 4.3.13 4.3.11 4.3.10 4.3.9 4.3.8 4.3.7 4.3.6 4.3.5 trunk 3.5.4 3.5.5.2 3.5.5.8 3.5.5.9 4.0 4.1.4 4.2.10 4.2.11 4.2.12 4.2.13 4.2.14 All 49 releases
← All changes | assets/public/passster-public.js +308 -353 4.2.11 → 4.3.17 View file →
@@ -1,388 +1,343 @@
1 -jQuery(document).ready(function ($) {
1 +jQuery( document ).ready( function( $ ) {
2 + const restUrl = ps_ajax.rest_url + 'passster/v1';
2 3
3 - // Get cookie duration.
4 - function getDurationBySettings() {
5 - switch (ps_ajax.cookie_duration_unit) {
6 - case 'days':
7 - return parseInt(ps_ajax.cookie_duration);
8 - break;
9 - case 'hours':
10 - return new Date(new Date().getTime() + (ps_ajax.cookie_duration * 10) * 60 * 1000);
11 - break;
12 - case 'minutes':
13 - return new Date(new Date().getTime() + ps_ajax.cookie_duration * 60 * 1000);
14 - break;
15 - default:
16 - return parseInt(ps_ajax.cookie_duration);
17 - }
18 - }
4 + // Get cookie duration.
5 + function getDurationBySettings() {
6 + switch ( ps_ajax.cookie_duration_unit ) {
7 + case 'days':
8 + return parseInt( ps_ajax.cookie_duration );
9 + case 'hours':
10 + return new Date( new Date().getTime() + ( ps_ajax.cookie_duration * 60 ) * 60 * 1000 );
11 + case 'minutes':
12 + return new Date( new Date().getTime() + ps_ajax.cookie_duration * 60 * 1000 );
13 + default:
14 + return parseInt( ps_ajax.cookie_duration );
15 + }
16 + }
19 17
20 - // Get cache busting URL.
21 - function getCacheFriendlyURL() {
22 - if (location.search) {
23 - return (location.origin).concat(location.pathname).concat(location.hash) + location.search + '&pts=' + Math.floor(Date.now() / 1000);
24 - } else {
25 - return (location.origin).concat(location.pathname).concat(location.hash) + '?pts=' + Math.floor(Date.now() / 1000);
26 - }
27 - }
18 + // Get cache busting URL.
19 + function getCacheFriendlyURL() {
20 + const pts = 'pts=' + Math.floor( Date.now() / 1000 );
21 + const base = location.origin + location.pathname;
22 + const search = location.search ? location.search + '&' + pts : '?' + pts;
23 + const hash = location.hash || '';
24 + return base + search + hash;
25 + }
28 26
29 - // Get hashed cookie via Ajax.
30 - function setHashedCookie(password) {
31 - $.ajax({
32 - type: "post", dataType: "json", url: ps_ajax.ajax_url, data: {
33 - 'action': 'hash_password', 'hash_nonce': ps_ajax.hash_nonce, 'password': password,
34 - }, success: function (response) {
35 - Cookies.set('passster', response.password, {
36 - expires: getDurationBySettings(), sameSite: 'strict'
37 - });
38 - }, async: false,
39 - });
40 - }
27 + // Hash password via REST API.
28 + async function hashPassword( password, postId ) {
29 + try {
30 + const response = await fetch( restUrl + '/hash', {
31 + method: 'POST',
32 + credentials: 'same-origin',
33 + headers: { 'Content-Type': 'application/json' },
34 + body: JSON.stringify( { password, post_id: postId } ),
35 + } );
36 + const data = await response.json();
37 + return data.hash || '';
38 + } catch ( e ) {
39 + return '';
40 + }
41 + }
41 42
42 - // Check if we have an unlock link.
43 - if (ps_ajax.link_pass) {
44 - if (!ps_ajax.disable_cookie) {
45 - if (ps_ajax.link_pass.length < 25) {
46 - // It's an old base64 encryption.
47 - setHashedCookie(atob(ps_ajax.link_pass));
48 - } else {
49 - Cookies.set('passster', ps_ajax.link_pass, {
50 - expires: getDurationBySettings(), sameSite: 'strict'
51 - });
52 - }
43 + // Get existing hashes from cookie as array.
44 + function getExistingHashes() {
45 + const existing = Cookies.get( 'passster' );
46 + if ( ! existing ) {
47 + return [];
48 + }
49 + // Support both old (single hash) and new (pipe-separated) format
50 + return existing.split( '|' ).filter( h => h.length > 0 );
51 + }
53 52
54 - // Handle the redirect with cache busting.
55 - window.location.replace(ps_ajax.permalink + '?pts=' + Math.floor(Date.now() / 1000));
56 - }
57 - }
53 + // Set hashed cookie (appends to existing hashes).
54 + async function setHashedCookie( password, postId ) {
55 + const hash = await hashPassword( password, postId );
56 + if ( hash ) {
57 + const hashes = getExistingHashes();
58 + // Only add if not already present
59 + if ( ! hashes.includes( hash ) ) {
60 + hashes.push( hash );
61 + }
62 + Cookies.set( 'passster', hashes.join( '|' ), {
63 + expires: getDurationBySettings(),
64 + sameSite: 'strict',
65 + } );
66 + }
67 + }
58 68
59 - // Passwords
60 - $('.passster-submit').on('click', function (e) {
61 - e.preventDefault();
69 + // Set simple cookie (for captcha) - appends to existing.
70 + function setCookie( value ) {
71 + const hashes = getExistingHashes();
72 + if ( ! hashes.includes( value ) ) {
73 + hashes.push( value );
74 + }
75 + Cookies.set( 'passster', hashes.join( '|' ), {
76 + expires: getDurationBySettings(),
77 + sameSite: 'strict',
78 + } );
79 + }
62 80
63 - // Validate form before submitting ajax.
64 - var form = $(this).parent().parent();
81 + // Handle successful unlock.
82 + function handleSuccess( data, $form, redirect ) {
83 + if ( data.redirect ) {
84 + window.location.replace( data.redirect );
85 + return;
86 + }
65 87
66 - if (!$(form)[0].checkValidity()) {
67 - $(form)[0].reportValidity();
68 - }
88 + if ( ! ps_ajax.unlock_mode ) {
89 + window.location.href = getCacheFriendlyURL();
90 + } else {
91 + $form.find( '.passster-error' ).hide();
92 + if ( data.requires_reload ) {
93 + window.location.href = getCacheFriendlyURL();
94 + return;
95 + }
96 + if ( data.content ) {
97 + let content = data.content;
98 + if ( ps_ajax.shortcodes ) {
99 + $.each( ps_ajax.shortcodes, function( key, value ) {
100 + content = content.replace( key, value );
101 + } );
102 + }
103 + $form.replaceWith( content );
104 + }
105 + if ( redirect ) {
106 + window.location.replace( redirect );
107 + }
108 + }
109 + }
69 110
70 - ps_id = $(this).attr('data-psid');
71 - form = $("#" + ps_id);
72 - password = $("#" + ps_id + ' .passster-password').attr('data-password');
73 - type = $("#" + ps_id + ' .passster-password').attr('data-protection-type');
74 - list = $("#" + ps_id + ' .passster-password').attr('data-list');
75 - lists = $("#" + ps_id + ' .passster-password').attr('data-lists');
76 - area = $("#" + ps_id + ' .passster-password').attr('data-area');
77 - protection = $("#" + ps_id + ' .passster-password').attr('data-protection');
78 - redirect = $(this).attr('data-redirect');
79 - input = $("#" + ps_id + ' .passster-password').val();
80 - acf = $(this).attr('data-acf');
111 + // Show error.
112 + function showError( $form, message ) {
113 + const $error = $form.find( '.passster-error' );
114 + $error.text( message || 'An error occurred.' );
115 + $error.show().fadeOut( 3500 );
116 + }
81 117
82 - $.ajax({
83 - type: "post", dataType: "json", url: ps_ajax.ajax_url, data: {
84 - 'action': 'validate_input',
85 - 'nonce': ps_ajax.nonce,
86 - 'input': input,
87 - 'password': password,
88 - 'post_id': ps_ajax.post_id,
89 - 'type': type,
90 - 'list': list,
91 - 'lists': lists,
92 - 'area': area,
93 - 'protection': protection,
94 - 'acf': acf,
95 - 'redirect': redirect
96 - }, beforeSend: function () {
97 - form.find(".ps-loader").css('display', 'block');
98 - }, success: function (response) {
99 - form.find(".ps-loader").css('display', 'none');
100 - if (true === response.success) {
101 - // if no ajax.
102 - if (!ps_ajax.unlock_mode) {
103 - setHashedCookie(input);
118 + // Check if we have an unlock link.
119 + if ( ps_ajax.link_pass ) {
120 + if ( ! ps_ajax.disable_cookie ) {
121 + if ( ps_ajax.link_pass.length < 25 ) {
122 + setHashedCookie( atob( ps_ajax.link_pass ), ps_ajax.post_id ).then( () => {
123 + window.location.replace( ps_ajax.permalink + '?pts=' + Math.floor( Date.now() / 1000 ) );
124 + } );
125 + } else {
126 + setCookie( ps_ajax.link_pass );
127 + window.location.replace( ps_ajax.permalink + '?pts=' + Math.floor( Date.now() / 1000 ) );
128 + }
129 + }
130 + }
104 131
105 - if (response.redirect) {
106 - window.location.replace(redirect);
107 - } else {
108 - window.location.href = getCacheFriendlyURL();
109 - }
110 - } else {
132 + // Password form submit - using REST API.
133 + $( '.passster-submit' ).on( 'click', async function( e ) {
134 + e.preventDefault();
111 135
112 - // set cookie if activated.
113 - if (!ps_ajax.disable_cookie) {
114 - setHashedCookie(input);
115 - }
116 - form.find('.passster-error').hide();
136 + const $button = $( this );
137 + const psId = $button.attr( 'data-psid' );
138 + const $form = $( '#' + psId );
139 + const $input = $form.find( '.passster-password' );
140 + const postId = parseInt( $button.attr( 'data-post-id' ) ) || ps_ajax.post_id;
117 141
118 - // replace shortcodes.
119 - let content = response.content;
142 + // Validate form.
143 + const formEl = $form.find( 'form' )[ 0 ];
144 + if ( formEl && ! formEl.checkValidity() ) {
145 + formEl.reportValidity();
146 + return;
147 + }
120 148
121 - if (content) {
122 - $.each(ps_ajax.shortcodes, function (key, value) {
123 - content = content.replace(key, value);
124 - });
149 + // Get form data.
150 + const password = $input.val();
151 + const type = ( $input.attr( 'data-protection-type' ) || 'password' ).replace( /-/g, '_' );
152 + const areaId = parseInt( $input.attr( 'data-area' ) ) || 0;
153 + const listId = parseInt( $input.attr( 'data-list' ) ) || 0;
154 + const lists = $input.attr( 'data-lists' ) || '';
155 + const protection = $input.attr( 'data-protection' ) || '';
156 + const acf = $button.attr( 'data-acf' ) || '';
157 + const redirect = $button.attr( 'data-redirect' ) || '';
158 + const termId = parseInt( $button.attr( 'data-term-id' ) ) || 0;
159 + const postType = $button.attr( 'data-post-type' ) || '';
125 160
126 - $("#" + ps_id).replaceWith(content);
127 - }
161 + // Get block ID from parent wrapper if exists.
162 + const $wrapper = $form.closest( '.passster-protected-content' );
163 + const blockId = $wrapper.length ? $wrapper.attr( 'data-block-id' ) : '';
128 164
129 - // Redirect?
130 - if (response.redirect) {
131 - window.location.replace(redirect);
132 - }
165 + $form.find( '.ps-loader' ).css( 'display', 'block' );
133 166
134 - }
135 - } else {
136 - form.find('.passster-error').text(response.error);
137 - form.find('.passster-error').show().fadeOut(3500);
138 - $("#" + ps_id + ' .passster-password').val('');
139 - }
140 - }
141 - });
142 - });
167 + try {
168 + const response = await fetch( restUrl + '/unlock', {
169 + method: 'POST',
170 + credentials: 'same-origin',
171 + headers: { 'Content-Type': 'application/json' },
172 + body: JSON.stringify( {
173 + password,
174 + type,
175 + post_id: postId,
176 + area_id: areaId,
177 + block_id: blockId,
178 + list_id: listId,
179 + lists,
180 + protection,
181 + acf,
182 + redirect,
183 + term_id: termId,
184 + post_type: postType,
185 + } ),
186 + } );
143 187
144 - // Recaptcha v2
145 - if ($('.recaptcha-form-v2').length > 0) {
146 - grecaptcha.ready(function () {
147 - grecaptcha.render('ps-recaptcha-v2', {
148 - 'sitekey': ps_ajax.recaptcha_key, 'callback': function (token) {
149 - ps_id = $('.recaptcha-v2-submit').attr('data-psid');
150 - form = $("#" + ps_id);
151 - protection = $('.recaptcha-v2-submit').attr('data-protection');
152 - acf = $('.recaptcha-v2-submit').attr('data-acf');
153 - area = $("#" + ps_id).find('.recaptcha-v2-submit').attr('data-area');
154 - redirect = $("#" + ps_id).find('.recaptcha-v2-submit').attr('data-redirect');
188 + const data = await response.json();
189 + $form.find( '.ps-loader' ).css( 'display', 'none' );
190 + if ( data.success ) {
191 + handleSuccess( data, $form, redirect );
192 + } else {
193 + showError( $form, data.error );
194 + $input.val( '' );
195 + }
196 + } catch ( err ) {
197 + $form.find( '.ps-loader' ).css( 'display', 'none' );
198 + showError( $form, 'An error occurred. Please try again.' );
199 + }
200 + } );
155 201
156 - $.ajax({
157 - type: "post", dataType: "json", url: ps_ajax.ajax_url, data: {
158 - 'action': 'validate_input',
159 - 'nonce': ps_ajax.nonce,
160 - 'token': token,
161 - 'post_id': ps_ajax.post_id,
162 - 'type': 'recaptcha',
163 - 'protection': protection,
164 - 'captcha_id': ps_id,
165 - 'acf': acf,
166 - 'area': area,
167 - 'redirect': redirect
168 - }, success: function (response) {
169 - if (true === response.success) {
202 + // Captcha validation via REST API.
203 + async function validateCaptcha( token, type, $form, psId, areaId, redirect, protection ) {
204 + try {
205 + const response = await fetch( restUrl + '/captcha', {
206 + method: 'POST',
207 + credentials: 'same-origin',
208 + headers: { 'Content-Type': 'application/json' },
209 + body: JSON.stringify( {
210 + token,
211 + type,
212 + post_id: ps_ajax.post_id,
213 + area_id: areaId,
214 + redirect,
215 + protection: protection || '',
216 + } ),
217 + } );
170 218
171 - // if no ajax.
172 - if (!ps_ajax.unlock_mode) {
173 - Cookies.set('passster', 'recaptcha', {
174 - expires: getDurationBySettings(), sameSite: 'strict'
175 - });
219 + const data = await response.json();
176 220
177 - if (response.redirect) {
178 - window.location.replace(redirect);
179 - } else {
180 - window.location.href = getCacheFriendlyURL();
181 - }
182 - } else {
183 - // set cookie if activated.
184 - if (!ps_ajax.disable_cookie) {
185 - Cookies.set('passster', 'recaptcha', {
186 - expires: getDurationBySettings(), sameSite: 'strict'
187 - });
188 - }
189 - form.find('.passster-error').hide();
221 + if ( data.success ) {
222 + handleSuccess( data, $form, redirect );
223 + } else {
224 + showError( $form, data.error );
225 + }
226 + } catch ( err ) {
227 + showError( $form, 'Captcha validation failed.' );
228 + }
229 + }
190 230
191 - // replace shortcodes.
192 - let content = response.content;
231 + // Recaptcha v2
232 + if ( $( '.recaptcha-form-v2' ).length > 0 && window.grecaptcha ) {
233 + grecaptcha.ready( function() {
234 + grecaptcha.render( 'ps-recaptcha-v2', {
235 + sitekey: ps_ajax.recaptcha_key,
236 + callback( token ) {
237 + const psId = $( '.recaptcha-v2-submit' ).attr( 'data-psid' );
238 + const $form = $( '#' + psId );
239 + const $btn = $form.find( '.recaptcha-v2-submit' );
240 + const areaId = parseInt( $btn.attr( 'data-area' ) ) || 0;
241 + const redirect = $btn.attr( 'data-redirect' ) || '';
242 + const protection = $btn.attr( 'data-protection' ) || '';
193 243
194 - if (content) {
244 + validateCaptcha( token, 'recaptcha_v2', $form, psId, areaId, redirect, protection );
245 + },
246 + } );
247 + } );
248 + }
195 249
196 - $.each(ps_ajax.shortcodes, function (key, value) {
197 - content = content.replace(key, value);
198 - });
250 + // ReCaptcha v3
251 + $( '.recaptcha-form' ).on( 'submit', function( event ) {
252 + event.preventDefault();
199 253
200 - $("#" + ps_id).replaceWith(content);
201 - }
254 + const $thisForm = $( this );
255 + const $btn = $thisForm.find( '.passster-submit-recaptcha' );
256 + const psId = $btn.attr( 'data-psid' );
257 + const $form = $( '#' + psId );
258 + const areaId = parseInt( $btn.attr( 'data-area' ) ) || 0;
259 + const redirect = $btn.attr( 'data-redirect' ) || '';
260 + const protection = $btn.attr( 'data-protection' ) || '';
202 261
203 - // Redirect?
204 - if (response.redirect) {
205 - window.location.replace(redirect);
206 - }
207 - }
208 - } else {
209 - form.find('.passster-error').text(response.error);
210 - form.find('.passster-error').show().fadeOut(3500);
211 - }
212 - }
213 - });
214 - }
215 - });
216 - });
217 - }
262 + if ( window.grecaptcha ) {
263 + grecaptcha.ready( function() {
264 + grecaptcha.execute( ps_ajax.recaptcha_key, { action: 'validate_input' } ).then( function( token ) {
265 + validateCaptcha( token, 'recaptcha_v3', $form, psId, areaId, redirect, protection );
266 + } );
267 + } );
268 + }
269 + } );
218 270
219 - // ReCaptcha v3
220 - $('.recaptcha-form').on('submit', function (event) {
221 - event.preventDefault();
271 + // hCaptcha
272 + $( '.hcaptcha-form' ).on( 'submit', function( event ) {
273 + event.preventDefault();
222 274
223 - ps_id = $(this).find('.passster-submit-recaptcha').attr('data-psid');
224 - form = $("#" + ps_id);
225 - protection = $(this).find('.passster-submit-recaptcha').attr('data-protection');
226 - acf = $(this).find('.passster-submit-recaptcha').attr('data-acf');
227 - area = $(this).find('.passster-submit-recaptcha').attr('data-area');
228 - redirect = $(this).find('.passster-submit-recaptcha').attr('data-redirect');
275 + const $thisForm = $( this );
276 + const $btn = $thisForm.find( '.passster-submit-recaptcha' );
277 + const psId = $btn.attr( 'data-psid' );
278 + const $form = $( '#' + psId );
279 + const areaId = parseInt( $btn.attr( 'data-area' ) ) || 0;
280 + const redirect = $btn.attr( 'data-redirect' ) || '';
281 + const protection = $btn.attr( 'data-protection' ) || '';
229 282
230 - grecaptcha.ready(function () {
231 - grecaptcha.execute(ps_ajax.recaptcha_key, {action: 'validate_input'}).then(function (token) {
283 + if ( window.hcaptcha ) {
284 + hcaptcha.execute( { async: true } )
285 + .then( ( { response } ) => {
286 + validateCaptcha( response, 'hcaptcha', $form, psId, areaId, redirect, protection );
287 + } )
288 + .catch( ( err ) => {
289 + showError( $form, err.message || 'hCaptcha error' );
290 + } );
291 + }
292 + } );
232 293
233 - form.prepend('<input type="hidden" name="token" value="' + token + '">');
234 - form.prepend('<input type="hidden" name="action" value="validate_input">');
294 + // Turnstile
295 + let turnstileToken = '';
296 + if ( $( '.turnstile-form' ).length > 0 && window.turnstile ) {
297 + window.turnstile.ready( function() {
298 + window.turnstile.render( '.passster-turnstile', {
299 + sitekey: ps_ajax.turnstile_key,
300 + callback( token ) {
301 + turnstileToken = token;
302 + },
303 + } );
304 + } );
235 305
236 - $.ajax({
237 - type: "post", dataType: "json", url: ps_ajax.ajax_url, data: {
238 - 'action': 'validate_input',
239 - 'nonce': ps_ajax.nonce,
240 - 'token': token,
241 - 'post_id': ps_ajax.post_id,
242 - 'type': 'recaptcha',
243 - 'protection': protection,
244 - 'captcha_id': ps_id,
245 - 'acf': acf,
246 - 'area': area,
247 - 'redirect': redirect
248 - }, success: function (response) {
249 - if (true === response.success) {
306 + $( '.turnstile-form' ).on( 'submit', function( event ) {
307 + event.preventDefault();
250 308
251 - // if no ajax.
252 - if (!ps_ajax.unlock_mode) {
253 - Cookies.set('passster', 'recaptcha', {
254 - expires: getDurationBySettings(), sameSite: 'strict'
255 - });
309 + const $thisForm = $( this );
310 + const $btn = $thisForm.find( '.passster-submit-turnstile' );
311 + const psId = $btn.attr( 'data-psid' );
312 + const $form = $( '#' + psId );
313 + const areaId = parseInt( $btn.attr( 'data-area' ) ) || 0;
314 + const redirect = $btn.attr( 'data-redirect' ) || '';
315 + const protection = $btn.attr( 'data-protection' ) || '';
256 316
257 - if (response.redirect) {
258 - window.location.replace(redirect);
259 - } else {
260 - window.location.href = getCacheFriendlyURL();
261 - }
262 - } else {
263 - // set cookie if activated.
264 - if (!ps_ajax.disable_cookie) {
265 - Cookies.set('passster', 'recaptcha', {
266 - expires: getDurationBySettings(), sameSite: 'strict'
267 - });
268 - }
269 - form.find('.passster-error').hide();
270 - // replace shortcodes.
271 - let content = response.content;
317 + if ( ! turnstileToken ) {
318 + showError( $form, 'Please complete the verification.' );
319 + return;
320 + }
272 321
273 - if (content) {
274 - $.each(ps_ajax.shortcodes, function (key, value) {
275 - content = content.replace(key, value);
276 - });
322 + validateCaptcha( turnstileToken, 'turnstile', $form, psId, areaId, redirect, protection );
323 + } );
324 + }
277 325
278 - form.replaceWith(content);
279 - }
280 -
281 - // Redirect?
282 - if (response.redirect) {
283 - window.location.replace(redirect);
284 - }
285 - }
286 - } else {
287 - form.find('.passster-error').text(response.error);
288 - form.find('.passster-error').show().fadeOut(3500);
289 - }
290 - }
291 - });
292 - });
293 - });
294 - });
295 -
296 - // hcaptcha
297 - $('.hcaptcha-form').on('submit', function (event) {
298 - event.preventDefault();
299 -
300 - ps_id = $(this).find('.passster-submit-recaptcha').attr('data-psid');
301 - form = $("#" + ps_id);
302 - protection = $(this).find('.passster-submit-recaptcha').attr('data-protection');
303 - acf = $(this).find('.passster-submit-recaptcha').attr('data-acf');
304 - area = $(this).find('.passster-submit-recaptcha').attr('data-area');
305 - redirect = $(this).find('.passster-submit-recaptcha').attr('data-redirect');
306 -
307 - hcaptcha.execute({async: true})
308 - .then(({response, key}) => {
309 - $.ajax({
310 - type: "post", dataType: "json", url: ps_ajax.ajax_url, data: {
311 - 'action': 'validate_input',
312 - 'nonce': ps_ajax.nonce,
313 - 'token': response,
314 - 'post_id': ps_ajax.post_id,
315 - 'type': 'recaptcha',
316 - 'protection': protection,
317 - 'captcha_id': ps_id,
318 - 'acf': acf,
319 - 'area': area,
320 - 'redirect': redirect
321 - }, success: function (response) {
322 - if (true === response.success) {
323 -
324 - // if no ajax.
325 - if (!ps_ajax.unlock_mode) {
326 - Cookies.set('passster', 'recaptcha', {
327 - expires: getDurationBySettings(), sameSite: 'strict'
328 - });
329 -
330 - if (response.redirect) {
331 - window.location.replace(redirect);
332 - } else {
333 - window.location.href = getCacheFriendlyURL();
334 - }
335 - } else {
336 - // set cookie if activated.
337 - if (!ps_ajax.disable_cookie) {
338 - Cookies.set('passster', 'recaptcha', {
339 - expires: getDurationBySettings(), sameSite: 'strict'
340 - });
341 - }
342 - form.find('.passster-error').hide();
343 - // replace shortcodes.
344 - let content = response.content;
345 -
346 - if (content) {
347 - $.each(ps_ajax.shortcodes, function (key, value) {
348 - content = content.replace(key, value);
349 - });
350 -
351 - form.replaceWith(content);
352 - }
353 -
354 - // Redirect?
355 - if (response.redirect) {
356 - window.location.replace(redirect);
357 - }
358 - }
359 - } else {
360 - form.find('.passster-error').text(response.error);
361 - form.find('.passster-error').show().fadeOut(3500);
362 - }
363 - }
364 - });
365 - })
366 - .catch(err => {
367 - form.find('.passster-error').text(err);
368 - form.find('.passster-error').show().fadeOut(3500);
369 - });
370 -
371 - });
372 -
373 - // Concurrent logout.
374 - $(document).on('click', '#ps-logout', function () {
375 - $.ajax({
376 - type: 'post',
377 - dataType: 'json',
378 - url: ps_ajax.ajax_url,
379 - data: {'action': 'handle_logout', 'logout_nonce': ps_ajax.logout_nonce},
380 - success: function (response) {
381 - if (true === response.success) {
382 - Cookies.set('passster', '', {expires: 0, sameSite: 'strict'});
383 - window.location.href = getCacheFriendlyURL();
384 - }
385 - }
386 - });
387 - });
388 -});
326 + // Concurrent logout - using REST API.
327 + $( document ).on( 'click', '#ps-logout', async function() {
328 + try {
329 + const response = await fetch( restUrl + '/logout', {
330 + method: 'POST',
331 + credentials: 'same-origin',
332 + headers: { 'Content-Type': 'application/json' },
333 + } );
334 + const data = await response.json();
335 + if ( data.success ) {
336 + Cookies.set( 'passster', '', { expires: 0, sameSite: 'strict' } );
337 + window.location.href = getCacheFriendlyURL();
338 + }
339 + } catch ( e ) {
340 + window.location.href = getCacheFriendlyURL();
341 + }
342 + } );
343 +} );