diff --git a/.eslintrc.json b/.eslintrc.json deleted file mode 100644 index 96aa29a4d..000000000 --- a/.eslintrc.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "env": { - "browser": true, - "commonjs": true, - "es2021": true, - "node": true - }, - "parserOptions": { - "ecmaVersion": "latest" - }, - "rules": { - } -} diff --git a/package.json b/package.json index 1bff1d7f1..951a7f01d 100644 --- a/package.json +++ b/package.json @@ -182,7 +182,6 @@ "@babel/traverse": "7.15.4", "@jazzer.js/core": "^1.4.0", "@playwright/test": "~1.32.2", - "eslint": "^8.48.0", "jshint": "~2.13.6", "mocha": "~8.2.0", "requirejs": "2.3.2", @@ -219,10 +218,5 @@ "type": "github", "url": "https://github.com/sponsors/faisalman" } - ], - "workspaces": [ - "src/gpu-detect", - "src/ua-client-hints", - "src/user-agent-helpers" ] } diff --git a/script/build-module.js b/script/build-module.js index 2c0c4587d..f8079233c 100755 --- a/script/build-module.js +++ b/script/build-module.js @@ -46,24 +46,6 @@ const modules = [ dest : 'src/extensions/ua-parser-extensions.mjs', title : 'ua-parser-js/extensions', replacements : [] - }, - { - src : 'src/gpu-detect/gpu-detect.js', - dest : 'src/gpu-detect/gpu-detect.mjs', - title : '@ua-parser-js/gpu-detect', - replacements : [] - }, - { - src : 'src/user-agent-helpers/user-agent-helpers.js', - dest : 'src/user-agent-helpers/user-agent-helpers.mjs', - title : '@ua-parser-js/user-agent-helpers', - replacements : [] - }, - { - src : 'src/ua-client-hints/ua-client-hints.js', - dest : 'src/ua-client-hints/ua-client-hints.mjs', - title : '@ua-parser-js/ua-client-hints', - replacements : [] } ]; diff --git a/script/test-all.sh b/script/test-all.sh index c8b2ca29b..37cbd19bf 100755 --- a/script/test-all.sh +++ b/script/test-all.sh @@ -9,7 +9,7 @@ echo ' - lint js code ' npm run test:jshint || exit 1 -npm run test:eslint || exit 1 +#npm run test:eslint || exit 1 echo ' - test using mocha diff --git a/src/gpu-detect/gpu-detect.d.ts b/src/gpu-detect/gpu-detect.d.ts deleted file mode 100644 index bccc81b6c..000000000 --- a/src/gpu-detect/gpu-detect.d.ts +++ /dev/null @@ -1,3 +0,0 @@ -export class GPUDetect { - static getGPU: { vendor: string, model: string } -} \ No newline at end of file diff --git a/src/gpu-detect/gpu-detect.js b/src/gpu-detect/gpu-detect.js deleted file mode 100644 index 326dbcf43..000000000 --- a/src/gpu-detect/gpu-detect.js +++ /dev/null @@ -1,116 +0,0 @@ -////////////////////////////////////////////// -/* Extracts GPU information from user-agent - https://github.com/faisalman/ua-parser-js - Author: Faisal Salman - MIT License */ -///////////////////////////////////////////// - -/*jshint esversion: 11 */ - -const rendererMap = [ - [[ - /(intel).*\b(hd\sgraphics\s\d{4}|iris(?:\spro)|gma\s\w+)/i, // Intel - /(nvidia)\s(geforce\s(?:gtx?\s)\d\w+|quadro)/i, // NVIDIA - /\b(sis)\s(\w+)/i // SiS - ], ['vendor', 'model']], - - [[ - /\b(radeon[\shdr\d]+\w{4,5})/i // ATI/AMD - ], ['model', ['vendor', 'AMD']]], - - [[ - /(adreno\s(?:\(tm\)\s)\w+)/i // Qualcomm - ], [['model', /\(tm\)\s/i, ''], ['vendor', 'Qualcomm']]] -]; - -const vendorMap = [ - [[ - /\b(amd|apple|arm|ati|img|intel|nvidia|qualcomm|samsung|sis)\b/i - ], ['vendor']] -]; - -class RegexMap { - - static parse(str, mapper) { - let res = {}; - if (typeof str === 'string') { - for (const [regs, props] of mapper) { - if (!Array.isArray(regs)) { - throw new Error('RegexMap: Expect Array of RegExp'); - } - if (!Array.isArray(props)) { - throw new Error('RegexMap: Expect Array for Properties Mapping'); - } - for (const reg of regs) { - if (!reg instanceof RegExp) { - throw new Error('RegexMap: Expect RegExp Instance'); - } - const matches = reg.exec(str); - if (matches) { - props.forEach((prop, idx) => { - const val = matches[idx+1]; - if (Array.isArray(prop)) { - const key = prop[0]; - if (typeof key !== 'string') { - throw new Error('RegexMap: Expect String Input'); - } - if (prop.length == 2) { - if (typeof prop[1] === 'string') { - res[key] = prop[1]; - } else if (typeof prop[1] === 'function') { - res[key] = prop[1].call(res, val); - } - } else if (prop.length == 3) { - if (prop[1] instanceof RegExp) { - res[key] = val.replace(prop[1], prop[2]); - } else if (typeof prop[1] === 'function') { - res[key] = prop[1].call(res, val, prop[2]); - } - } else if (prop.length == 4) { - res[key] = prop[3].call(res, val.replace(prop[1], prop[2])); - } else { - res[key] = val; - } - } else if (typeof prop === 'string') { - res[prop] = val; - } - }); - if (res) return res; - } - } - } - } - return res; - }; -} - -class GPUDetect { - - static getGPU (strRenderer, strVendor) { - - let gpuInfo = { vendor : undefined, model : undefined }; - - if (typeof strRenderer !== 'string') { - if (globalThis.document) { - const canvas = document.createElement('canvas'); - const gl = canvas.getContext('webgl2') || - canvas.getContext('webgl') || - canvas.getContext('experimental-webgl'); - if (gl) { - const debugInfo = gl.getExtension('WEBGL_debug_renderer_info'); - strVendor = gl.getParameter(debugInfo?.UNMASKED_VENDOR_WEBGL); - strRenderer = gl.getParameter(debugInfo?.UNMASKED_RENDERER_WEBGL); - } - } - } - if (strRenderer || strVendor) { - ({ vendor : gpuInfo.vendor, model : gpuInfo.model } = RegexMap.parse(strRenderer, rendererMap)); - gpuInfo.vendor = gpuInfo.vendor ?? RegexMap.parse(strVendor, rendererMap)?.vendor ?? RegexMap.parse(strVendor, vendorMap)?.vendor; - } - return gpuInfo; - } -} - -module.exports = { - GPUDetect -} \ No newline at end of file diff --git a/src/gpu-detect/package.json b/src/gpu-detect/package.json deleted file mode 100644 index c3ffaf9f5..000000000 --- a/src/gpu-detect/package.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "title": "User-Agent GPU Info", - "name": "@ua-parser-js/gpu-detect", - "version": "0.0.1", - "author": "Faisal Salman ", - "description": "Extracts GPU information from user-agent", - "main": "gpu-detect.js", - "module": "gpu-detect.mjs", - "scripts": { - "test": "mocha ../../test/mocha-test-helpers" - }, - "repository": { - "type": "git", - "url": "git+https://github.com/faisalman/ua-parser-js.git" - }, - "keywords": [ - "ua-parser-js", - "gpu-detection" - ], - "license": "MIT", - "bugs": { - "url": "https://github.com/faisalman/ua-parser-js/issues" - }, - "homepage": "https://github.com/faisalman/ua-parser-js#readme" -} diff --git a/src/gpu-detect/readme.md b/src/gpu-detect/readme.md deleted file mode 100644 index 86b9fa45f..000000000 --- a/src/gpu-detect/readme.md +++ /dev/null @@ -1,16 +0,0 @@ -# @ua-parser-js/gpu-detect - -This is a [UAParser.js](https://github.com/faisalman/ua-parser-js) module that extracts GPU information from user-agent. - -```sh -npm i @ua-parser-js/gpu-detect -``` - -## Code Example - -// in browser environment -const { vendor, model } = GPUDetect.getGPU(); - -// in non-browser environment -const { vendor, model } = GPUDetect.getGPU("AMD Radeon"); -``` \ No newline at end of file diff --git a/src/gpu-detect/test/index.js b/src/gpu-detect/test/index.js deleted file mode 100644 index 76b7e7046..000000000 --- a/src/gpu-detect/test/index.js +++ /dev/null @@ -1,4 +0,0 @@ -const { GPUDetect } = require('../gpu-detect.js'); - -console.log(GPUDetect.getGPU('AMD Radeon R9 M295X OpenGL Engine')); -console.log(GPUDetect.getGPU('','ATI Technologies Inc.')); \ No newline at end of file diff --git a/src/ua-client-hints/package.json b/src/ua-client-hints/package.json deleted file mode 100644 index 9fdb8eaf7..000000000 --- a/src/ua-client-hints/package.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "title": "User-Agent Client Hints", - "name": "@ua-parser-js/ua-client-hints", - "version": "0.0.1", - "author": "Faisal Salman ", - "description": "A collection of utility methods for working with user-agent client hints", - "main": "ua-client-hints.js", - "module": "ua-client-hints.mjs", - "scripts": { - "test": "mocha ./test/*" - }, - "repository": { - "type": "git", - "url": "git+https://github.com/faisalman/ua-parser-js.git" - }, - "keywords": [ - "ua-parser-js", - "browser-detection", - "device-detection", - "os-detection", - "user-agent", - "client-hints" - ], - "license": "MIT", - "bugs": { - "url": "https://github.com/faisalman/ua-parser-js/issues" - }, - "homepage": "https://github.com/faisalman/ua-parser-js#readme" -} diff --git a/src/ua-client-hints/readme.md b/src/ua-client-hints/readme.md deleted file mode 100644 index 253f4ebe7..000000000 --- a/src/ua-client-hints/readme.md +++ /dev/null @@ -1,128 +0,0 @@ -# @ua-parser-js/ua-client-hints - -This is a [UAParser.js](https://github.com/faisalman/ua-parser-js) module that contains a collection of utility methods for working with user-agent client hints. - -```sh -npm i @ua-parser-js/ua-client-hints -``` - -### * `getUAData([props:array]):object` - -Get user-agent client hints values of current instance in form of JS object representation - -### * `setUAData([uaData:object]):UAClientHints` - -Set values of user-agent client hints for the current instance either from navigator.userAgentData or from HTTP headers (Sec-CH-UA-*) - -### * `getSerializedUAData([props:array]):object` - -Get user-agent client hints values of current instance in form of HTTP headers string representation (Sec-CH-UA-*) - -## Code Example - -```js -import { UAClientHints } from '@ua-parser-js/ua-client-hints'; - -/* - Suppose we're in a server having this client hints data: - - const httpHeaders = { - 'sec-ch-ua' : '"Chromium";v="93", "Google Chrome";v="93", " Not;A Brand";v="99"', - 'sec-ch-ua-full-version-list' : '"Chromium";v="93.0.1.2", "Google Chrome";v="93.0.1.2", " Not;A Brand";v="99.0.1.2"', - 'sec-ch-ua-arch' : 'arm', - 'sec-ch-ua-bitness' : '64', - 'sec-ch-ua-mobile' : '?1', - 'sec-ch-ua-model' : 'Pixel 99', - 'sec-ch-ua-platform' : 'Linux', - 'sec-ch-ua-platform-version' : '13' - }; -*/ - -const uaCH = new UAClientHints(); -uaCH.setUAData(httpHeaders); -const uaCHData1 = uaCH.getUAData(); -const uaCHData2 = uaCH.getUAData(['architecture', 'bitness']); - -console.log(uaCHData1); -/* - { - "architecture": "arm", - "bitness": "64", - "brands": [ - { - "brand": "Chromium", - "version": "93" - }, - { - "brand": "Google Chrome", - "version": "93" - }, - { - "brand": " Not;A Brand", - "version": "99" - } - ], - "fullVersionList": [ - { - "brand": "Chromium", - "version": "93.0.1.2" - }, - { - "brand": "Google Chrome", - "version": "93.0.1.2" - }, - { - "brand": " Not;A Brand", - "version": "99.0.1.2" - } - ], - "mobile": true, - "model": "Pixel 99", - "platform": "Linux", - "platformVersion": "13", - "wow64": null, - "formFactor": null - } -*/ - -console.log(uaCHData2); -/* - { - "architecture": "arm", - "bitness": "64" - } -*/ - -uaCH.setUAData({ - "wow64" : true, - "formFactor" : "Automotive" -}); - -const headersData1 = uaCH.getSerializedUAData(); -const headersData2 = uaCH.getSerializedUAData(['brand', 'mobile', 'model']); - -console.log(headersData1); -/* - { - 'sec-ch-ua' : '"Chromium";v="93", "Google Chrome";v="93", " Not;A Brand";v="99"', - 'sec-ch-ua-full-version-list' : '"Chromium";v="93.0.1.2", "Google Chrome";v="93.0.1.2", " Not;A Brand";v="99.0.1.2"', - 'sec-ch-ua-arch' : 'arm', - 'sec-ch-ua-bitness' : '64', - 'sec-ch-ua-mobile' : '?1', - 'sec-ch-ua-model' : 'Pixel 99', - 'sec-ch-ua-platform' : 'Linux', - 'sec-ch-ua-platform-version' : '13', - 'sec-ch-ua-wow64' : '?1', - 'sec-ch-ua-form-factor' : 'Automotive' - }; -*/ - -console.log(headersData2); -/* - { - 'sec-ch-ua' : '"Chromium";v="93", "Google Chrome";v="93", " Not;A Brand";v="99"', - 'sec-ch-ua-mobile' : '?1', - 'sec-ch-ua-model' : 'Pixel 99' - }; -*/ -``` \ No newline at end of file diff --git a/src/ua-client-hints/test/index.js b/src/ua-client-hints/test/index.js deleted file mode 100644 index 23d126245..000000000 --- a/src/ua-client-hints/test/index.js +++ /dev/null @@ -1,64 +0,0 @@ -const { UAClientHints } = require('../ua-client-hints'); -const assert = require('assert'); - -describe('Parse CH Headers', () => { - it('parse client hints HTTP headers (sec-ch-ua) into a client hints-like JavaScript object', () => { - - const req = { - headers : { - 'sec-ch-ua' : '"Chromium";v="93", "Google Chrome";v="93", " Not;A Brand";v="99"', - 'sec-ch-ua-full-version-list' : '"Chromium";v="93.0.1.2", "Google Chrome";v="93.0.1.2", " Not;A Brand";v="99.0.1.2"', - 'sec-ch-ua-arch' : '"arm"', - 'sec-ch-ua-bitness' : '"64"', - 'sec-ch-ua-mobile' : '?1', - 'sec-ch-ua-model' : '"Pixel 99"', - 'sec-ch-ua-platform' : '"Linux"', - 'sec-ch-ua-platform-version' : '"13"', - 'user-agent' : 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/110.0.0.0 Safari/537.36' - }}; - - assert.deepEqual(new UAClientHints().setUAData(req.headers).getUAData(['architecture', 'bitness']), { - "architecture": "arm", - "bitness": "64" - }); - - assert.deepEqual(new UAClientHints().setUAData(req.headers).getUAData(), { - "architecture": "arm", - "bitness": "64", - "brands": [ - { - "brand": "Chromium", - "version": "93" - }, - { - "brand": "Google Chrome", - "version": "93" - }, - { - "brand": "Not;A Brand", - "version": "99" - } - ], - "fullVersionList": [ - { - "brand": "Chromium", - "version": "93.0.1.2" - }, - { - "brand": "Google Chrome", - "version": "93.0.1.2" - }, - { - "brand": "Not;A Brand", - "version": "99.0.1.2" - } - ], - "formFactor": null, - "mobile": true, - "model": "Pixel 99", - "platform": "Linux", - "platformVersion": "13", - "wow64": null - }); - }); -}); \ No newline at end of file diff --git a/src/ua-client-hints/ua-client-hints.d.ts b/src/ua-client-hints/ua-client-hints.d.ts deleted file mode 100644 index 307765848..000000000 --- a/src/ua-client-hints/ua-client-hints.d.ts +++ /dev/null @@ -1,39 +0,0 @@ -export type UABrowser = { - brand: string | null, - version: string | null -}; - -export type UADataType = boolean | string | Array | null; -export type UADataField = - 'brands' | - 'mobile' | - 'platform' | - 'architecture' | - 'bitness' | - 'formFactor' | - 'fullVersionList' | - 'model' | - 'platformVersion' | - 'wow64'; - -export type HeaderType = 'sf-boolean' | 'sf-string' | 'sf-list'; -export type HeaderField = - 'sec-ch-ua-arch' | - 'sec-ch-ua-bitness' | - 'sec-ch-ua' | - 'sec-ch-ua-form-factor' | - 'sec-ch-ua-full-version-list' | - 'sec-ch-ua-mobile' | - 'sec-ch-ua-model' | - 'sec-ch-ua-platform' | - 'sec-ch-ua-platform-version' | - 'sec-ch-ua-wow64'; - -export class UAClientHints { - #ch: Map; - #parseHeader(str: string, type: HeaderType): UADataType; - #serialize(data: UADataType, type: HeaderType): string; - getSerializedUAData(): Record; - getUAData(props?: Array): Record; - setUAData(uaData: Record | Record): UAClientHints; -}; \ No newline at end of file diff --git a/src/ua-client-hints/ua-client-hints.js b/src/ua-client-hints/ua-client-hints.js deleted file mode 100644 index d4ddc6077..000000000 --- a/src/ua-client-hints/ua-client-hints.js +++ /dev/null @@ -1,130 +0,0 @@ -////////////////////////////////////////////// -/* A collection of utility methods for - working with user-agent client hints - https://github.com/faisalman/ua-parser-js - Author: Faisal Salman - MIT License */ -///////////////////////////////////////////// - -/*jshint esversion: 11 */ - -const fieldType = Object.freeze({ - Boolean : 'sf-boolean', - List : 'sf-list', - String : 'sf-string' -}); - -const uaCHMap = Object.freeze({ - architecture : { - field : 'Sec-CH-UA-Arch', - type : fieldType.String - }, - bitness : { - field : 'Sec-CH-UA-Bitness', - type : fieldType.String - }, - brands : { - field : 'Sec-CH-UA', - type : fieldType.List - }, - formFactor : { - field : 'Sec-CH-UA-Form-Factor', - type : fieldType.String - }, - fullVersionList : { - field : 'Sec-CH-UA-Full-Version-List', - type : fieldType.List - }, - mobile : { - field : 'Sec-CH-UA-Mobile', - type : fieldType.Boolean - }, - model : { - field : 'Sec-CH-UA-Model', - type : fieldType.String - }, - platform : { - field : 'Sec-CH-UA-Platform', - type : fieldType.String - }, - platformVersion : { - field : 'Sec-CH-UA-Platform-Version', - type : fieldType.String - }, - wow64 : { - field : 'Sec-CH-UA-WOW64', - type : fieldType.Boolean - } -}); - -class UAClientHints { - - #uach = new Map(); - - constructor () { - for (const key in uaCHMap) { - this.#uach.set(key, null); - } - return this; - }; - - #parseHeader (str, type) { - if (!str) { - return null; - } - switch (type) { - case fieldType.Boolean: - return /\?1/.test(str); - case fieldType.List: - return str.replace(/\\?\"/g, '') - .split(',') - .map(brands => { - const [brand, version] = brands.trim().split(';v='); - return { - brand : brand, - version : version - }; - }); - case fieldType.String: - return str.replace(/\s*\\?\"\s*/g, ''); - default: - return ''; - } - }; - - #serialize(data, type) { - throw new Error('Not implemented yet'); - //return ''; - } - - getSerializedUAData() { - throw new Error('Not implemented yet'); - //let http = {}; - //return http; - } - - getUAData(props) { - if (props) { - return Object.fromEntries(props.filter(val => this.#uach.get(val)).map(val => [val, this.#uach.get(val)])); - } - return Object.fromEntries(this.#uach); - } - - setUAData(uaDataValues) { - if(Object.keys(uaDataValues).some(key => key.startsWith('sec-ch-ua'))) { - for (const val in uaCHMap) { - const { field, type } = uaCHMap[val]; - this.#uach.set(val, this.#parseHeader(uaDataValues[field.toLowerCase()], type)); - } - } else { - for (const value in uaDataValues) { - if (this.#uach.has(value)) this.#uach.set(value, uaDataValues[value]); - } - } - return this; - }; -} - -module.exports = { - UAClientHints -}; \ No newline at end of file diff --git a/src/ua-client-hints/ua-client-hints.mjs b/src/ua-client-hints/ua-client-hints.mjs deleted file mode 100644 index 047f5c828..000000000 --- a/src/ua-client-hints/ua-client-hints.mjs +++ /dev/null @@ -1,134 +0,0 @@ -// Generated ESM version of @ua-parser-js/ua-client-hints -// DO NOT EDIT THIS FILE! -// Source: /src/ua-client-hints/ua-client-hints.js - -////////////////////////////////////////////// -/* A collection of utility methods for - working with user-agent client hints - https://github.com/faisalman/ua-parser-js - Author: Faisal Salman - MIT License */ -///////////////////////////////////////////// - -/*jshint esversion: 11 */ - -const fieldType = Object.freeze({ - Boolean : 'sf-boolean', - List : 'sf-list', - String : 'sf-string' -}); - -const uaCHMap = Object.freeze({ - architecture : { - field : 'Sec-CH-UA-Arch', - type : fieldType.String - }, - bitness : { - field : 'Sec-CH-UA-Bitness', - type : fieldType.String - }, - brands : { - field : 'Sec-CH-UA', - type : fieldType.List - }, - formFactor : { - field : 'Sec-CH-UA-Form-Factor', - type : fieldType.String - }, - fullVersionList : { - field : 'Sec-CH-UA-Full-Version-List', - type : fieldType.List - }, - mobile : { - field : 'Sec-CH-UA-Mobile', - type : fieldType.Boolean - }, - model : { - field : 'Sec-CH-UA-Model', - type : fieldType.String - }, - platform : { - field : 'Sec-CH-UA-Platform', - type : fieldType.String - }, - platformVersion : { - field : 'Sec-CH-UA-Platform-Version', - type : fieldType.String - }, - wow64 : { - field : 'Sec-CH-UA-WOW64', - type : fieldType.Boolean - } -}); - -class UAClientHints { - - #uach = new Map(); - - constructor () { - for (const key in uaCHMap) { - this.#uach.set(key, null); - } - return this; - }; - - #parseHeader (str, type) { - if (!str) { - return null; - } - switch (type) { - case fieldType.Boolean: - return /\?1/.test(str); - case fieldType.List: - return str.replace(/\\?\"/g, '') - .split(',') - .map(brands => { - const [brand, version] = brands.trim().split(';v='); - return { - brand : brand, - version : version - }; - }); - case fieldType.String: - return str.replace(/\s*\\?\"\s*/g, ''); - default: - return ''; - } - }; - - #serialize(data, type) { - throw new Error('Not implemented yet'); - //return ''; - } - - getSerializedUAData() { - throw new Error('Not implemented yet'); - //let http = {}; - //return http; - } - - getUAData(props) { - if (props) { - return Object.fromEntries(props.filter(val => this.#uach.get(val)).map(val => [val, this.#uach.get(val)])); - } - return Object.fromEntries(this.#uach); - } - - setUAData(uaDataValues) { - if(Object.keys(uaDataValues).some(key => key.startsWith('sec-ch-ua'))) { - for (const val in uaCHMap) { - const { field, type } = uaCHMap[val]; - this.#uach.set(val, this.#parseHeader(uaDataValues[field.toLowerCase()], type)); - } - } else { - for (const value in uaDataValues) { - if (this.#uach.has(value)) this.#uach.set(value, uaDataValues[value]); - } - } - return this; - }; -} - -export { - UAClientHints -}; \ No newline at end of file diff --git a/src/user-agent-helpers/package.json b/src/user-agent-helpers/package.json deleted file mode 100644 index ba573084f..000000000 --- a/src/user-agent-helpers/package.json +++ /dev/null @@ -1,32 +0,0 @@ -{ - "title": "User-Agent Helpers", - "name": "@ua-parser-js/user-agent-helpers", - "version": "0.0.2", - "author": "Faisal Salman ", - "description": "A collection of utility methods for working with user-agent", - "main": "user-agent-helpers.js", - "module": "user-agent-helpers.mjs", - "scripts": { - "test": "mocha ./test/*" - }, - "repository": { - "type": "git", - "url": "git+https://github.com/faisalman/ua-parser-js.git" - }, - "keywords": [ - "ua-parser-js", - "browser-detection", - "device-detection", - "os-detection", - "user-agent", - "client-hints" - ], - "license": "MIT", - "bugs": { - "url": "https://github.com/faisalman/ua-parser-js/issues" - }, - "homepage": "https://github.com/faisalman/ua-parser-js#readme", - "dependencies": { - "@ua-parser-js/client-hints-helpers": "*" - } -} diff --git a/src/user-agent-helpers/readme.md b/src/user-agent-helpers/readme.md deleted file mode 100644 index 472070765..000000000 --- a/src/user-agent-helpers/readme.md +++ /dev/null @@ -1,77 +0,0 @@ -# @ua-parser-js/user-agent-helpers - -This is a [UAParser.js](https://github.com/faisalman/ua-parser-js) module that contains a collection of utility methods for working with user-agent. - -```sh -npm i @ua-parser-js/user-agent-helpers -``` - -### * `isFrozenUA(ua:string):boolean` - -Check whether a user-agent string match with [frozen user-agent pattern](https://www.chromium.org/updates/ua-reduction/) - -### * `unfreezeUA([ua:string,ch:object]|[headers:object]):Promise` - -Construct new unfreezed user-agent string using real data from client hints - -## Code Example - -```js -import { isFrozenUA } from '@ua-parser-js/user-agent-helpers'; - -const regularMobileUA = "Mozilla/5.0 (Linux; Android 9; SM-A205U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/93.0.1234.56 Mobile Safari/537.36"; -const freezedMobileUA = "Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/93.0.0.0 Mobile Safari/537.36"; - -console.log(isFrozenUA(regularMobileUA)); -// false - -console.log(isFrozenUA(freezedMobileUA)); -// true -``` - -```js -import { unfreezeUA } from '@ua-parser-js/user-agent-helpers'; - -/* - Suppose we're in a browser having this client hints data: - - { - fullVersionList: [ - { - brand: 'New Browser', - version: '110.1.2.3' - }, - { - brand: 'Chromium', - version: '110.1.2.3' - }, - { - brand: 'Not(A:Brand', - version: '110' - } - ], - platform: 'Windows', - platformVersion: '13.0.0', - architecture: 'arm' - } - - With a frozen user-agent: - - 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/93.0.0.0 Safari/537.36' -*/ - -// Now let's generate a complete user-agent: -unfreezeUA() - .then(newUA => console.log(newUA)); -// 'Mozilla/5.0 (Windows NT 11.0; ARM) AppleWebKit/537.36 (KHTML, like Gecko) New Browser/110.1.2.3 Chromium/110.1.2.3 Safari/537.36' - -/* -// Alternatively: -const ua = navigator.userAgent; -const ch = await navigator.userAgentData.getHighEntropyValues(); -const newUA = await unfreezeUA(ua, ch); - -// Server environment: -const newUA = await unfreezeUA(req.headers); -*/ -``` \ No newline at end of file diff --git a/src/user-agent-helpers/test/index.js b/src/user-agent-helpers/test/index.js deleted file mode 100644 index 4cea95409..000000000 --- a/src/user-agent-helpers/test/index.js +++ /dev/null @@ -1,56 +0,0 @@ -const { isFrozenUA, unfreezeUA } = require('../user-agent-helpers'); -const { UAClientHints } = require('@ua-parser-js/ua-client-hints'); -const assert = require('assert'); - -describe('isFrozenUA()', () => { - it('Returns whether a user agent is frozen', () => { - - const regularWindowsUA = "Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/93.0.1234.56 Safari/537.36"; - const freezedWindowsUA = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/93.0.0.0 Safari/537.36"; - - const regularMacUA = ""; - const freezedMacUA = ""; - - const regularLinuxUA = ""; - const freezedLinuxUA = ""; - - const regularCrOSUA = ""; - const freezedCrOSUA = ""; - - const regularFuchsiaUA = ""; - const freezedFuchsiaUA = ""; - - const regularMobileUA = "Mozilla/5.0 (Linux; Android 9; SM-A205U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/93.0.1234.56 Mobile Safari/537.36"; - const freezedMobileUA = "Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/93.0.0.0 Mobile Safari/537.36"; - - const regularTabletUA = "Mozilla/5.0 (Linux; Android 9; SM-T810) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/93.0.1234.56 Safari/537.36"; - const freezedTabletUA = "Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/93.0.0.0 Safari/537.36"; - - assert.strictEqual(isFrozenUA(regularWindowsUA), false); - assert.strictEqual(isFrozenUA(freezedWindowsUA), true); - assert.strictEqual(isFrozenUA(regularMobileUA), false); - assert.strictEqual(isFrozenUA(freezedMobileUA), true); - assert.strictEqual(isFrozenUA(regularTabletUA), false); - assert.strictEqual(isFrozenUA(freezedTabletUA), true); - }); -}); - -const req = { - headers : { - 'sec-ch-ua' : '"Chromium";v="93", "Google Chrome";v="93", " Not;A Brand";v="99"', - 'sec-ch-ua-full-version-list' : '"Chromium";v="93.0.1.2", "Google Chrome";v="93.0.1.2", " Not;A Brand";v="99.0.1.2"', - 'sec-ch-ua-arch' : '"arm"', - 'sec-ch-ua-bitness' : '"64"', - 'sec-ch-ua-mobile' : '?1', - 'sec-ch-ua-model' : '"Pixel 99"', - 'sec-ch-ua-platform' : '"Linux"', - 'sec-ch-ua-platform-version' : '"13"', - 'user-agent' : 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/110.0.0.0 Safari/537.36' -}}; - -describe('unfreezeUA()', () => { - it('returns an unfreezed user-agent using real data from client hints HTTP headers (sec-ch-ua)', async () => { - const unfreezed = await unfreezeUA(req.headers); - assert.strictEqual(unfreezed, 'Mozilla/5.0 (X11; Linux arm64) AppleWebKit/537.36 (KHTML, like Gecko) Chromium/93.0.1.2 Chrome/93.0.1.2 Safari/537.36'); - }); -}); \ No newline at end of file diff --git a/src/user-agent-helpers/user-agent-helpers.d.ts b/src/user-agent-helpers/user-agent-helpers.d.ts deleted file mode 100644 index d77af20c8..000000000 --- a/src/user-agent-helpers/user-agent-helpers.d.ts +++ /dev/null @@ -1,35 +0,0 @@ -export type UABrowser = { - brand: string | null, - version: string | null -}; - -export type UADataType = boolean | string | Array | null; -export type UADataField = - 'brands' | - 'mobile' | - 'platform' | - 'architecture' | - 'bitness' | - 'formFactor' | - 'fullVersionList' | - 'model' | - 'platformVersion' | - 'wow64'; - -export type HeaderType = 'sf-boolean' | 'sf-string' | 'sf-list'; -export type HeaderField = - 'sec-ch-ua-arch' | - 'sec-ch-ua-bitness' | - 'sec-ch-ua' | - 'sec-ch-ua-form-factor' | - 'sec-ch-ua-full-version-list' | - 'sec-ch-ua-mobile' | - 'sec-ch-ua-model' | - 'sec-ch-ua-platform' | - 'sec-ch-ua-platform-version' | - 'sec-ch-ua-wow64'; - -export function isFrozenUA(ua: string): boolean; -export function unfreezeUA(): Promise; -export function unfreezeUA(ua: string, ch: Record): Promise; -export function unfreezeUA(headers: Record): Promise; \ No newline at end of file diff --git a/src/user-agent-helpers/user-agent-helpers.js b/src/user-agent-helpers/user-agent-helpers.js deleted file mode 100644 index cfc9ecf07..000000000 --- a/src/user-agent-helpers/user-agent-helpers.js +++ /dev/null @@ -1,97 +0,0 @@ -//////////////////////////////////////////////////// -/* A collection of utility methods for user-agent - https://github.com/faisalman/ua-parser-js - Author: Faisal Salman - MIT License */ -/////////////////////////////////////////////////// - -/*jshint esversion: 11 */ - -const { UAClientHints } = require('@ua-parser-js/ua-client-hints'); - -/* - # Reference: - https://www.chromium.org/updates/ua-reduction/ - - # Desktop - --- - Format: - Mozilla/5.0 () AppleWebKit/537.36 (KHTML, like Gecko) Chrome/.0.0.0 Safari/537.36 - - Possible values: - - Windows NT 10.0; Win64; x64 - - Macintosh; Intel Mac OS X 10_15_7 - - X11; Linux x86_64 - - X11; CrOS x86_64 14541.0.0 - - Fuchsia - - # Mobile & Tablet: (except iOS/Android WebView) - --- - Format: - Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/.0.0.0 Safari/537.36 - - Possible values: - - "Mobile" - - "" (empty string for Tablets & Desktop) -*/ - -const isFrozenUA = ua => /^Mozilla\/5\.0 \((Windows NT 10\.0; Win64; x64|Macintosh; Intel Mac OS X 10_15_7|X11; Linux x86_64|X11; CrOS x86_64 14541\.0\.0|Fuchsia|Linux; Android 10; K)\) AppleWebKit\/537\.36 \(KHTML, like Gecko\) Chrome\/\d+\.0\.0\.0 (Mobile )?Safari\/537\.36$/.test(ua); - -const unfreezeUA = async (ua, ch) => { - const env = typeof navigator == 'undefined' ? 'node' : 'browser'; - if (env == 'node') { - if (!ua['user-agent']) { - throw new Error('User-Agent header not found'); - } - ch = new UAClientHints().setUAData(ua).getUAData(); - ua = ua['user-agent']; - } else { - ua = ua || navigator.userAgent; - ch = ch || await navigator.userAgentData?.getHighEntropyValues(['arch', 'bitness', 'fullVersionList', 'model', 'platform', 'platformVersion', 'wow64']); - } - if (isFrozenUA(ua) && ch) { - switch (ch.platform) { - case 'Windows': - let [major, minor] = ch.platformVersion - .split('.') - .map(num => parseInt(num, 10)); - major = (major < 1) ? '6' : (major >= 13) ? '11' : '10'; - ua = ua .replace(/(?Windows NT) 10\.0/, `$ ${major}.${minor}`) - .replace(/; (?Win64; x64)/, - (ch.architecture == 'arm') ? - '; ARM' : - (ch.wow64) ? - '; WOW64' : - (ch.architecture == 'x86' && ch.bitness != '64') ? - '' : '; $'); - break; - case 'Android': - ua = ua.replace(/(?Android) 10; K/, `$ ${ch.platformVersion}; ${ch.model}`); - break; - case 'Linux': - case 'Chrome OS': - ua = ua.replace(/(?x86_64)/, - (ch.architecture == 'arm') ? - ((ch.bitness == '64') ? 'arm64' : 'arm') : - (ch.architecture == 'x86' && ch.bitness != '64') ? - 'x86' : '$'); - break; - case 'macOS': - ua = ua.replace(/(?Mac OS X) 10_15_7/, `$ ${ch.platformVersion.replace(/\./, '_')}`); - break; - } - if (ch.fullVersionList) { - ua = ua.replace(/Chrome\/\d+\.0\.0\.0 /, - ch.fullVersionList - .filter(browser => !/not.a.brand/i.test(browser.brand)) - .map(browser => `${browser.brand.replace(/^google /i,'')}/${browser.version} `) - .join('')); - } - } - return ua; -}; - -module.exports = { - isFrozenUA, - unfreezeUA -}; \ No newline at end of file diff --git a/src/user-agent-helpers/user-agent-helpers.mjs b/src/user-agent-helpers/user-agent-helpers.mjs deleted file mode 100644 index b8f398e09..000000000 --- a/src/user-agent-helpers/user-agent-helpers.mjs +++ /dev/null @@ -1,101 +0,0 @@ -// Generated ESM version of @ua-parser-js/user-agent-helpers -// DO NOT EDIT THIS FILE! -// Source: /src/user-agent-helpers/user-agent-helpers.js - -//////////////////////////////////////////////////// -/* A collection of utility methods for user-agent - https://github.com/faisalman/ua-parser-js - Author: Faisal Salman - MIT License */ -/////////////////////////////////////////////////// - -/*jshint esversion: 11 */ - -import { UAClientHints } from '@ua-parser-js/ua-client-hints'; - -/* - # Reference: - https://www.chromium.org/updates/ua-reduction/ - - # Desktop - --- - Format: - Mozilla/5.0 () AppleWebKit/537.36 (KHTML, like Gecko) Chrome/.0.0.0 Safari/537.36 - - Possible values: - - Windows NT 10.0; Win64; x64 - - Macintosh; Intel Mac OS X 10_15_7 - - X11; Linux x86_64 - - X11; CrOS x86_64 14541.0.0 - - Fuchsia - - # Mobile & Tablet: (except iOS/Android WebView) - --- - Format: - Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/.0.0.0 Safari/537.36 - - Possible values: - - "Mobile" - - "" (empty string for Tablets & Desktop) -*/ - -const isFrozenUA = ua => /^Mozilla\/5\.0 \((Windows NT 10\.0; Win64; x64|Macintosh; Intel Mac OS X 10_15_7|X11; Linux x86_64|X11; CrOS x86_64 14541\.0\.0|Fuchsia|Linux; Android 10; K)\) AppleWebKit\/537\.36 \(KHTML, like Gecko\) Chrome\/\d+\.0\.0\.0 (Mobile )?Safari\/537\.36$/.test(ua); - -const unfreezeUA = async (ua, ch) => { - const env = typeof navigator == 'undefined' ? 'node' : 'browser'; - if (env == 'node') { - if (!ua['user-agent']) { - throw new Error('User-Agent header not found'); - } - ch = new UAClientHints().setUAData(ua).getUAData(); - ua = ua['user-agent']; - } else { - ua = ua || navigator.userAgent; - ch = ch || await navigator.userAgentData?.getHighEntropyValues(['arch', 'bitness', 'fullVersionList', 'model', 'platform', 'platformVersion', 'wow64']); - } - if (isFrozenUA(ua) && ch) { - switch (ch.platform) { - case 'Windows': - let [major, minor] = ch.platformVersion - .split('.') - .map(num => parseInt(num, 10)); - major = (major < 1) ? '6' : (major >= 13) ? '11' : '10'; - ua = ua .replace(/(?Windows NT) 10\.0/, `$ ${major}.${minor}`) - .replace(/; (?Win64; x64)/, - (ch.architecture == 'arm') ? - '; ARM' : - (ch.wow64) ? - '; WOW64' : - (ch.architecture == 'x86' && ch.bitness != '64') ? - '' : '; $'); - break; - case 'Android': - ua = ua.replace(/(?Android) 10; K/, `$ ${ch.platformVersion}; ${ch.model}`); - break; - case 'Linux': - case 'Chrome OS': - ua = ua.replace(/(?x86_64)/, - (ch.architecture == 'arm') ? - ((ch.bitness == '64') ? 'arm64' : 'arm') : - (ch.architecture == 'x86' && ch.bitness != '64') ? - 'x86' : '$'); - break; - case 'macOS': - ua = ua.replace(/(?Mac OS X) 10_15_7/, `$ ${ch.platformVersion.replace(/\./, '_')}`); - break; - } - if (ch.fullVersionList) { - ua = ua.replace(/Chrome\/\d+\.0\.0\.0 /, - ch.fullVersionList - .filter(browser => !/not.a.brand/i.test(browser.brand)) - .map(browser => `${browser.brand.replace(/^google /i,'')}/${browser.version} `) - .join('')); - } - } - return ua; -}; - -export { - isFrozenUA, - unfreezeUA -}; \ No newline at end of file