From d4f5275f547d8129df3ac34e7fd039b0baffb40d Mon Sep 17 00:00:00 2001 From: Glomberg Date: Thu, 8 Oct 2026 11:07:15 +0300 Subject: [PATCH 1/6] Dev. Code. JS code for parameters handling refactored #1. --- js/new_src/functions/ajaxHandlers.js | 527 ++++++++++++++++++ js/new_src/functions/noCookieHiddenField.js | 237 ++++++++ js/new_src/functions/storeParams.js | 127 +++++ js/new_src/initParams.js | 16 + js/new_src/params/checkJs.js | 17 + js/new_src/params/headless.js | 5 + js/new_src/params/pageSetTimestamp.js | 5 + js/new_src/params/timezone.js | 6 + js/new_src/utils/apbctLocalStorage.js | 61 ++ js/new_src/utils/apbctSessionStorage.js | 41 ++ js/new_src/utils/botDetectorLog.js | 98 ++++ js/prebuild/apbct-public-bundle.js | 24 +- js/src/public-0-core.js | 481 ---------------- js/src/public-1-functions.js | 203 +------ js/src/public-1-main.js | 29 - js/src/public-3-bot-detector-log.js | 24 +- .../ApbctWP/ApbctJsBundleResolver.php | 2 +- webpack.config.js | 117 ++-- 18 files changed, 1218 insertions(+), 802 deletions(-) create mode 100644 js/new_src/functions/ajaxHandlers.js create mode 100644 js/new_src/functions/noCookieHiddenField.js create mode 100644 js/new_src/functions/storeParams.js create mode 100644 js/new_src/initParams.js create mode 100644 js/new_src/params/checkJs.js create mode 100644 js/new_src/params/headless.js create mode 100644 js/new_src/params/pageSetTimestamp.js create mode 100644 js/new_src/params/timezone.js create mode 100644 js/new_src/utils/apbctLocalStorage.js create mode 100644 js/new_src/utils/apbctSessionStorage.js create mode 100644 js/new_src/utils/botDetectorLog.js diff --git a/js/new_src/functions/ajaxHandlers.js b/js/new_src/functions/ajaxHandlers.js new file mode 100644 index 000000000..30835430b --- /dev/null +++ b/js/new_src/functions/ajaxHandlers.js @@ -0,0 +1,527 @@ +export function sendAJAX(data, params, obj) { + // Default params + let _params = []; + _params['callback'] = params.callback || null; + _params['onErrorCallback'] = params.onErrorCallback || null; + _params['callback_context'] = params.callback_context || null; + _params['callback_params'] = params.callback_params || null; + _params['async'] = params.async || true; + _params['notJson'] = params.notJson || null; + _params['responseType']= params.notJson ? 'text' : 'json'; + _params['timeout'] = params.timeout || 15000; + _params['obj'] = obj || null; + _params['button'] = params.button || null; + _params['spinner'] = params.spinner || null; + _params['progressbar'] = params.progressbar || null; + _params['silent'] = params.silent || null; + _params['no_nonce'] = params.no_nonce || null; + _params['data'] = data; + _params['url'] = ctPublicFunctions._ajax_url; + const nonce = selectActualNonce(); + + if (typeof (data) === 'string') { + if ( ! _params['no_nonce'] ) { + _params['data'] = _params['data'] + '&_ajax_nonce=' + nonce; + } + _params['data'] = _params['data'] + '&no_cache=' + Math.random(); + } else { + if ( ! _params['no_nonce'] ) { + _params['data']._ajax_nonce = nonce; + } + _params['data'].no_cache = Math.random(); + } + + new ApbctAjax(_params); +} + +export function sendREST( route, params ) { + let _params = []; + _params['route'] = route; + _params['callback'] = params.callback || null; + _params['onErrorCallback'] = params.onErrorCallback || null; + _params['data'] = params.data || []; + _params['method'] = params.method || 'POST'; + + new ApbctRest(_params); +} + +/** + * ApbctXhr + */ +class ApbctXhr { + xhr = new XMLHttpRequest(); + + // Base parameters + method = 'POST'; // HTTP-request type + url = ''; // URL to send the request + async = true; + user = null; // HTTP-authorization username + password = null; // HTTP-authorization password + data = {}; // Data to send + + // Optional params + button = null; // Button that should be disabled when request is performing + spinner = null; // Spinner that should appear when request is in process + progressbar = null; // Progress bar for the current request + context = this; // Context + callback = null; + onErrorCallback = null; + + responseType = 'json'; // Expected data type from server + headers = {}; + timeout = 15000; // Request timeout in milliseconds + + methods_to_convert_data_to_URL = [ + 'GET', + 'HEAD', + ]; + + body = null; + http_code = 0; + status_text = ''; + + // eslint-disable-next-line require-jsdoc + constructor(parameters) { + // Set class properties + for ( let key in parameters ) { + if ( typeof this[key] !== 'undefined' ) { + this[key] = parameters[key]; + } + } + + // Modifying DOM-elements + this.prepare(); + + // Modify URL with data for GET and HEAD requests + if ( Object.keys(this.data).length ) { + this.deleteDoubleJSONEncoding(this.data); + this.convertData(); + } + + if ( ! this.url ) { + console.log('%cXHR%c not URL provided', + 'color: red; font-weight: bold;', 'color: grey; font-weight: normal;'); + return false; + } + + // Configure the request + this.xhr.open(this.method, this.url, this.async, this.user, this.password); + this.setHeaders(); + + this.xhr.responseType = this.responseType; + this.xhr.timeout = this.timeout; + + /* EVENTS */ + // Monitoring status + this.xhr.onreadystatechange = function() { + if (this.isWpNonceError()) { + this.getFreshNonceAndRerunXHR(parameters); + return; + } + this.onReadyStateChange(); + }.bind(this); + + // Run callback + this.xhr.onload = function() { + this.onLoad(); + }.bind(this); + + // On progress + this.xhr.onprogress = function(event) { + this.onProgress(event); + }.bind(this); + + // On error + this.xhr.onerror = function() { + this.onError(); + }.bind(this); + + this.xhr.ontimeout = function() { + this.onTimeout(); + }.bind(this); + + // Send the request + this.xhr.send(this.body); + } + + /** + * prepare + */ + prepare() { + // Disable button + if (this.button) { + this.button.setAttribute('disabled', 'disabled'); + this.button.style.cursor = 'not-allowed'; + } + + // Enable spinner + if (this.spinner) { + this.spinner.style.display = 'inline'; + } + } + + /** + * complete + */ + complete() { + this.http_code = this.xhr.status; + this.status_text = this.xhr.statusText; + + // Disable button + if (this.button) { + this.button.removeAttribute('disabled'); + this.button.style.cursor = 'auto'; + } + + // Enable spinner + if (this.spinner) { + this.spinner.style.display = 'none'; + } + + if ( this.progressbar ) { + this.progressbar.fadeOut('slow'); + } + } + + /** + * onReadyStateChange + */ + onReadyStateChange() { + if (this.on_ready_state_change !== null && typeof this.on_ready_state_change === 'function') { + this.on_ready_state_change(); + } + } + + /** + * @param {object} event + */ + onProgress(event) { + if (this.on_progress !== null && typeof this.on_progress === 'function') { + this.on_progress(); + } + } + + /** + * onError + */ + onError() { + console.log('error'); + + this.complete(); + this.error( + this.http_code, + this.status_text, + ); + + if (this.onErrorCallback !== null && typeof this.onErrorCallback === 'function') { + this.onErrorCallback(this.status_text); + } + } + + /** + * onTimeout + */ + onTimeout() { + this.complete(); + this.error( + 0, + 'timeout', + ); + + if (this.onErrorCallback !== null && typeof this.onErrorCallback === 'function') { + this.onErrorCallback('Timeout'); + } + } + + /** + * @return {boolean} + */ + onLoad() { + this.complete(); + + if (this.responseType === 'json' ) { + if (this.xhr.response === null) { + this.error(this.http_code, this.status_text, 'No response'); + return false; + } else if ( typeof this.xhr.response.error !== 'undefined') { + this.error(this.http_code, this.status_text, this.xhr.response.error); + return false; + } + } + + if (this.callback !== null && typeof this.callback === 'function') { + this.callback.call(this.context, this.xhr.response, this.data); + } + } + + /** + * Check if 403 code of WP nonce error + * @return {bool} + */ + isWpNonceError() { + let restErrror = false; + let ajaxErrror = false; + // check rest error + if (this.xhr.readyState == 4) { + restErrror = ( + typeof this.xhr.response === 'object' && this.xhr.response !== null && + this.xhr.response.hasOwnProperty('data') && + this.xhr.response.data.hasOwnProperty('status') && + this.xhr.response.data.status === 403 + ); + ajaxErrror = this.xhr.response === '-1' && this.xhr.status === 403; + } + // todo check AJAX error + return restErrror || ajaxErrror; + } + + /** + * Get the fresh nonce and rerun the initial XHR with params + * @param {[]} initialRequestParams + */ + getFreshNonceAndRerunXHR(initialRequestParams) { + let noncePrev = ''; + + // Check if initialRequestParams['headers']['X-WP-Nonce'] exists. + if ( + initialRequestParams.hasOwnProperty('headers') && + initialRequestParams.headers.hasOwnProperty('X-WP-Nonce') + ) { + noncePrev = initialRequestParams['headers']['X-WP-Nonce']; + } + + // Check if initialRequestParams['data']['_ajax_nonce'] exists. + if ( + initialRequestParams.hasOwnProperty('data') && + initialRequestParams.data.hasOwnProperty('_ajax_nonce') + ) { + noncePrev = initialRequestParams['data']['_ajax_nonce']; + } + + // Nonce is not provided. Exit. + if ( noncePrev === '' ) { + return; + } + + // prepare params for refreshing nonce + let params = {}; + params.method = 'POST'; + params.data = { + 'spbc_remote_call_action': 'get_fresh_wpnonce', + 'plugin_name': 'antispam', + 'nonce_prev': noncePrev, + 'initial_request_params': initialRequestParams, + }; + params.notJson = true; + params.url = ctPublicFunctions.host_url; + // this callback will rerun the XHR with initial params + params.callback = function(...args) { + // the refresh result itself + let freshNonceResult = args[0]; + let newRequestParams = false; + // provided initial params + if (args[1] !== undefined && args[1].hasOwnProperty('initial_request_params')) { + newRequestParams = args[1].initial_request_params; + } + if (newRequestParams && freshNonceResult.hasOwnProperty('wpnonce')) { + ctPublicFunctions._fresh_nonce = freshNonceResult.wpnonce; + if (ctPublicFunctions.data__ajax_type === 'rest') { + new ApbctCore().rest(newRequestParams); + } else { + new ApbctCore().ajax(newRequestParams); + } + } + }; + // run the nonce refreshing call + new ApbctXhr(params); + } + + /** + * @param {number} httpCode + * @param {string} statusText + * @param {string} additionalMsg + */ + error(httpCode, statusText, additionalMsg) { + let errorString = ''; + + if ( statusText === 'timeout' ) { + errorString += 'Server response timeout'; + } else if ( httpCode === 200 ) { + if ( statusText === 'parsererror' ) { + errorString += 'Unexpected response from server. See console for details.'; + } else { + errorString += 'Unexpected error. Status: ' + statusText + '.'; + if ( typeof additionalMsg !== 'undefined' ) { + errorString += ' Additional error info: ' + additionalMsg; + } + } + } else if (httpCode === 500) { + errorString += 'Internal server error.'; + } else { + errorString += 'Unexpected response code:' + httpCode; + } + + this.errorOutput( errorString ); + + if (this.onErrorCallback !== null && typeof this.onErrorCallback === 'function') { + this.onErrorCallback(this.status_text); + } + } + + /** + * @param {string} errorMsg + */ + errorOutput(errorMsg) { + console.log( '%c ctXHR error: %c' + errorMsg, 'color: red;', 'color: grey;' ); + } + + /** + * setHeaders + */ + setHeaders() { + // Set headers if passed + for ( let headerName in this.headers ) { + if ( typeof this.headers[headerName] !== 'undefined' ) { + this.xhr.setRequestHeader(headerName, this.headers[headerName]); + } + } + } + + /** + * @return {string|*} + */ + convertData() { + // GET, HEAD request-type + if ( ~this.methods_to_convert_data_to_URL.indexOf( this.method ) ) { + return this.convertDataToURL(); + + // POST request-type + } else { + return this.convertDataToBody(); + } + } + + /** + * @return {string} + */ + convertDataToURL() { + let paramsAppendix = new URLSearchParams(this.data).toString(); + let paramsPrefix = this.url.match(/^(https?:\/{2})?[a-z0-9.]+\?/) ? '&' : '?'; + this.url += paramsPrefix + paramsAppendix; + + return this.url; + } + + /** + * @return {null} + */ + convertDataToBody() { + this.body = new FormData(); + for (let dataKey in this.data) { + if (Object.hasOwn(this.data, dataKey)) { + this.body.append( + dataKey, + typeof this.data[dataKey] === 'object' ? + JSON.stringify(this.data[dataKey]) : + this.data[dataKey], + ); + } + } + + return this.body; + } + + /** + * Recursive + * + * Recursively decode JSON-encoded properties + * + * @param {object} object + * @return {*} + */ + deleteDoubleJSONEncoding(object) { + if ( typeof object === 'object') { + for (let objectKey in object) { + if (Object.hasOwn(object, objectKey)) { + // Recursion + if ( typeof object[objectKey] === 'object') { + object[objectKey] = this.deleteDoubleJSONEncoding(object[objectKey]); + } + + // Common case (out) + if ( + typeof object[objectKey] === 'string' && + object[objectKey].match(/^[\[{].*?[\]}]$/) !== null // is like JSON + ) { + let parsedValue = JSON.parse(object[objectKey]); + if ( typeof parsedValue === 'object' ) { + object[objectKey] = parsedValue; + } + } + } + } + } + + return object; + } +} +// eslint-disable-next-line require-jsdoc +class ApbctAjax extends ApbctXhr { + // eslint-disable-next-line require-jsdoc + constructor(...args) { + args = args[0]; + args.data._ajax_nonce = selectActualNonce(); + super(args); + } +} +// eslint-disable-next-line require-jsdoc +class ApbctRest extends ApbctXhr { + static default_route = ctPublicFunctions._rest_url + 'cleantalk-antispam/v1/'; + route = ''; + + // eslint-disable-next-line require-jsdoc + constructor(...args) { + args = args[0]; + const nonce = selectActualNonce(); + args.url = ApbctRest.default_route + args.route; + args.headers = { + 'X-WP-Nonce': nonce, + }; + super(args); + } +} + +/** + * Select actual WP nonce depending on the ajax type and the fresh nonce provided. + * @return {string} url + */ +function selectActualNonce() { + let defaultNonce = ''; + // return fresh nonce immediately if persists + if ( + ctPublicFunctions.hasOwnProperty('_fresh_nonce') && + typeof ctPublicFunctions._fresh_nonce === 'string' && + ctPublicFunctions._fresh_nonce.length > 0 + ) { + return ctPublicFunctions._fresh_nonce; + } + // select from default rest/ajax nonces + if ( + ctPublicFunctions.data__ajax_type === 'admin_ajax' && + ctPublicFunctions.hasOwnProperty('_ajax_nonce') && + typeof ctPublicFunctions._ajax_nonce === 'string' && + ctPublicFunctions._ajax_nonce.length > 0 + ) { + defaultNonce = ctPublicFunctions._ajax_nonce; + } + if ( + ctPublicFunctions.data__ajax_type === 'rest' && + ctPublicFunctions.hasOwnProperty('_rest_nonce') && + typeof ctPublicFunctions._rest_nonce === 'string' && + ctPublicFunctions._rest_nonce.length > 0 + ) { + defaultNonce = ctPublicFunctions._rest_nonce; + } + + return defaultNonce; +} diff --git a/js/new_src/functions/noCookieHiddenField.js b/js/new_src/functions/noCookieHiddenField.js new file mode 100644 index 000000000..aeef4755b --- /dev/null +++ b/js/new_src/functions/noCookieHiddenField.js @@ -0,0 +1,237 @@ +import {ApbctBrowserState} from '../utils/botDetectorLog'; +import {apbctLocalStorage} from '../utils/apbctLocalStorage'; +import {apbctSessionStorage} from '../utils/apbctSessionStorage'; + +export function ctNoCookieAttachHiddenFieldsToForms() { + if (ctPublic.data__cookies_type !== 'none') { + return; + } + + let forms = ctGetPageForms(); + + if (forms) { + for ( let i = 0; i < forms.length; i++ ) { + if ( checkHiddenFieldsExclusions(document.forms[i], 'no_cookie') ) { + continue; + } + + // ignore forms with get method @todo We need to think about this + if (document.forms[i].getAttribute('method') === null || + document.forms[i].getAttribute('method').toLowerCase() === 'post') { + // remove old sets + let fields = forms[i].querySelectorAll('.ct_no_cookie_hidden_field'); + for ( let j = 0; j < fields.length; j++ ) { + fields[j].outerHTML = ''; + } + // add new set + document.forms[i].append(constructNoCookieHiddenField()); + } + } + } +} + +/** + * @return {boolean|*} + */ +function ctGetPageForms() { // eslint-disable-line no-unused-vars + let forms = document.forms; + if (forms) { + return forms; + } + return false; +} + +/** + * Check if the form should be skipped from hidden field attach. + * Return exclusion description if it is found, false otherwise. + * @param {object} form Form dom object. + * @param {string} hiddenFieldType Type of hidden field that needs to be checked. + * Possible values: 'no_cookie'|'visible_fields'. + * @return {boolean} + */ +function checkHiddenFieldsExclusions(form, hiddenFieldType) { + const formAction = typeof(form.action) == 'string' ? form.action : ''; + // Ajax Search Lite + if (Boolean(form.querySelector('fieldset.asl_sett_scroll'))) { + return true; + } + // Super WooCommerce Product Filter + if (form.classList.contains('swpf-instant-filtering')) { + return true; + } + // PayU 3-rd party service forms + if (formAction.indexOf('secure.payu.com') !== -1 ) { + return true; + } + + if (formAction.indexOf('hsforms') !== -1 ) { + return true; + } + + if (formAction.indexOf('secureinternetbank.com') !== -1 ) { + return true; + } + + if (typeof (hiddenFieldType) === 'string' && + ['visible_fields', 'no_cookie'].indexOf(hiddenFieldType) !== -1) { + const exclusions = getHiddenFieldExclusionsType(form); + return exclusions[hiddenFieldType] === 1; + } + + return false; +} + +/** + * Get type of the field should be excluded. Return exclusion signs via object. + * @param {object} form Form dom object. + * @return {object} {'no_cookie': 1|0, 'visible_fields': 1|0} + */ +function getHiddenFieldExclusionsType(form) { + // visible fields + let result = {'no_cookie': 0, 'visible_fields': 0}; + if ( + +ctPublic.data__visible_fields_required === 0 || + (form.method.toString().toLowerCase() === 'get' && + form.querySelectorAll('.nf-form-content').length === 0 && + form.id !== 'twt_cc_signup') || + form.classList.contains('slp_search_form') || // StoreLocatorPlus form + form.parentElement.classList.contains('mec-booking') || + form.action.toString().indexOf('activehosted.com') !== -1 || // Active Campaign + (form.id && form.id === 'caspioform') || // Caspio Form + (form.classList && form.classList.contains('tinkoffPayRow')) || // TinkoffPayForm + (form.classList && form.classList.contains('give-form')) || // GiveWP + (form.id && form.id === 'ult-forgot-password-form') || // ult forgot password + (form.id && form.id.toString().indexOf('calculatedfields') !== -1) || // CalculatedFieldsForm + (form.id && form.id.toString().indexOf('sac-form') !== -1) || // Simple Ajax Chat + (form.id && + form.id.toString().indexOf('cp_tslotsbooking_pform') !== -1) || // WP Time Slots Booking Form + (form.name && + form.name.toString().indexOf('cp_tslotsbooking_pform') !== -1) || // WP Time Slots Booking Form + form.action.toString() === 'https://epayment.epymtservice.com/epay.jhtml' || // Custom form + (form.name && form.name.toString().indexOf('tribe-bar-form') !== -1) || // The Events Calendar + (form.id && form.id === 'ihf-login-form') || // Optima Express login + (form.id && + form.id === 'subscriberForm' && + form.action.toString().indexOf('actionType=update') !== -1) || // Optima Express update + (form.id && form.id === 'ihf-main-search-form') || // Optima Express search + (form.id && form.id === 'frmCalc') || // nobletitle-calc + form.action.toString().indexOf('property-organizer-delete-saved-search-submit') !== -1 || + form.querySelector('a[name="login"]') !== null // digimember login form + ) { + result.visible_fields = 1; + } + + // ajax search pro exclusion + let ncFieldExclusionsSign = form.parentNode; + if ( + ncFieldExclusionsSign && ncFieldExclusionsSign.classList.contains('proinput') || + (form.name === 'options' && form.classList.contains('asp-fss-flex')) + ) { + result.no_cookie = 1; + } + + // woocommerce login form + if ( + form && form.classList.contains('woocommerce-form-login') + ) { + result.visible_fields = 1; + result.no_cookie = 1; + } + + // WordPress login form (wp-login.php is excluded from spam check in PHP) + if ( + (form.id && form.id === 'loginform') || + form.action.toString().indexOf('wp-login.php') !== -1 + ) { + result.visible_fields = 1; + result.no_cookie = 1; + } + + return result; +} + +/** + * Construct hidden field for no cookie + * @param {string} type + * @return {HTMLInputElement} + */ +function constructNoCookieHiddenField(type) { + let inputType = 'hidden'; + if (type === 'submit') { + inputType = 'submit'; + } + let field = ''; + + let noCookieData = getCleanTalkStorageDataArray(); + noCookieData = JSON.stringify(noCookieData); + noCookieData = '_ct_no_cookie_data_' + btoa(unescape(encodeURIComponent(noCookieData))); + field = document.createElement('input'); + field.setAttribute('name', 'ct_no_cookie_hidden_field'); + field.setAttribute('value', noCookieData); + field.setAttribute('type', inputType); + field.classList.add('apbct_special_field'); + field.classList.add('ct_no_cookie_hidden_field'); + return field; +} + +/** + * Retrieves the clentalk "cookie" data from starages. + * Contains {...noCookieDataLocal, ...noCookieDataSession, ...noCookieDataTypo, ...noCookieDataFromUserActivity}. + * @return {string} + */ +function getCleanTalkStorageDataArray() { // eslint-disable-line no-unused-vars + let noCookieDataLocal = apbctLocalStorage.getCleanTalkData(); + let noCookieDataSession = apbctSessionStorage.getCleanTalkData(); + + let noCookieDataTypo = {typo: []}; + if (document.ctTypoData && document.ctTypoData.data) { + noCookieDataTypo = {typo: document.ctTypoData.data}; + } + + let noCookieDataFromUserActivity = {collecting_user_activity_data: []}; + + if (document.ctCollectingUserActivityData) { + let collectingUserActivityData = JSON.parse(JSON.stringify(document.ctCollectingUserActivityData)); + noCookieDataFromUserActivity = {collecting_user_activity_data: collectingUserActivityData}; + } + + let browserStateData = {}; + if (typeof apbctGetBrowserStatePair === 'function') { + const browserState = apbctGetBrowserStatePair(); + if (browserState) { + browserStateData[browserState.key] = browserState.value; + } + } + + return { + ...noCookieDataLocal, + ...noCookieDataSession, + ...noCookieDataTypo, + ...noCookieDataFromUserActivity, + ...browserStateData, + }; +} + +/** + * Get the browser state as a key/value pair to attach it to an intercepted request. + * @return {{key: string, value: string}|false} False if there is nothing to attach. + */ +function apbctGetBrowserStatePair() { // eslint-disable-line no-unused-vars + try { + ApbctBrowserState.detectScripts(); + let state = ApbctBrowserState.asDTO(); + if ( ApbctBrowserState.botdLogicLoaded ) { + const transportEnabled = localStorage.getItem(ApbctBrowserState.TRANSPORT_ENABLED_SIGN_KEY) === '1'; + if (transportEnabled) { + state.frontend_data_log = ApbctBrowserState.getFrontendDataLog(); + } else { + state.transport_enabled = 0; + } + } else { + state.frontend_data_log = ApbctBrowserState.getFrontendDataLog(); + } + return {key: ApbctBrowserState.STATE_KEY, value: JSON.stringify(state)}; + } catch (e) { + return false; + } +} diff --git a/js/new_src/functions/storeParams.js b/js/new_src/functions/storeParams.js new file mode 100644 index 000000000..665428bba --- /dev/null +++ b/js/new_src/functions/storeParams.js @@ -0,0 +1,127 @@ +import {apbctLocalStorage} from '../utils/apbctLocalStorage'; +import {sendAJAX, sendREST} from './ajaxHandlers'; +import {ctNoCookieAttachHiddenFieldsToForms} from './noCookieHiddenField'; + +const PARAMS_TO_FORCE_ALT = [ + 'ct_sfw_pass_key', + 'ct_sfw_passed', + 'apbct_antibot', + 'apbct_anticrawler_passed', + 'apbct_bot_detector_exist', + 'apbct_antiflood_passed', + 'apbct_email_encoder_passed', +]; + +const PARAMS_SKIP_ALT = [ + 'ct_pointer_data' +] + +/** + * @param {array} params + */ +export function storeParams(params) { + if (ctPublicFunctions.data__cookies_type === 'alternative') { + return ctSetAltCookies(params); + } + params.forEach( function(param) { + const paramName = param[0]; + const paramValue = param[1]; + + if (PARAMS_TO_FORCE_ALT.includes(paramName)) { + ctSetAltCookies([param]); + return; + } + + if (ctPublicFunctions.data__cookies_type === 'native') { + ctSetCookie(paramName, paramValue); + } + + if (ctPublicFunctions.data__cookies_type === 'none') { + ctSetNoCookie(paramName, paramValue); + } + }); +} + +export function ctSetCookie(name, value, expires = '') { + const _expires = typeof expires !== 'undefined' ? 'expires=' + expires + '; ' : ''; + const _secure = location.protocol === 'https:' ? '; secure' : ''; + let _cookieName = name; + if ( ctPublicFunctions.cookiePrefix ) { + _cookieName = ctPublicFunctions.cookiePrefix + name; + } + document.cookie = + _cookieName + '=' + encodeURIComponent(value) + '; ' + + _expires + + 'path=/; ' + + 'samesite=lax' + + _secure; +} + +/** + * @param {array} params + */ +export function ctSetAltCookies(params) { + let filteredParams = params.filter(([name]) => !PARAMS_SKIP_ALT.includes(name)); + + // if cookies is array, convert it to object + if (Array.isArray(filteredParams) && filteredParams[0] && filteredParams[0][0] === 'apbct_bot_detector_exist') { + filteredParams = {apbct_bot_detector_exist: filteredParams[0][1]}; + } + // Only try to parse if cookies is a string (JSON) + if (typeof filteredParams === 'string') { + try { + filteredParams = JSON.parse(filteredParams); + } catch (e) { + console.log('APBCT ERROR: JSON parse error:' + e); + return; + } + } + + const callback = params && params.callback || null; + const onErrorCallback = params && params.onErrorCallback || null; + + if ( params && params.forceAltCookies ) { + filteredParams.apbct_force_alt_cookies = true; + } + + // Using REST API handler + if ( ctPublicFunctions.data__ajax_type === 'rest' ) { + // fix for url encoded cookie apbct_pixel_url on REST route + if (typeof cookies.apbct_pixel_url === 'string' && + cookies.apbct_pixel_url.indexOf('%3A') !== -1 + ) { + cookies.apbct_pixel_url = decodeURIComponent(cookies.apbct_pixel_url); + } + sendREST( + 'alt_sessions', + { + method: 'POST', + data: {cookies: filteredParams}, + callback: callback, + onErrorCallback: onErrorCallback, + }, + ); + + // Using AJAX request and handler + } else if ( ctPublicFunctions.data__ajax_type === 'admin_ajax' ) { + sendAJAX( + { + action: 'apbct_alt_session__save__AJAX', + cookies: filteredParams, + }, + { + notJson: 1, + callback: callback, + onErrorCallback: onErrorCallback, + beforeSend: function(xhr) { + xhr.setRequestHeader('X-Robots-Tag', 'noindex, nofollow'); + }, + }, + ); + } +} + +export function ctSetNoCookie(name, value) { + apbctLocalStorage.set(name, value); + ctNoCookieAttachHiddenFieldsToForms(); +} diff --git a/js/new_src/initParams.js b/js/new_src/initParams.js new file mode 100644 index 000000000..379432c02 --- /dev/null +++ b/js/new_src/initParams.js @@ -0,0 +1,16 @@ +import {storeParams} from './functions/storeParams'; +import {PARAM_NAME as CHECK_JS_PARAM_NAME, initCheckJs} from './params/checkJs'; +import {PARAM_NAME as PAGE_SET_TIMESTAMP_PARAM_NAME, initPageSetTimestamp} from './params/pageSetTimestamp'; +import {PARAM_NAME as TIMEZONE_PARAM_NAME, initTimezone} from "./params/timezone"; +import {PARAM_NAME as HEADLESS_PARAM_NAME, initHeadless} from "./params/headless"; + +export function initParams() { + const initParams = [ + [CHECK_JS_PARAM_NAME, initCheckJs()], + [PAGE_SET_TIMESTAMP_PARAM_NAME, initPageSetTimestamp()], + [TIMEZONE_PARAM_NAME, initTimezone()], + [HEADLESS_PARAM_NAME, initHeadless()], + ]; + + storeParams(initParams); +} diff --git a/js/new_src/params/checkJs.js b/js/new_src/params/checkJs.js new file mode 100644 index 000000000..2cfb5a064 --- /dev/null +++ b/js/new_src/params/checkJs.js @@ -0,0 +1,17 @@ +export const PARAM_NAME = 'ct_checkjs'; + +export function initCheckJs() { + if (typeof ctPublic.ct_checkjs_key !== 'undefined' && ctPublic.ct_checkjs_key !== null) { + return ctPublic.ct_checkjs_key; + } + return 0; +} + +export function setInputValue(result) { + if ( document.querySelectorAll('[name^=ct_checkjs]').length > 0 ) { + let elements = document.querySelectorAll('[name^=ct_checkjs]'); + for ( let i = 0; i < elements.length; i++ ) { + elements[i].value = result.js_key; + } + } +} diff --git a/js/new_src/params/headless.js b/js/new_src/params/headless.js new file mode 100644 index 000000000..3d64aa5b8 --- /dev/null +++ b/js/new_src/params/headless.js @@ -0,0 +1,5 @@ +export const PARAM_NAME = 'apbct_headless'; + +export function initHeadless() { + return navigator.webdriver; +} diff --git a/js/new_src/params/pageSetTimestamp.js b/js/new_src/params/pageSetTimestamp.js new file mode 100644 index 000000000..0f2a486f9 --- /dev/null +++ b/js/new_src/params/pageSetTimestamp.js @@ -0,0 +1,5 @@ +export const PARAM_NAME = 'ct_ps_timestamp'; + +export function initPageSetTimestamp() { + return Math.floor(new Date().getTime() / 1000); +} diff --git a/js/new_src/params/timezone.js b/js/new_src/params/timezone.js new file mode 100644 index 000000000..8cfd10d46 --- /dev/null +++ b/js/new_src/params/timezone.js @@ -0,0 +1,6 @@ +export const PARAM_NAME = 'ct_timezone'; + +export function initTimezone() { + const ctDate = new Date(); + return ctDate.getTimezoneOffset()/60*(-1); +} diff --git a/js/new_src/utils/apbctLocalStorage.js b/js/new_src/utils/apbctLocalStorage.js new file mode 100644 index 000000000..4cb596610 --- /dev/null +++ b/js/new_src/utils/apbctLocalStorage.js @@ -0,0 +1,61 @@ +export const apbctLocalStorage = { + get: function(key, property) { + if ( typeof property === 'undefined' ) { + property = 'value'; + } + const storageValue = localStorage.getItem(key); + if ( storageValue !== null ) { + try { + const json = JSON.parse(storageValue); + if ( json.hasOwnProperty(property) ) { + try { + const parsed = JSON.parse( json[property] ); + if ( parsed !== null && typeof parsed === 'object' ) { + return json[property].toString(); + } + return parsed; + } catch (e) { + return json[property].toString(); + } + } else { + return json; + } + } catch (e) { + return storageValue; + } + } + return false; + }, + set: function(key, value, isJson = true) { + if (isJson) { + let objToSave = {'value': JSON.stringify(value), 'timestamp': Math.floor(new Date().getTime() / 1000)}; + localStorage.setItem(key, JSON.stringify(objToSave)); + } else { + localStorage.setItem(key, value); + } + }, + isAlive: function(key, maxLifetime) { + if ( typeof maxLifetime === 'undefined' ) { + maxLifetime = 86400; + } + const keyTimestamp = this.get(key, 'timestamp'); + return keyTimestamp + maxLifetime > Math.floor(new Date().getTime() / 1000); + }, + isSet: function(key) { + return localStorage.getItem(key) !== null; + }, + delete: function(key) { + localStorage.removeItem(key); + }, + getCleanTalkData: function() { + let data = {}; + for (let i=0; iPHP transport and goes + * to the moderate request as sender_info.bot_detector_frontend_data_log. + */ +export class ApbctBrowserState { + static STATE_KEY = 'apbct_browser_state'; + static LOG_KEY = 'ct_bot_detector_frontend_data_log'; + static SCRIPT_SIGNS = { + botd_wrapper_loaded: 'ct-bot-detector-wrapper', + botd_logic_loaded: 'ct-bot-detector.min', + }; + /** + * This LS key is set on bot-detector side + * @type {string} + */ + static TRANSPORT_ENABLED_SIGN_KEY = 'bot_detector_log_transport_enabled'; + static botdWrapperLoaded = 0; + static botdLogicLoaded = 0; + + /** + * Get the current browser state as a JSON string ready to be transferred. + * @return {string} Empty string if the bot detector is disabled or on any collecting error. + */ + static getFrontendDataLog() { + const prefix = (typeof ctPublicFunctions !== 'undefined' && ctPublicFunctions.cookiePrefix) ? + ctPublicFunctions.cookiePrefix : + ''; + const logKey = prefix + ApbctBrowserState.LOG_KEY; + const noPrefixLogKey = ApbctBrowserState.LOG_KEY; + + if (typeof apbctLocalStorage !== 'undefined' && apbctLocalStorage.get) { + const logObject = apbctLocalStorage.get(logKey) || apbctLocalStorage.get(noPrefixLogKey) || null; + if (logObject && typeof logObject === 'string') { + try { + return JSON.parse(logObject); + } catch (e) { + return ''; + } + } + return logObject; + } + + let rawLog = localStorage.getItem(logKey); + if (!rawLog) { + rawLog = localStorage.getItem(noPrefixLogKey) || null; + } + + try { + return typeof rawLog === 'string' ? JSON.parse(rawLog) : rawLog; + } catch (e) { + return ''; + } + } + + /** + * + * @return {object} + */ + static asDTO() { + return { + botd_logic_loaded: ApbctBrowserState.botdLogicLoaded, + botd_wrapper_loaded: ApbctBrowserState.botdWrapperLoaded, + frontend_data_log: '', + transport_enabled: 1, + }; + } + + /** + * Look for the bot detector scripts in the page DOM. + * @return {boolean} True if both scripts are found. + */ + static detectScripts() { + if (ApbctBrowserState.botdWrapperLoaded && ApbctBrowserState.botdLogicLoaded) { + return true; + } + + const scripts = document.getElementsByTagName('script'); + + for (let i = 0; i < scripts.length; i++) { + const src = scripts[i].getAttribute('src'); + if (!src) { + continue; + } + if (src.indexOf(ApbctBrowserState.SCRIPT_SIGNS.botd_wrapper_loaded) !== -1) { + ApbctBrowserState.botdWrapperLoaded = 1; + } else if (src.indexOf(ApbctBrowserState.SCRIPT_SIGNS.botd_logic_loaded) !== -1) { + ApbctBrowserState.botdLogicLoaded = 1; + } + } + + // The bot detector logic sets this flag on its own start + return !!ApbctBrowserState.botdWrapperLoaded && !!ApbctBrowserState.botdLogicLoaded; + } +} + + diff --git a/js/prebuild/apbct-public-bundle.js b/js/prebuild/apbct-public-bundle.js index d49a18cf7..9ff2ad934 100644 --- a/js/prebuild/apbct-public-bundle.js +++ b/js/prebuild/apbct-public-bundle.js @@ -5867,29 +5867,7 @@ class ApbctBrowserState { } } -/** - * Get the browser state as a key/value pair to attach it to an intercepted request. - * @return {{key: string, value: string}|false} False if there is nothing to attach. - */ -function apbctGetBrowserStatePair() { // eslint-disable-line no-unused-vars - try { - ApbctBrowserState.detectScripts(); - let state = ApbctBrowserState.asDTO(); - if ( ApbctBrowserState.botdLogicLoaded ) { - const transportEnabled = localStorage.getItem(ApbctBrowserState.TRANSPORT_ENABLED_SIGN_KEY) === '1'; - if (transportEnabled) { - state.frontend_data_log = ApbctBrowserState.getFrontendDataLog(); - } else { - state.transport_enabled = 0; - } - } else { - state.frontend_data_log = ApbctBrowserState.getFrontendDataLog(); - } - return {key: ApbctBrowserState.STATE_KEY, value: JSON.stringify(state)}; - } catch (e) { - return false; - } -} + let ctCheckedEmails = {}; let ctCheckedEmailsExist = {}; diff --git a/js/src/public-0-core.js b/js/src/public-0-core.js index ac73d5327..0584285b4 100644 --- a/js/src/public-0-core.js +++ b/js/src/public-0-core.js @@ -576,41 +576,6 @@ class ApbctCore { } } -/** - * Select actual WP nonce depending on the ajax type and the fresh nonce provided. - * @return {string} url - */ -function selectActualNonce() { - let defaultNonce = ''; - // return fresh nonce immediately if persists - if ( - ctPublicFunctions.hasOwnProperty('_fresh_nonce') && - typeof ctPublicFunctions._fresh_nonce === 'string' && - ctPublicFunctions._fresh_nonce.length > 0 - ) { - return ctPublicFunctions._fresh_nonce; - } - // select from default rest/ajax nonces - if ( - ctPublicFunctions.data__ajax_type === 'admin_ajax' && - ctPublicFunctions.hasOwnProperty('_ajax_nonce') && - typeof ctPublicFunctions._ajax_nonce === 'string' && - ctPublicFunctions._ajax_nonce.length > 0 - ) { - defaultNonce = ctPublicFunctions._ajax_nonce; - } - if ( - ctPublicFunctions.data__ajax_type === 'rest' && - ctPublicFunctions.hasOwnProperty('_rest_nonce') && - typeof ctPublicFunctions._rest_nonce === 'string' && - ctPublicFunctions._rest_nonce.length > 0 - ) { - defaultNonce = ctPublicFunctions._rest_nonce; - } - - return defaultNonce; -} - /** * Enter point to ApbctCore class * @@ -622,449 +587,3 @@ function apbct(params) { return new ApbctCore() .select(params); } - -/** - * ApbctXhr - */ -class ApbctXhr { - xhr = new XMLHttpRequest(); - - // Base parameters - method = 'POST'; // HTTP-request type - url = ''; // URL to send the request - async = true; - user = null; // HTTP-authorization username - password = null; // HTTP-authorization password - data = {}; // Data to send - - // Optional params - button = null; // Button that should be disabled when request is performing - spinner = null; // Spinner that should appear when request is in process - progressbar = null; // Progress bar for the current request - context = this; // Context - callback = null; - onErrorCallback = null; - - responseType = 'json'; // Expected data type from server - headers = {}; - timeout = 15000; // Request timeout in milliseconds - - methods_to_convert_data_to_URL = [ - 'GET', - 'HEAD', - ]; - - body = null; - http_code = 0; - status_text = ''; - - // eslint-disable-next-line require-jsdoc - constructor(parameters) { - // Set class properties - for ( let key in parameters ) { - if ( typeof this[key] !== 'undefined' ) { - this[key] = parameters[key]; - } - } - - // Modifying DOM-elements - this.prepare(); - - // Modify URL with data for GET and HEAD requests - if ( Object.keys(this.data).length ) { - this.deleteDoubleJSONEncoding(this.data); - this.convertData(); - } - - if ( ! this.url ) { - console.log('%cXHR%c not URL provided', - 'color: red; font-weight: bold;', 'color: grey; font-weight: normal;'); - return false; - } - - // Configure the request - this.xhr.open(this.method, this.url, this.async, this.user, this.password); - this.setHeaders(); - - this.xhr.responseType = this.responseType; - this.xhr.timeout = this.timeout; - - /* EVENTS */ - // Monitoring status - this.xhr.onreadystatechange = function() { - if (this.isWpNonceError()) { - this.getFreshNonceAndRerunXHR(parameters); - return; - } - this.onReadyStateChange(); - }.bind(this); - - // Run callback - this.xhr.onload = function() { - this.onLoad(); - }.bind(this); - - // On progress - this.xhr.onprogress = function(event) { - this.onProgress(event); - }.bind(this); - - // On error - this.xhr.onerror = function() { - this.onError(); - }.bind(this); - - this.xhr.ontimeout = function() { - this.onTimeout(); - }.bind(this); - - // Send the request - this.xhr.send(this.body); - } - - /** - * prepare - */ - prepare() { - // Disable button - if (this.button) { - this.button.setAttribute('disabled', 'disabled'); - this.button.style.cursor = 'not-allowed'; - } - - // Enable spinner - if (this.spinner) { - this.spinner.style.display = 'inline'; - } - } - - /** - * complete - */ - complete() { - this.http_code = this.xhr.status; - this.status_text = this.xhr.statusText; - - // Disable button - if (this.button) { - this.button.removeAttribute('disabled'); - this.button.style.cursor = 'auto'; - } - - // Enable spinner - if (this.spinner) { - this.spinner.style.display = 'none'; - } - - if ( this.progressbar ) { - this.progressbar.fadeOut('slow'); - } - } - - /** - * onReadyStateChange - */ - onReadyStateChange() { - if (this.on_ready_state_change !== null && typeof this.on_ready_state_change === 'function') { - this.on_ready_state_change(); - } - } - - /** - * @param {object} event - */ - onProgress(event) { - if (this.on_progress !== null && typeof this.on_progress === 'function') { - this.on_progress(); - } - } - - /** - * onError - */ - onError() { - console.log('error'); - - this.complete(); - this.error( - this.http_code, - this.status_text, - ); - - if (this.onErrorCallback !== null && typeof this.onErrorCallback === 'function') { - this.onErrorCallback(this.status_text); - } - } - - /** - * onTimeout - */ - onTimeout() { - this.complete(); - this.error( - 0, - 'timeout', - ); - - if (this.onErrorCallback !== null && typeof this.onErrorCallback === 'function') { - this.onErrorCallback('Timeout'); - } - } - - /** - * @return {boolean} - */ - onLoad() { - this.complete(); - - if (this.responseType === 'json' ) { - if (this.xhr.response === null) { - this.error(this.http_code, this.status_text, 'No response'); - return false; - } else if ( typeof this.xhr.response.error !== 'undefined') { - this.error(this.http_code, this.status_text, this.xhr.response.error); - return false; - } - } - - if (this.callback !== null && typeof this.callback === 'function') { - this.callback.call(this.context, this.xhr.response, this.data); - } - } - - /** - * Check if 403 code of WP nonce error - * @return {bool} - */ - isWpNonceError() { - let restErrror = false; - let ajaxErrror = false; - // check rest error - if (this.xhr.readyState == 4) { - restErrror = ( - typeof this.xhr.response === 'object' && this.xhr.response !== null && - this.xhr.response.hasOwnProperty('data') && - this.xhr.response.data.hasOwnProperty('status') && - this.xhr.response.data.status === 403 - ); - ajaxErrror = this.xhr.response === '-1' && this.xhr.status === 403; - } - // todo check AJAX error - return restErrror || ajaxErrror; - } - - /** - * Get the fresh nonce and rerun the initial XHR with params - * @param {[]} initialRequestParams - */ - getFreshNonceAndRerunXHR(initialRequestParams) { - let noncePrev = ''; - - // Check if initialRequestParams['headers']['X-WP-Nonce'] exists. - if ( - initialRequestParams.hasOwnProperty('headers') && - initialRequestParams.headers.hasOwnProperty('X-WP-Nonce') - ) { - noncePrev = initialRequestParams['headers']['X-WP-Nonce']; - } - - // Check if initialRequestParams['data']['_ajax_nonce'] exists. - if ( - initialRequestParams.hasOwnProperty('data') && - initialRequestParams.data.hasOwnProperty('_ajax_nonce') - ) { - noncePrev = initialRequestParams['data']['_ajax_nonce']; - } - - // Nonce is not provided. Exit. - if ( noncePrev === '' ) { - return; - } - - // prepare params for refreshing nonce - let params = {}; - params.method = 'POST'; - params.data = { - 'spbc_remote_call_action': 'get_fresh_wpnonce', - 'plugin_name': 'antispam', - 'nonce_prev': noncePrev, - 'initial_request_params': initialRequestParams, - }; - params.notJson = true; - params.url = ctPublicFunctions.host_url; - // this callback will rerun the XHR with initial params - params.callback = function(...args) { - // the refresh result itself - let freshNonceResult = args[0]; - let newRequestParams = false; - // provided initial params - if (args[1] !== undefined && args[1].hasOwnProperty('initial_request_params')) { - newRequestParams = args[1].initial_request_params; - } - if (newRequestParams && freshNonceResult.hasOwnProperty('wpnonce')) { - ctPublicFunctions._fresh_nonce = freshNonceResult.wpnonce; - if (ctPublicFunctions.data__ajax_type === 'rest') { - new ApbctCore().rest(newRequestParams); - } else { - new ApbctCore().ajax(newRequestParams); - } - } - }; - // run the nonce refreshing call - new ApbctXhr(params); - } - - /** - * @param {number} httpCode - * @param {string} statusText - * @param {string} additionalMsg - */ - error(httpCode, statusText, additionalMsg) { - let errorString = ''; - - if ( statusText === 'timeout' ) { - errorString += 'Server response timeout'; - } else if ( httpCode === 200 ) { - if ( statusText === 'parsererror' ) { - errorString += 'Unexpected response from server. See console for details.'; - } else { - errorString += 'Unexpected error. Status: ' + statusText + '.'; - if ( typeof additionalMsg !== 'undefined' ) { - errorString += ' Additional error info: ' + additionalMsg; - } - } - } else if (httpCode === 500) { - errorString += 'Internal server error.'; - } else { - errorString += 'Unexpected response code:' + httpCode; - } - - this.errorOutput( errorString ); - - if (this.onErrorCallback !== null && typeof this.onErrorCallback === 'function') { - this.onErrorCallback(this.status_text); - } - } - - /** - * @param {string} errorMsg - */ - errorOutput(errorMsg) { - console.log( '%c ctXHR error: %c' + errorMsg, 'color: red;', 'color: grey;' ); - } - - /** - * setHeaders - */ - setHeaders() { - // Set headers if passed - for ( let headerName in this.headers ) { - if ( typeof this.headers[headerName] !== 'undefined' ) { - this.xhr.setRequestHeader(headerName, this.headers[headerName]); - } - } - } - - /** - * @return {string|*} - */ - convertData() { - // GET, HEAD request-type - if ( ~this.methods_to_convert_data_to_URL.indexOf( this.method ) ) { - return this.convertDataToURL(); - - // POST request-type - } else { - return this.convertDataToBody(); - } - } - - /** - * @return {string} - */ - convertDataToURL() { - let paramsAppendix = new URLSearchParams(this.data).toString(); - let paramsPrefix = this.url.match(/^(https?:\/{2})?[a-z0-9.]+\?/) ? '&' : '?'; - this.url += paramsPrefix + paramsAppendix; - - return this.url; - } - - /** - * @return {null} - */ - convertDataToBody() { - this.body = new FormData(); - for (let dataKey in this.data) { - if (Object.hasOwn(this.data, dataKey)) { - this.body.append( - dataKey, - typeof this.data[dataKey] === 'object' ? - JSON.stringify(this.data[dataKey]) : - this.data[dataKey], - ); - } - } - - return this.body; - } - - /** - * Recursive - * - * Recursively decode JSON-encoded properties - * - * @param {object} object - * @return {*} - */ - deleteDoubleJSONEncoding(object) { - if ( typeof object === 'object') { - for (let objectKey in object) { - if (Object.hasOwn(object, objectKey)) { - // Recursion - if ( typeof object[objectKey] === 'object') { - object[objectKey] = this.deleteDoubleJSONEncoding(object[objectKey]); - } - - // Common case (out) - if ( - typeof object[objectKey] === 'string' && - object[objectKey].match(/^[\[{].*?[\]}]$/) !== null // is like JSON - ) { - let parsedValue = JSON.parse(object[objectKey]); - if ( typeof parsedValue === 'object' ) { - object[objectKey] = parsedValue; - } - } - } - } - } - - return object; - } -} -// eslint-disable-next-line require-jsdoc -class ApbctAjax extends ApbctXhr { - // eslint-disable-next-line require-jsdoc - constructor(...args) { - args = args[0]; - args.data._ajax_nonce = selectActualNonce(); - super(args); - } -} -// eslint-disable-next-line require-jsdoc -class ApbctRest extends ApbctXhr { - static default_route = ctPublicFunctions._rest_url + 'cleantalk-antispam/v1/'; - route = ''; - - // eslint-disable-next-line require-jsdoc - constructor(...args) { - args = args[0]; - const nonce = selectActualNonce(); - args.url = ApbctRest.default_route + args.route; - args.headers = { - 'X-WP-Nonce': nonce, - }; - super(args); - } -} diff --git a/js/src/public-1-functions.js b/js/src/public-1-functions.js index e32ba7998..073399aaf 100644 --- a/js/src/public-1-functions.js +++ b/js/src/public-1-functions.js @@ -11,10 +11,7 @@ function initParams(gatheringLoaded) { ) ? new ApbctGatheringData().getScreenInfo() : ''; const initCookies = [ ['ct_ps_timestamp', Math.floor(new Date().getTime() / 1000)], - ['ct_fkp_timestamp', '0'], - ['ct_pointer_data', '0'], ['ct_timezone', ctDate.getTimezoneOffset()/60*(-1)], - ['ct_screen_info', screenInfo], ['apbct_headless', headless], ]; @@ -75,14 +72,11 @@ function initParams(gatheringLoaded) { } } - if (apbctLocalStorage.isSet('ct_checkjs')) { - initCookies.push(['ct_checkjs', apbctLocalStorage.get('ct_checkjs')]); - } else { - initCookies.push(['ct_checkjs', 0]); - } - if (gatheringLoaded) { initCookies.push(['ct_gathering_loaded', gatheringLoaded]); + initCookies.push(['ct_fkp_timestamp', '0']); + initCookies.push(['ct_pointer_data', '0']); + initCookies.push(['ct_screen_info', screenInfo]); } ctSetCookie(initCookies); @@ -355,130 +349,6 @@ function removeDoubleJsonEncoding(object) { // eslint-disable-line no-unused-var return object; } -/** - * @return {boolean|*} - */ -function ctGetPageForms() { // eslint-disable-line no-unused-vars - let forms = document.forms; - if (forms) { - return forms; - } - return false; -} - -// eslint-disable-next-line camelcase,require-jsdoc,no-unused-vars -function apbct_js_keys__set_input_value(result, data, params, obj) { - if ( document.querySelectorAll('[name^=ct_checkjs]').length > 0 ) { - let elements = document.querySelectorAll('[name^=ct_checkjs]'); - for ( let i = 0; i < elements.length; i++ ) { - elements[i].value = result.js_key; - } - } -} - -let apbctLocalStorage = { - get: function(key, property) { - if ( typeof property === 'undefined' ) { - property = 'value'; - } - const storageValue = localStorage.getItem(key); - if ( storageValue !== null ) { - try { - const json = JSON.parse(storageValue); - if ( json.hasOwnProperty(property) ) { - try { - const parsed = JSON.parse( json[property] ); - if ( parsed !== null && typeof parsed === 'object' ) { - return json[property].toString(); - } - return parsed; - } catch (e) { - return json[property].toString(); - } - } else { - return json; - } - } catch (e) { - return storageValue; - } - } - return false; - }, - set: function(key, value, isJson = true) { - if (isJson) { - let objToSave = {'value': JSON.stringify(value), 'timestamp': Math.floor(new Date().getTime() / 1000)}; - localStorage.setItem(key, JSON.stringify(objToSave)); - } else { - localStorage.setItem(key, value); - } - }, - isAlive: function(key, maxLifetime) { - if ( typeof maxLifetime === 'undefined' ) { - maxLifetime = 86400; - } - const keyTimestamp = this.get(key, 'timestamp'); - return keyTimestamp + maxLifetime > Math.floor(new Date().getTime() / 1000); - }, - isSet: function(key) { - return localStorage.getItem(key) !== null; - }, - delete: function(key) { - localStorage.removeItem(key); - }, - getCleanTalkData: function() { - let data = {}; - for (let i=0; i