From acf2d1afb5edfa1ce572688ca6b1e749b9d9b7fd Mon Sep 17 00:00:00 2001 From: "NullDev (Shadow)" Date: Mon, 13 Nov 2023 05:35:57 +0100 Subject: [PATCH] added basic fingerprinting --- web/src/challange/challanges.js | 32 ++++++++++++++++- web/src/challange/fingerprinting.js | 55 +++++++++++++++++++++++++++++ 2 files changed, 86 insertions(+), 1 deletion(-) create mode 100644 web/src/challange/fingerprinting.js diff --git a/web/src/challange/challanges.js b/web/src/challange/challanges.js index fc1cf31..2f2d7c3 100644 --- a/web/src/challange/challanges.js +++ b/web/src/challange/challanges.js @@ -1,9 +1,15 @@ +import Fingerprinting from "./fingerprinting"; + /** * Collection of challenges. * * @class Challenges */ -class Challenges { +class Challenges extends Fingerprinting { + constructor(){ + super(); + } + /** * Calculate native hash. * @@ -18,6 +24,20 @@ class Challenges { return hashArray.map(b => b.toString(16).padStart(2, "0")).join(""); } + /** + * Send failed fingerprinting to server. + * + * @param {string} reason + * @return {Promise} + * @memberof Challenger + */ + async #sendFingerprintingResult(reason){ + fetch("/cdn-cgi/challenge-platform/challenge", { + method: "POST", + body: reason, + }); + } + /** * Challenge POW. * @@ -51,6 +71,16 @@ class Challenges { * @memberof Challenger */ async challengeFingerprinting(){ + const usualUa = this.isUsualBrowserBasedOnUa(); + if (!usualUa) return await this.#sendFingerprintingResult("ua"); + + const notHeadless = this.isNotHeadless(); + if (!notHeadless) return await this.#sendFingerprintingResult("headless"); + + const canvasSupported = this.isCanvasSupported(); + if (!canvasSupported) return await this.#sendFingerprintingResult("canvas"); + + return await this.#sendFingerprintingResult("ok"); } /** diff --git a/web/src/challange/fingerprinting.js b/web/src/challange/fingerprinting.js new file mode 100644 index 0000000..544d232 --- /dev/null +++ b/web/src/challange/fingerprinting.js @@ -0,0 +1,55 @@ +/** + * Browser based fingerprinting + * + * @class Fingerprinting + */ +class Fingerprinting { + /** + * Check user agent string for usual browsers. + * + * @return {boolean} + * @memberof Fingerprinting + */ + isUsualBrowserBasedOnUa(){ + const ua = navigator.userAgent; + const isUsualBrowser = ua.includes("Chrome") + || ua.includes("Firefox") + || ua.includes("Safari") + || ua.includes("Edge") + || ua.includes("Opera") + || ua.includes("OPR") + || ua.includes("MSIE") + || ua.includes("Trident"); + return isUsualBrowser; + } + + /** + * Check if browser is headless. + * + * @return {boolean} + * @memberof Fingerprinting + */ + isNotHeadless(){ + const isHeadless = !!navigator.webdriver // @ts-ignore + || !!window.chrome + || !!navigator.languages + || navigator.userAgent.toLowerCase().includes("headless"); + return !isHeadless; + } + + /** + * Check if canvas is supported. + * + * @return {boolean} + * @memberof Fingerprinting + */ + isCanvasSupported(){ + const canvas = document.createElement("canvas"); + const gl = canvas.getContext("webgl") || canvas.getContext("experimental-webgl"); + return !!gl; + } + + // more to come +} + +export default Fingerprinting;