diff --git a/CHANGELOG.md b/CHANGELOG.md index 8f8f185..ffc053f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +## 23.12.4 + +* Enhanced userAgentData detection for bot filtering + ## 23.12.3 * Added bot detection for workers diff --git a/cypress/e2e/user_agent.cy.js b/cypress/e2e/user_agent.cy.js index 5f6a9b9..999b7af 100644 --- a/cypress/e2e/user_agent.cy.js +++ b/cypress/e2e/user_agent.cy.js @@ -1,6 +1,7 @@ /* eslint-disable cypress/no-unnecessary-waiting */ /* eslint-disable require-jsdoc */ var Countly = require("../../Countly.js"); +var Utils = require("../../modules/Utils.js"); var hp = require("../support/helper"); function initMain() { @@ -55,11 +56,19 @@ describe("User Agent tests ", () => { hp.haltAndClearStorage(() => { initMain(); // setting ua value to strings that can pass the regex test + expect(Countly._internals.userAgentSearchBotDetection("")).to.equal(false); expect(Countly._internals.userAgentSearchBotDetection("123")).to.equal(false); expect(Countly._internals.userAgentSearchBotDetection("Googlebot")).to.equal(true); expect(Countly._internals.userAgentSearchBotDetection("Google")).to.equal(false); expect(Countly._internals.userAgentSearchBotDetection("HeadlessChrome")).to.equal(true); expect(Countly._internals.userAgentSearchBotDetection("Chrome-Lighthouse")).to.equal(true); + expect(Countly._internals.userAgentSearchBotDetection("Lighthouse")).to.equal(true); + }); + }); + // userAgentData is not supported by all browsers yet so it is hard to test with consistency + it("Check if currentUserAgentDataString override works", () => { + hp.haltAndClearStorage(() => { + expect(Utils.currentUserAgentDataString('123')).to.equal("123"); }); }); }); diff --git a/modules/Constants.js b/modules/Constants.js index f8514b2..08cb5e4 100644 --- a/modules/Constants.js +++ b/modules/Constants.js @@ -104,7 +104,7 @@ var healthCheckCounterEnum = Object.freeze({ errorMessage: "cly_hc_error_message", }); -var SDK_VERSION = "23.12.3"; +var SDK_VERSION = "23.12.4"; var SDK_NAME = "javascript_native_web"; // Using this on document.referrer would return an array with 15 elements in it. The 12th element (array[11]) would be the path we are looking for. Others would be things like password and such (use https://regex101.com/ to check more) diff --git a/modules/CountlyClass.js b/modules/CountlyClass.js index 29f63a7..2d56f9d 100644 --- a/modules/CountlyClass.js +++ b/modules/CountlyClass.js @@ -19,6 +19,7 @@ import { add_event_listener, get_event_target, currentUserAgentString, + currentUserAgentDataString, userAgentDeviceDetection, userAgentSearchBotDetection, get_page_coord, @@ -4624,6 +4625,7 @@ class CountlyClass { processScrollView: processScrollView, processScroll: processScroll, currentUserAgentString: currentUserAgentString, + currentUserAgentDataString: currentUserAgentDataString, userAgentDeviceDetection: userAgentDeviceDetection, userAgentSearchBotDetection: userAgentSearchBotDetection, getRequestQueue: getRequestQueue, diff --git a/modules/Utils.js b/modules/Utils.js index 1e43adc..80cae76 100644 --- a/modules/Utils.js +++ b/modules/Utils.js @@ -319,23 +319,39 @@ function currentUserAgentString(uaOverride) { } var ua_raw = navigator.userAgent; - // check if userAgentData is supported and userAgent is not available, use it + // check if userAgentData is supported and userAgent is not available, then use it if (!ua_raw) { - if (navigator.userAgentData) { - // turn brands array into string - ua_raw = navigator.userAgentData.brands.map(function (e) { - return e.brand + ":" + e.version; - }).join(); - // add mobile info - ua_raw += (navigator.userAgentData.mobile ? " mobi " : " "); - // add platform info - ua_raw += navigator.userAgentData.platform; - } + ua_raw = currentUserAgentDataString(); } // RAW USER AGENT STRING return ua_raw; } +/** + * Forms user agent string from userAgentData by concatenating brand, version, mobile and platform + * @memberof Countly._internals + * @param {string} uaOverride - a string value to pass instead of ua value + * @returns {string} currentUserAgentString - user agent string from userAgentData + */ +function currentUserAgentDataString(uaOverride) { + if (uaOverride) { + return uaOverride; + } + + var ua = ""; + if (navigator.userAgentData) { + // turn brands array into string + ua = navigator.userAgentData.brands.map(function (e) { + return e.brand + ":" + e.version; + }).join(); + // add mobile info + ua += (navigator.userAgentData.mobile ? " mobi " : " "); + // add platform info + ua += navigator.userAgentData.platform; + } + return ua; +} + /** * Returns device type information according to user agent string * @memberof Countly._internals @@ -348,7 +364,7 @@ function userAgentDeviceDetection(uaOverride) { if (uaOverride) { userAgent = uaOverride; } - else if (navigator.userAgentData.mobile) { + else if (navigator.userAgentData && navigator.userAgentData.mobile) { return "phone"; } else { @@ -384,9 +400,18 @@ function userAgentDeviceDetection(uaOverride) { */ function userAgentSearchBotDetection(uaOverride) { // search bot regexp - var searchBotRE = /(CountlySiteBot|nuhk|Googlebot|GoogleSecurityScanner|Yammybot|Openbot|Slurp|MSNBot|Ask Jeeves\/Teoma|ia_archiver|bingbot|Google Web Preview|Mediapartners-Google|AdsBot-Google|Baiduspider|Ezooms|YahooSeeker|AltaVista|AVSearch|Mercator|Scooter|InfoSeek|Ultraseek|Lycos|Wget|YandexBot|Yandex|YaDirectFetcher|SiteBot|Exabot|AhrefsBot|MJ12bot|TurnitinBot|magpie-crawler|Nutch Crawler|CMS Crawler|rogerbot|Domnutch|ssearch_bot|XoviBot|netseer|digincore|fr-crawler|wesee|AliasIO|contxbot|PingdomBot|BingPreview|HeadlessChrome|Chrome-Lighthouse)/; - // true if the user agent string contains a search bot string pattern - return searchBotRE.test(uaOverride || currentUserAgentString()); + const searchBotRE = /(CountlySiteBot|nuhk|Googlebot|GoogleSecurityScanner|Yammybot|Openbot|Slurp|MSNBot|Ask Jeeves\/Teoma|ia_archiver|bingbot|Google Web Preview|Mediapartners-Google|AdsBot-Google|Baiduspider|Ezooms|YahooSeeker|AltaVista|AVSearch|Mercator|Scooter|InfoSeek|Ultraseek|Lycos|Wget|YandexBot|Yandex|YaDirectFetcher|SiteBot|Exabot|AhrefsBot|MJ12bot|TurnitinBot|magpie-crawler|Nutch Crawler|CMS Crawler|rogerbot|Domnutch|ssearch_bot|XoviBot|netseer|digincore|fr-crawler|wesee|AliasIO|contxbot|PingdomBot|BingPreview|HeadlessChrome|Lighthouse)/; + + // check override first + if (uaOverride) { + return searchBotRE.test(uaOverride); + } + + // check both userAgent and userAgentData, as one of them might be containing the information we are looking for + const ua_bot = searchBotRE.test(currentUserAgentString()); + const uaData_bot = searchBotRE.test(currentUserAgentDataString()); + + return ua_bot || uaData_bot; } /** @@ -614,5 +639,6 @@ export { loadCSS, showLoader, checkIfLoggingIsOn, - hideLoader + hideLoader, + currentUserAgentDataString }; \ No newline at end of file diff --git a/package.json b/package.json index 4ec9deb..0105d8c 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "countly-sdk-js", - "version": "23.12.3", + "version": "23.12.4", "description": "Countly JavaScript SDK", "type": "module", "main": "Countly.js",