diff --git a/package.json b/package.json index 5f3eed80..dfcfb730 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "aesirx-lib", - "version": "2.0.2", + "version": "2.0.3", "license": "GPL-3.0-only", "author": "AesirX", "repository": "https://github.com/aesirxio/aesirx-lib", @@ -13,6 +13,7 @@ "date-fns": "^2.30.0", "date-fns-tz": "^2.0.0", "moment": "^2.29.4", + "murmurhash-js": "^1.0.0", "query-string": "7", "react-secure-storage": "^1.2.2" }, @@ -45,7 +46,8 @@ "prettier": "^2.8.8", "ts-jest": "^29.1.1", "tsup": "^6.7.0", - "typescript": "^5.0.4" + "typescript": "^5.0.4", + "@types/murmurhash-js": "^1.0.3" }, "files": [ "dist" diff --git a/src/Authentication/Authentication.ts b/src/Authentication/Authentication.ts index 83064b64..5f064164 100644 --- a/src/Authentication/Authentication.ts +++ b/src/Authentication/Authentication.ts @@ -171,12 +171,15 @@ class AesirxAuthenticationApiService { let tokenType = ''; let accessToken = ''; let refreshToken = ''; + let jwt = ''; if (tokenRefreshResponse && tokenRefreshResponse.data) { tokenType = tokenRefreshResponse.data.token_type ?? 'Bearer'; accessToken = tokenRefreshResponse.data.access_token ?? ''; authorizationHeader = authorizationHeader.concat(tokenType).concat(' ').concat(accessToken); refreshToken = tokenRefreshResponse.data[AUTHORIZATION_KEY.REFRESH_TOKEN] ?? ''; + jwt = tokenRefreshResponse.data[AUTHORIZATION_KEY.JWT] ?? ''; + const isJwtChange = jwt !== this.getStore(AUTHORIZATION_KEY.JWT); if (process.env.NODE_ENV === 'test') { return tokenRefreshResponse.data; } else { @@ -185,8 +188,10 @@ class AesirxAuthenticationApiService { [key[AUTHORIZATION_KEY.TOKEN_TYPE]]: tokenType, [key[AUTHORIZATION_KEY.AUTHORIZED_TOKEN_HEADER]]: authorizationHeader, [key[AUTHORIZATION_KEY.REFRESH_TOKEN]]: refreshToken, + [key[AUTHORIZATION_KEY.JWT]]: jwt, }; this.setStore(setStore); + process.env.REACT_APP_HEADER_JWT === 'true' && isJwtChange && location.reload(); } } else { return logout(); diff --git a/src/Authentication/Logout.ts b/src/Authentication/Logout.ts index 36bd4a1b..2a2abce2 100644 --- a/src/Authentication/Logout.ts +++ b/src/Authentication/Logout.ts @@ -9,7 +9,7 @@ const logout = () => { return 'logout'; } else { localStorage.clear(); - window.location.reload(); + typeof window !== 'undefined' && window.location.reload(); } }; diff --git a/src/Bi/Bi.ts b/src/Bi/Bi.ts index 7119b684..7c48eda2 100644 --- a/src/Bi/Bi.ts +++ b/src/Bi/Bi.ts @@ -6,6 +6,9 @@ import { BrowsersModel, CitiesModel, + ConsentsDateModel, + ConsentsListModel, + ConsentsTierModel, CountriesModel, DevicesModel, DomainModel, @@ -14,6 +17,7 @@ import { LanguagesModel, MetricsModel, PagesModel, + RefererModel, SummaryModel, VisitorModel, VisitorsModel, @@ -502,6 +506,99 @@ class AesirxBiApiService { } else throw error; } }; + getConsentsList = async (dataFilter: any, dateFilter: any) => { + try { + const data = await this.route.getConsentsList(dataFilter, dateFilter); + + let results = null; + let pagination = null; + if (data) { + results = new ConsentsListModel(data); + pagination = results.getBiPagination(); + } + if (results) { + results = results.toJSON(); + } + return { + list: results, + pagination: pagination, + }; + } catch (error) { + if (axios.isCancel(error)) { + return { message: 'isCancle' }; + } else throw error; + } + }; + getConsentsDate = async (dataFilter: any, dateFilter: any) => { + try { + const data = await this.route.getConsentsDate(dataFilter, dateFilter); + + let results = null; + let pagination = null; + if (data) { + results = new ConsentsDateModel(data); + pagination = results.getBiPagination(); + } + if (results) { + results = results.toJSON(); + } + return { + list: results, + pagination: pagination, + }; + } catch (error) { + if (axios.isCancel(error)) { + return { message: 'isCancle' }; + } else throw error; + } + }; + getConsentsTier = async (dataFilter: any, dateFilter: any) => { + try { + const data = await this.route.getConsentsTier(dataFilter, dateFilter); + + let results = null; + let pagination = null; + if (data) { + results = new ConsentsTierModel(data); + pagination = results.getBiPagination(); + } + if (results) { + results = results.toJSON(); + } + return { + list: results, + pagination: pagination, + }; + } catch (error) { + if (axios.isCancel(error)) { + return { message: 'isCancle' }; + } else throw error; + } + }; + + getReferer = async (dataFilter: any, dateFilter: any) => { + try { + const data = await this.route.getReferer(dataFilter, dateFilter); + + let results = null; + let pagination = null; + if (data) { + results = new RefererModel(data); + pagination = results.getBiPagination(); + } + if (results) { + results = results.toJSON(); + } + return { + list: results, + pagination: pagination, + }; + } catch (error) { + if (axios.isCancel(error)) { + return { message: 'isCancle' }; + } else throw error; + } + }; } export { AesirxBiApiService }; diff --git a/src/Bi/BiModel.ts b/src/Bi/BiModel.ts index cf0b94bb..0ccc26d4 100644 --- a/src/Bi/BiModel.ts +++ b/src/Bi/BiModel.ts @@ -22,6 +22,10 @@ import { BI_WOOCOMMERCE_PRODUCT_CHART_FIELD_KEY, BI_WOOCOMMERCE_STATISTIC_CHART_FIELD_KEY, BI_WOOCOMMERCE_STATISTIC_FIELD_KEY, + BI_CONSENTS_LIST_FIELD_KEY, + BI_CONSENTS_DATE_FIELD_KEY, + BI_CONSENTS_TIER_FIELD_KEY, + BI_REFERER_FIELD_KEY, } from '../Constant/BiConstant'; import BaseModel from '../Abstract/BaseModel'; @@ -833,6 +837,157 @@ class WoocommerceProductItemModel extends BaseItemModel { }; } +class ConsentsListModel extends BaseModel { + items: any = null; + constructor(entities: any) { + super(entities); + if (entities) { + this.items = entities.collection.map((element: any) => { + return new ConsentsListItemModel(element); + }); + this.items.pagination = this.getBiPagination(); + } + } +} +class ConsentsListItemModel extends BaseItemModel { + consent: any = null; + tier: any = null; + datetime: any = null; + expiration: any = null; + uuid: any = null; + wallet: any = null; + web3id: any = null; + constructor(entity: any) { + super(entity); + if (entity) { + this.consent = entity[BI_CONSENTS_LIST_FIELD_KEY.CONSENT] ?? ''; + this.tier = entity[BI_CONSENTS_LIST_FIELD_KEY.TIER] ?? ''; + this.datetime = entity[BI_CONSENTS_LIST_FIELD_KEY.DATETIME] ?? ''; + this.expiration = entity[BI_CONSENTS_LIST_FIELD_KEY.EXPIRATION] ?? ''; + this.uuid = entity[BI_CONSENTS_LIST_FIELD_KEY.UUID] ?? ''; + this.wallet = entity[BI_CONSENTS_LIST_FIELD_KEY.WALLET] ?? ''; + this.web3id = entity[BI_CONSENTS_LIST_FIELD_KEY.WEB3ID] ?? ''; + } + } + toObject = () => { + return {}; + }; + toJSON = () => { + return { + ...this.baseToJSON(), + [BI_CONSENTS_LIST_FIELD_KEY.CONSENT]: this.consent, + [BI_CONSENTS_LIST_FIELD_KEY.TIER]: this.tier, + [BI_CONSENTS_LIST_FIELD_KEY.DATETIME]: this.datetime, + [BI_CONSENTS_LIST_FIELD_KEY.EXPIRATION]: this.expiration, + [BI_CONSENTS_LIST_FIELD_KEY.UUID]: this.uuid, + [BI_CONSENTS_LIST_FIELD_KEY.WALLET]: this.wallet, + [BI_CONSENTS_LIST_FIELD_KEY.WEB3ID]: this.web3id, + }; + }; +} + +class ConsentsDateModel extends BaseModel { + items: any = null; + constructor(entities: any) { + super(entities); + if (entities) { + this.items = entities.collection.map((element: any) => { + return new ConsentsDateItemModel(element); + }); + this.items.pagination = this.getBiPagination(); + } + } +} +class ConsentsDateItemModel extends BaseItemModel { + date: any = null; + total: any = null; + constructor(entity: any) { + super(entity); + if (entity) { + this.date = entity[BI_CONSENTS_DATE_FIELD_KEY.DATE] ?? ''; + this.total = entity[BI_CONSENTS_DATE_FIELD_KEY.TOTAL] ?? ''; + } + } + toObject = () => { + return {}; + }; + toJSON = () => { + return { + ...this.baseToJSON(), + [BI_CONSENTS_DATE_FIELD_KEY.DATE]: this.date, + [BI_CONSENTS_DATE_FIELD_KEY.TOTAL]: this.total, + }; + }; +} + +class ConsentsTierModel extends BaseModel { + items: any = null; + constructor(entities: any) { + super(entities); + if (entities) { + this.items = entities.collection.map((element: any) => { + return new ConsentsTierItemModel(element); + }); + this.items.pagination = this.getBiPagination(); + } + } +} +class ConsentsTierItemModel extends BaseItemModel { + tier: any = null; + total: any = null; + constructor(entity: any) { + super(entity); + if (entity) { + this.tier = entity[BI_CONSENTS_TIER_FIELD_KEY.TIER] ?? ''; + this.total = entity[BI_CONSENTS_TIER_FIELD_KEY.TOTAL] ?? ''; + } + } + toObject = () => { + return {}; + }; + toJSON = () => { + return { + ...this.baseToJSON(), + [BI_CONSENTS_TIER_FIELD_KEY.TIER]: this.tier, + [BI_CONSENTS_TIER_FIELD_KEY.TOTAL]: this.total, + }; + }; +} + +class RefererModel extends BaseModel { + items: any = null; + constructor(entities: any) { + super(entities); + if (entities) { + this.items = entities.collection.map((element: any) => { + return new RefererItemModel(element); + }); + this.items.pagination = this.getBiPagination(); + } + } +} +class RefererItemModel extends BaseItemModel { + number_of_visitors: any = null; + referer: any = null; + constructor(entity: any) { + super(entity); + if (entity) { + this.number_of_visitors = entity[BI_SUMMARY_FIELD_KEY.NUMBER_OF_VISITORS] ?? ''; + this.referer = entity[BI_REFERER_FIELD_KEY.REFERER] ?? ''; + } + } + toObject = () => { + return {}; + }; + toJSON = () => { + return { + ...this.baseToJSON(), + [BI_SUMMARY_FIELD_KEY.NUMBER_OF_VISITORS]: this.number_of_visitors, + [BI_REFERER_FIELD_KEY.REFERER]: this.referer, + }; + }; +} + export { DomainModel, VisitorsModel, @@ -854,4 +1009,8 @@ export { WoocommerceStatisticChartModel, WoocommerceProductModel, WoocommerceProductChartModel, + ConsentsListModel, + ConsentsDateModel, + ConsentsTierModel, + RefererModel, }; diff --git a/src/Bi/BiRoute.ts b/src/Bi/BiRoute.ts index 0b9940b0..750e8d8f 100644 --- a/src/Bi/BiRoute.ts +++ b/src/Bi/BiRoute.ts @@ -289,6 +289,64 @@ class BiRoute extends BaseRoute { ); }; + getConsentsList = (dataFilter: any, dateFilter: any) => { + return AesirXApiInstance.get( + this.createRequestURL( + { + url: 'consents' + version, + filter: dataFilter, + date: dateFilter, + }, + false, + process.env.REACT_APP_BI_ENDPOINT_URL, + true + ) + ); + }; + + getConsentsDate = (dataFilter: any, dateFilter: any) => { + return AesirXApiInstance.get( + this.createRequestURL( + { + url: 'consents' + version, + filter: dataFilter, + date: dateFilter, + }, + false, + process.env.REACT_APP_BI_ENDPOINT_URL, + true + ) + ); + }; + + getConsentsTier = (dataFilter: any, dateFilter: any) => { + return AesirXApiInstance.get( + this.createRequestURL( + { + url: 'consents' + version + dateFilter?.date_start + '/' + dateFilter?.date_end + '/tier', + filter: dataFilter, + }, + false, + process.env.REACT_APP_BI_ENDPOINT_URL, + true + ) + ); + }; + + getReferer = (dataFilter: any, dateFilter: any) => { + return AesirXApiInstance.get( + this.createRequestURL( + { + url: 'referrers' + version + dateFilter?.date_start + '/' + dateFilter?.date_end, + filter: dataFilter, + }, + false, + process.env.REACT_APP_BI_ENDPOINT_URL, + true + ) + ); + }; + init = () => { return AesirXApiInstance.post( this.createRequestURL( diff --git a/src/Constant/BiConstant.ts b/src/Constant/BiConstant.ts index 8612a4e6..e17df5e5 100644 --- a/src/Constant/BiConstant.ts +++ b/src/Constant/BiConstant.ts @@ -151,6 +151,30 @@ const BI_WOOCOMMERCE_STATISTIC_CHART_FIELD_KEY = { TOTAL_REVENUE: 'total_revenue', }; +const BI_CONSENTS_LIST_FIELD_KEY = { + CONSENT: 'consent', + DATETIME: 'datetime', + EXPIRATION: 'expiration', + TIER: 'tier', + UUID: 'uuid', + WALLET: 'wallet', + WEB3ID: 'web3id', +}; + +const BI_CONSENTS_DATE_FIELD_KEY = { + DATE: 'date', + TOTAL: 'total', +}; + +const BI_CONSENTS_TIER_FIELD_KEY = { + TIER: 'tier', + TOTAL: 'total', +}; + +const BI_REFERER_FIELD_KEY = { + REFERER: 'referer', +}; + export { BI_DASHBOARD_FIELD_KEY, BI_WIDGET_FIELD_KEY, @@ -173,4 +197,8 @@ export { BI_WOOCOMMERCE_PRODUCT_CHART_FIELD_KEY, BI_WOOCOMMERCE_STATISTIC_FIELD_KEY, BI_WOOCOMMERCE_STATISTIC_CHART_FIELD_KEY, + BI_CONSENTS_LIST_FIELD_KEY, + BI_CONSENTS_DATE_FIELD_KEY, + BI_CONSENTS_TIER_FIELD_KEY, + BI_REFERER_FIELD_KEY, }; diff --git a/src/Constant/Constant.ts b/src/Constant/Constant.ts index 50284917..1301705b 100644 --- a/src/Constant/Constant.ts +++ b/src/Constant/Constant.ts @@ -52,7 +52,10 @@ const AXIOS_CONFIGS: any = { DAM_LICENSE: env.REACT_APP_DAM_LICENSE || '', DMA_LICENSE: env.REACT_APP_DMA_LICENSE || '', TEST_MODE: env.REACT_APP_TEST_MODE || '', - DOMAIN: process.env.NODE_ENV === 'test' ? env.REACT_APP_TEST_DOMAIN : window?.location?.hostname, + DOMAIN: + process.env.NODE_ENV === 'test' + ? env.REACT_APP_TEST_DOMAIN + : typeof window !== 'undefined' && window?.location?.hostname, }; const GENERAL_CONFIG = { diff --git a/src/Constant/MemberConstant.ts b/src/Constant/MemberConstant.ts index 2c6d38ae..ed1c5d7f 100644 --- a/src/Constant/MemberConstant.ts +++ b/src/Constant/MemberConstant.ts @@ -29,6 +29,7 @@ const MEMBER_FIELD_KEY = { ORGANIZATION: 'organization', FIRST_NAME: 'first_name', LAST_NAME: 'sur_name', + CHATGPT_API_KEY: 'chatgpt_api_key', }; const MEMBER_GET_FIELD_KEY = { diff --git a/src/Gateway/Instance.ts b/src/Gateway/Instance.ts index 00108a27..76f99d3b 100644 --- a/src/Gateway/Instance.ts +++ b/src/Gateway/Instance.ts @@ -47,6 +47,7 @@ const refreshToken = (failedRequest: any) => { [AUTHORIZATION_KEY.TOKEN_TYPE]: [AUTHORIZATION_KEY.TOKEN_TYPE], [AUTHORIZATION_KEY.AUTHORIZED_TOKEN_HEADER]: [AUTHORIZATION_KEY.AUTHORIZED_TOKEN_HEADER], [AUTHORIZATION_KEY.REFRESH_TOKEN]: [AUTHORIZATION_KEY.REFRESH_TOKEN], + [AUTHORIZATION_KEY.JWT]: [AUTHORIZATION_KEY.JWT], }; const request = new AesirxAuthenticationApiService(); diff --git a/src/Member/MemberModel.ts b/src/Member/MemberModel.ts index 83796a3f..084f3444 100644 --- a/src/Member/MemberModel.ts +++ b/src/Member/MemberModel.ts @@ -71,6 +71,7 @@ class MemberItemModel { [MEMBER_FIELD_KEY.AVATAR_DAM]: data[MEMBER_FIELD_KEY.AVATAR_DAM] ?? '', [MEMBER_FIELD_KEY.ORGANIZATION]: data[MEMBER_FIELD_KEY.ORGANIZATION] ?? '', [MEMBER_FIELD_KEY.DESCRIPTION]: data[MEMBER_FIELD_KEY.DESCRIPTION] ?? '', + [MEMBER_FIELD_KEY.CHATGPT_API_KEY]: data[MEMBER_FIELD_KEY.CHATGPT_API_KEY] ?? '', }; }; diff --git a/src/env.ts b/src/env.ts index 63306d7e..9776bfaa 100644 --- a/src/env.ts +++ b/src/env.ts @@ -1,2 +1,10 @@ -const s: any = process.env.NODE_ENV === 'test' ? [] : window; +declare global { + interface Window { + process: any; + } +} +if (typeof window !== 'undefined') { + window.process = { env: '' }; +} +const s: any = process.env.NODE_ENV === 'test' ? [] : typeof window !== 'undefined' && window; export const env = { ...process.env, ...s['env'] }; diff --git a/src/index.ts b/src/index.ts index c79035d7..070bfd11 100644 --- a/src/index.ts +++ b/src/index.ts @@ -129,3 +129,4 @@ export * from './Utils/Date'; export * from './Utils/Storage'; export * from './env'; +export { default as getFingerprint } from './lib/fingerprint'; diff --git a/src/lib/envHelper.ts b/src/lib/envHelper.ts new file mode 100644 index 00000000..bc655db1 --- /dev/null +++ b/src/lib/envHelper.ts @@ -0,0 +1,68 @@ +// const SUPPORTED_PREFIX = ['', 'REACT_APP_', 'NEXT_PUBLIC_', 'VITE_']; + +/** + * Function to get SECURE_LOCAL_STORAGE_HASH_KEY + * @returns + */ +const getHashKey = () => { + let value: string | null | undefined = null; + try { + if (typeof process.env != 'undefined') { + value = + process.env.SECURE_LOCAL_STORAGE_HASH_KEY || + process.env.REACT_APP_SECURE_LOCAL_STORAGE_HASH_KEY || + process.env.NEXT_PUBLIC_SECURE_LOCAL_STORAGE_HASH_KEY || + process.env.VITE_SECURE_LOCAL_STORAGE_HASH_KEY; + } + } catch (ex) { + return null; + } + return value; +}; + +/** + * Function to get SECURE_LOCAL_STORAGE_PREFIX + * @returns + */ +const getStoragePrefix = () => { + let value: string | null | undefined = null; + try { + if (typeof process.env != 'undefined') { + value = + process.env.SECURE_LOCAL_STORAGE_PREFIX || + process.env.REACT_APP_SECURE_LOCAL_STORAGE_PREFIX || + process.env.NEXT_PUBLIC_SECURE_LOCAL_STORAGE_PREFIX || + process.env.VITE_SECURE_LOCAL_STORAGE_PREFIX; + } + } catch (ex) { + return null; + } + return value; +}; +/** + * Function to get SECURE_LOCAL_STORAGE_DISABLED_KEYS + * @returns + */ +const getDisabledKeys = () => { + let value: string | null | undefined = null; + try { + if (typeof process.env != 'undefined') { + value = + process.env.SECURE_LOCAL_STORAGE_DISABLED_KEYS || + process.env.REACT_APP_SECURE_LOCAL_STORAGE_DISABLED_KEYS || + process.env.NEXT_PUBLIC_SECURE_LOCAL_STORAGE_DISABLED_KEYS || + process.env.VITE_SECURE_LOCAL_STORAGE_DISABLED_KEYS; + } + } catch (ex) { + return null; + } + return value; +}; + +const envHelper = { + getHashKey, + getStoragePrefix, + getDisabledKeys, +}; + +export default envHelper; diff --git a/src/lib/fingerpint.lib.ts b/src/lib/fingerpint.lib.ts new file mode 100644 index 00000000..86386a59 --- /dev/null +++ b/src/lib/fingerpint.lib.ts @@ -0,0 +1,240 @@ +import murmurhash3_32_gc from 'murmurhash-js/murmurhash3_gc'; +import { FINGERPRINT_KEYS, getDisabledKeys } from './utils'; + +// ClientJS prototype which contains all methods. +const ClientJS = class { + // + // MAIN METHODS + // + + // Get Fingerprint. Return a 32-bit integer representing the browsers fingerprint. + getFingerprint() { + const bar = '|'; + + const disabledKeys = getDisabledKeys(); + let key = ''; + if (!disabledKeys.includes(FINGERPRINT_KEYS.USERAGENT)) { + key += navigator.userAgent + bar; + } + if (!disabledKeys.includes(FINGERPRINT_KEYS.HOSTNAME)) { + key += window.location.hostname + bar; + } + if (!disabledKeys.includes(FINGERPRINT_KEYS.SCREEN_PRINT)) { + key += this.getScreenPrint() + bar; + } + if (!disabledKeys.includes(FINGERPRINT_KEYS.PLUGINS)) { + key += this.getPlugins() + bar; + } + if (!disabledKeys.includes(FINGERPRINT_KEYS.FONTS)) { + key += this.getFonts() + bar; + } + if (!disabledKeys.includes(FINGERPRINT_KEYS.LOCAL_STORAGE)) { + key += this.isLocalStorage() + bar; + } + if (!disabledKeys.includes(FINGERPRINT_KEYS.SESSION_STORAGE)) { + key += this.isSessionStorage() + bar; + } + if (!disabledKeys.includes(FINGERPRINT_KEYS.TIMEZONE)) { + key += this.getTimeZone() + bar; + } + if (!disabledKeys.includes(FINGERPRINT_KEYS.LANGUAGE)) { + key += this.getLanguage() + bar; + } + if (!disabledKeys.includes(FINGERPRINT_KEYS.SYSTEM_LANGUAGE)) { + key += this.getSystemLanguage() + bar; + } + if (!disabledKeys.includes(FINGERPRINT_KEYS.COOKIE)) { + key += this.isCookie() + bar; + } + if (!disabledKeys.includes(FINGERPRINT_KEYS.CANVAS)) { + key += this.getCanvasPrint(); + } + if (key.endsWith(bar)) key = key.substring(0, key.length - 1); + const seed = 256; + + return murmurhash3_32_gc(key, seed); + } + + // + // SCREEN METHODS + // + + // Get Screen Print. Return a string containing screen information. + getScreenPrint() { + // "Current Resolution: " + this.getCurrentResolution() +", Available Resolution: " + this.getAvailableResolution() + + return ( + 'Color Depth: ' + + this.getColorDepth() + + ', Device XDPI: ' + + this.getDeviceXDPI() + + ', Device YDPI: ' + + this.getDeviceYDPI() + ); + } + + // Get Color Depth. Return a string containing the color depth. + getColorDepth() { + return window.screen.colorDepth; + } + + // Get Current Resolution. Return a string containing the current resolution. + getCurrentResolution() { + return window.screen.width + 'x' + window.screen.height; + } + + // Get Available Resolution. Return a string containing the available resolution. + getAvailableResolution() { + return window.screen.availWidth + 'x' + window.screen.availHeight; + } + + // Get Device XPDI. Return a string containing the device XPDI. + getDeviceXDPI() { + // return window.screen.deviceXDPI; + return ''; + } + + // Get Device YDPI. Return a string containing the device YDPI. + getDeviceYDPI() { + // return window.screen.deviceYDPI; + return ''; + } + + // + // PLUGIN METHODS + // + + // Get Plugins. Return a string containing a list of installed plugins. + getPlugins() { + let pluginsList = ''; + + for (let i = 0; i < navigator.plugins.length; i++) { + if (i === navigator.plugins.length - 1) { + pluginsList += navigator.plugins[i].name; + } else { + pluginsList += navigator.plugins[i].name + ', '; + } + } + return pluginsList; + } + + // + // FONT METHODS + // + + // Get Fonts. Return a string containing a list of installed fonts. + getFonts() { + const fontString = ''; + + // TODO: Need to enable this code + // for (let i = 0; i < fontArray.length; i++) { + // if (fontDetective.detect(fontArray[i])) { + // if (i == fontArray.length - 1) { + // fontString += fontArray[i]; + // } else { + // fontString += fontArray[i] + ", "; + // } + // } + // } + + return fontString; + } + + // + // STORAGE METHODS + // + + // Is Local Storage. Check if local storage is enabled. + isLocalStorage() { + try { + return !!localStorage; + } catch (e) { + return true; // SecurityError when referencing it means it exists + } + } + + // Is Session Storage. Check if session storage is enabled. + isSessionStorage() { + try { + return !!sessionStorage; + } catch (e) { + return true; // SecurityError when referencing it means it exists + } + } + + // Is Cookie. Check if cookies are enabled. + isCookie() { + return navigator.cookieEnabled; + } + + // + // TIME METHODS + // + + // Get Time Zone. Return a string containing the time zone. + getTimeZone() { + const rightNow = new Date(); + let myNumber: any, formattedNumber, result; + myNumber = String(-(rightNow.getTimezoneOffset() / 60)); + if (myNumber < 0) { + myNumber = myNumber * -1; + formattedNumber = ('0' + myNumber).slice(-2); + result = '-' + formattedNumber; + } else { + formattedNumber = ('0' + myNumber).slice(-2); + result = '+' + formattedNumber; + } + return result; + } + + // + // LANGUAGE METHODS + // + + // Get Language. Return a string containing the user language. + getLanguage() { + return navigator.language; + } + + // Get System Language. Return a string containing the system language. + getSystemLanguage() { + return navigator.language || window.navigator.language; + } + + // Get Canvas Print. Return a string containing the canvas URI data. + getCanvasPrint() { + // create a canvas element + const canvas = document.createElement('canvas'); + + // define a context let that will be used for browsers with canvas support + let ctx: any; + + // try/catch for older browsers that don't support the canvas element + try { + // attempt to give ctx a 2d canvas context value + ctx = canvas.getContext('2d'); + } catch (e) { + // return empty string if canvas element not supported + return ''; + } + + // https://www.browserleaks.com/canvas#how-does-it-work + // Text with lowercase/uppercase/punctuation symbols + const txt = 'ClientJS,org 1.0'; + ctx.textBaseline = 'top'; + // The most common type + ctx.font = "14px 'Arial'"; + ctx.textBaseline = 'alphabetic'; + ctx.fillStyle = '#f60'; + ctx.fillRect(125, 1, 62, 20); + // Some tricks for color mixing to increase the difference in rendering + ctx.fillStyle = '#069'; + ctx.fillText(txt, 2, 15); + ctx.fillStyle = 'rgba(102, 204, 0, 0.7)'; + ctx.fillText(txt, 4, 17); + return canvas.toDataURL(); + } +}; + +const clientJS = new ClientJS(); + +export default clientJS; diff --git a/src/lib/fingerprint.ts b/src/lib/fingerprint.ts new file mode 100644 index 00000000..74cdda8a --- /dev/null +++ b/src/lib/fingerprint.ts @@ -0,0 +1,18 @@ +/* eslint-disable no-undef */ +import envHelper from './envHelper'; +import clientJS from './fingerpint.lib'; + +const HASH_KEY = 'E86E2612010258B35137'; + +/** + * Function to get browser finger print + * @returns + */ +const getFingerprint = () => { + const HASH_KEY_CUSTOM = envHelper.getHashKey() || HASH_KEY; + + if (typeof window === 'undefined') return HASH_KEY_CUSTOM; + return clientJS.getFingerprint() + HASH_KEY_CUSTOM; +}; + +export default getFingerprint; diff --git a/src/lib/utils.ts b/src/lib/utils.ts new file mode 100644 index 00000000..7eaabab0 --- /dev/null +++ b/src/lib/utils.ts @@ -0,0 +1,55 @@ +import envHelper from './envHelper'; + +/** + * Function which is used to get the secure prefix + * @returns + */ +export const getSecurePrefix = (): string => { + const KEY_PREFIX = envHelper.getStoragePrefix() || '@secure.'; + if (!KEY_PREFIX.endsWith('.')) return KEY_PREFIX + '.'; + return KEY_PREFIX; +}; + +export const FINGERPRINT_KEYS = { + USERAGENT: 'UserAgent', + SCREEN_PRINT: 'ScreenPrint', + PLUGINS: 'Plugins', + FONTS: 'Fonts', + LOCAL_STORAGE: 'LocalStorage', + SESSION_STORAGE: 'SessionStorage', + TIMEZONE: 'TimeZone', + LANGUAGE: 'Language', + SYSTEM_LANGUAGE: 'SystemLanguage', + COOKIE: 'Cookie', + CANVAS: 'Canvas', + HOSTNAME: 'Hostname', +}; + +/** + * Function which is used to get all the disabled keys + * @returns + */ +export const getDisabledKeys = (): string[] => { + const DISABLED_KEYS = envHelper.getDisabledKeys() || ''; + if (DISABLED_KEYS === '') return []; + + const allOptions = [ + FINGERPRINT_KEYS.USERAGENT, + FINGERPRINT_KEYS.SCREEN_PRINT, + FINGERPRINT_KEYS.PLUGINS, + FINGERPRINT_KEYS.FONTS, + FINGERPRINT_KEYS.LOCAL_STORAGE, + FINGERPRINT_KEYS.SESSION_STORAGE, + FINGERPRINT_KEYS.TIMEZONE, + FINGERPRINT_KEYS.LANGUAGE, + FINGERPRINT_KEYS.SYSTEM_LANGUAGE, + FINGERPRINT_KEYS.COOKIE, + FINGERPRINT_KEYS.CANVAS, + FINGERPRINT_KEYS.HOSTNAME, + ]; + const response: string[] = []; + DISABLED_KEYS.split('|').forEach((key) => { + if (allOptions.includes(key)) response.push(key); + }); + return response; +}; diff --git a/yarn.lock b/yarn.lock index fceccfbd..d7399558 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1755,6 +1755,11 @@ "@types/tough-cookie" "*" parse5 "^7.0.0" +"@types/murmurhash-js@^1.0.3": + version "1.0.6" + resolved "https://registry.yarnpkg.com/@types/murmurhash-js/-/murmurhash-js-1.0.6.tgz#1e7131c6ae041d0df272e5c5ff501ecb860dba3b" + integrity sha512-P2RRwRpevEKO0FrK5xNjxBywg0Br24tEv8K2+iWg56PtcCUNGAkaaOWKBQiUpofA8H/gmgdHXrcvSgp2uXCVAQ== + "@types/node@*": version "18.15.11" resolved "https://registry.yarnpkg.com/@types/node/-/node-18.15.11.tgz#b3b790f09cb1696cffcec605de025b088fa4225f"