mirror of
https://github.com/faisalman/ua-parser-js.git
synced 2025-09-27 16:08:47 +03:00
[ua-client-hints] Refactor UAClientHints
This commit is contained in:
parent
f538018f8e
commit
1522691426
10
package-lock.json
generated
10
package-lock.json
generated
@ -23,7 +23,7 @@
|
||||
],
|
||||
"license": "MIT",
|
||||
"workspaces": [
|
||||
"src/client-hints-helpers",
|
||||
"src/ua-client-hints",
|
||||
"src/user-agent-helpers"
|
||||
],
|
||||
"devDependencies": {
|
||||
@ -768,6 +768,10 @@
|
||||
"resolved": "src/client-hints-helpers",
|
||||
"link": true
|
||||
},
|
||||
"node_modules/@ua-parser-js/ua-client-hints": {
|
||||
"resolved": "src/ua-client-hints",
|
||||
"link": true
|
||||
},
|
||||
"node_modules/@ua-parser-js/user-agent-helpers": {
|
||||
"resolved": "src/user-agent-helpers",
|
||||
"link": true
|
||||
@ -3794,6 +3798,10 @@
|
||||
"extraneous": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"src/ua-client-hints": {
|
||||
"version": "0.0.1",
|
||||
"license": "MIT"
|
||||
},
|
||||
"src/user-agent-helpers": {
|
||||
"name": "@ua-parser-js/user-agent-helpers",
|
||||
"version": "0.0.1",
|
||||
|
@ -219,7 +219,7 @@
|
||||
}
|
||||
],
|
||||
"workspaces": [
|
||||
"src/client-hints-helpers",
|
||||
"src/ua-client-hints",
|
||||
"src/user-agent-helpers"
|
||||
]
|
||||
}
|
||||
|
@ -54,9 +54,9 @@ const modules = [
|
||||
replacements : []
|
||||
},
|
||||
{
|
||||
src : 'src/client-hints-helpers/client-hints-helpers.js',
|
||||
dest : 'src/client-hints-helpers/client-hints-helpers.mjs',
|
||||
title : '@ua-parser-js/client-hints-helpers',
|
||||
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 : []
|
||||
}
|
||||
];
|
||||
|
@ -1,35 +0,0 @@
|
||||
interface IBrowser {
|
||||
brand: string;
|
||||
version: string;
|
||||
}
|
||||
|
||||
interface ClientHintsJSLowEntropy {
|
||||
brands: Array<IBrowser>;
|
||||
mobile: boolean;
|
||||
platform: string;
|
||||
}
|
||||
|
||||
export interface ClientHintsJSHighEntropy extends ClientHintsJSLowEntropy {
|
||||
architecture?: string;
|
||||
bitness?: string;
|
||||
formFactor?: string;
|
||||
fullVersionList?: Array<IBrowser>;
|
||||
model?: string;
|
||||
platformVersion?: string;
|
||||
wow64?: boolean;
|
||||
};
|
||||
|
||||
export interface ClientHintsHTTPHeaders {
|
||||
'sec-ch-ua-arch'?: string;
|
||||
'sec-ch-ua-bitness'?: string;
|
||||
'sec-ch-ua'?: string;
|
||||
'sec-ch-ua-form-factor'?: string;
|
||||
'sec-ch-ua-full-version-list'?: string;
|
||||
'sec-ch-ua-mobile'?: string;
|
||||
'sec-ch-ua-model'?: string;
|
||||
'sec-ch-ua-platform'?: string;
|
||||
'sec-ch-ua-platform-version'?: string;
|
||||
'sec-ch-ua-wow64'?: string;
|
||||
}
|
||||
|
||||
export function UACHParser(headers: ClientHintsHTTPHeaders): ClientHintsJSHighEntropy;
|
@ -1,88 +0,0 @@
|
||||
////////////////////////////////////////////////////
|
||||
/* A collection of utility methods for client-hints
|
||||
https://github.com/faisalman/ua-parser-js
|
||||
Author: Faisal Salman <f@faisalman.com>
|
||||
MIT License */
|
||||
///////////////////////////////////////////////////
|
||||
|
||||
/*jshint esversion: 11 */
|
||||
|
||||
const UACHMap = {
|
||||
'sec-ch-ua-arch' : {
|
||||
prop : 'architecture',
|
||||
type : 'sf-string'
|
||||
},
|
||||
'sec-ch-ua-bitness' : {
|
||||
prop : 'bitness',
|
||||
type : 'sf-string'
|
||||
},
|
||||
'sec-ch-ua' : {
|
||||
prop : 'brands',
|
||||
type : 'sf-list'
|
||||
},
|
||||
'sec-ch-ua-form-factor' : {
|
||||
prop : 'formFactor',
|
||||
type : 'sf-string'
|
||||
},
|
||||
'sec-ch-ua-full-version-list' : {
|
||||
prop : 'fullVersionList',
|
||||
type : 'sf-list'
|
||||
},
|
||||
'sec-ch-ua-mobile' : {
|
||||
prop : 'mobile',
|
||||
type : 'sf-boolean',
|
||||
},
|
||||
'sec-ch-ua-model' : {
|
||||
prop : 'model',
|
||||
type : 'sf-string',
|
||||
},
|
||||
'sec-ch-ua-platform' : {
|
||||
prop : 'platform',
|
||||
type : 'sf-string'
|
||||
},
|
||||
'sec-ch-ua-platform-version' : {
|
||||
prop : 'platformVersion',
|
||||
type : 'sf-string'
|
||||
},
|
||||
'sec-ch-ua-wow64' : {
|
||||
prop : 'wow64',
|
||||
type : 'sf-boolean'
|
||||
}
|
||||
};
|
||||
|
||||
const UACHParser = (headers) => {
|
||||
const parse = (str, type) => {
|
||||
if (!str) {
|
||||
return '';
|
||||
}
|
||||
switch (type) {
|
||||
case 'sf-boolean':
|
||||
return /\?1/.test(str);
|
||||
case 'sf-list':
|
||||
return str.replace(/\\?\"/g, '')
|
||||
.split(', ')
|
||||
.map(brands => {
|
||||
const [brand, version] = brands.split(';v=');
|
||||
return {
|
||||
brand : brand,
|
||||
version : version
|
||||
};
|
||||
});
|
||||
case 'sf-string':
|
||||
default:
|
||||
return str.replace(/\\?\"/g, '');
|
||||
}
|
||||
};
|
||||
let ch = {};
|
||||
Object.keys(UACHMap).forEach(field => {
|
||||
if (headers.hasOwnProperty(field)) {
|
||||
const { prop, type } = UACHMap[field];
|
||||
ch[prop] = parse(headers[field], type);
|
||||
}
|
||||
});
|
||||
return ch;
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
UACHParser
|
||||
};
|
@ -1,92 +0,0 @@
|
||||
// Generated ESM version of @ua-parser-js/client-hints-helpers
|
||||
// DO NOT EDIT THIS FILE!
|
||||
// Source: /src/client-hints-helpers/client-hints-helpers.js
|
||||
|
||||
////////////////////////////////////////////////////
|
||||
/* A collection of utility methods for client-hints
|
||||
https://github.com/faisalman/ua-parser-js
|
||||
Author: Faisal Salman <f@faisalman.com>
|
||||
MIT License */
|
||||
///////////////////////////////////////////////////
|
||||
|
||||
/*jshint esversion: 11 */
|
||||
|
||||
const UACHMap = {
|
||||
'sec-ch-ua-arch' : {
|
||||
prop : 'architecture',
|
||||
type : 'sf-string'
|
||||
},
|
||||
'sec-ch-ua-bitness' : {
|
||||
prop : 'bitness',
|
||||
type : 'sf-string'
|
||||
},
|
||||
'sec-ch-ua' : {
|
||||
prop : 'brands',
|
||||
type : 'sf-list'
|
||||
},
|
||||
'sec-ch-ua-form-factor' : {
|
||||
prop : 'formFactor',
|
||||
type : 'sf-string'
|
||||
},
|
||||
'sec-ch-ua-full-version-list' : {
|
||||
prop : 'fullVersionList',
|
||||
type : 'sf-list'
|
||||
},
|
||||
'sec-ch-ua-mobile' : {
|
||||
prop : 'mobile',
|
||||
type : 'sf-boolean',
|
||||
},
|
||||
'sec-ch-ua-model' : {
|
||||
prop : 'model',
|
||||
type : 'sf-string',
|
||||
},
|
||||
'sec-ch-ua-platform' : {
|
||||
prop : 'platform',
|
||||
type : 'sf-string'
|
||||
},
|
||||
'sec-ch-ua-platform-version' : {
|
||||
prop : 'platformVersion',
|
||||
type : 'sf-string'
|
||||
},
|
||||
'sec-ch-ua-wow64' : {
|
||||
prop : 'wow64',
|
||||
type : 'sf-boolean'
|
||||
}
|
||||
};
|
||||
|
||||
const UACHParser = (headers) => {
|
||||
const parse = (str, type) => {
|
||||
if (!str) {
|
||||
return '';
|
||||
}
|
||||
switch (type) {
|
||||
case 'sf-boolean':
|
||||
return /\?1/.test(str);
|
||||
case 'sf-list':
|
||||
return str.replace(/\\?\"/g, '')
|
||||
.split(', ')
|
||||
.map(brands => {
|
||||
const [brand, version] = brands.split(';v=');
|
||||
return {
|
||||
brand : brand,
|
||||
version : version
|
||||
};
|
||||
});
|
||||
case 'sf-string':
|
||||
default:
|
||||
return str.replace(/\\?\"/g, '');
|
||||
}
|
||||
};
|
||||
let ch = {};
|
||||
Object.keys(UACHMap).forEach(field => {
|
||||
if (headers.hasOwnProperty(field)) {
|
||||
const { prop, type } = UACHMap[field];
|
||||
ch[prop] = parse(headers[field], type);
|
||||
}
|
||||
});
|
||||
return ch;
|
||||
};
|
||||
|
||||
export {
|
||||
UACHParser
|
||||
};
|
@ -1,75 +0,0 @@
|
||||
# @ua-parser-js/client-hints-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 client-hints.
|
||||
|
||||
```sh
|
||||
npm i @ua-parser-js/client-hints-helpers
|
||||
```
|
||||
|
||||
### * `UACHParser(headers:object):object`
|
||||
|
||||
Parse user-agent client-hints HTTP headers (sec-ch-ua) into its JS API equivalent
|
||||
|
||||
## Code Example
|
||||
|
||||
```js
|
||||
import { UACHParser } from '@ua-parser-js/client-hints-helpers';
|
||||
|
||||
/*
|
||||
Suppose we're in a server having this client hints data:
|
||||
|
||||
const 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'
|
||||
};
|
||||
*/
|
||||
|
||||
const userAgentData = UACHParser(headers);
|
||||
|
||||
console.log(userAgentData);
|
||||
/*
|
||||
{
|
||||
"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"
|
||||
}
|
||||
*/
|
||||
```
|
@ -1,11 +1,11 @@
|
||||
{
|
||||
"title": "Client-Hints Helpers",
|
||||
"name": "@ua-parser-js/client-hints-helpers",
|
||||
"title": "User-Agent Client Hints",
|
||||
"name": "@ua-parser-js/ua-client-hints",
|
||||
"version": "0.0.1",
|
||||
"author": "Faisal Salman <f@faisalman.com>",
|
||||
"description": "A collection of utility methods for working with client-hints",
|
||||
"main": "client-hints-helpers.js",
|
||||
"module": "client-hints-helpers.mjs",
|
||||
"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/mocha-test-helpers"
|
||||
},
|
128
src/ua-client-hints/readme.md
Normal file
128
src/ua-client-hints/readme.md
Normal file
@ -0,0 +1,128 @@
|
||||
# @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'
|
||||
};
|
||||
*/
|
||||
```
|
39
src/ua-client-hints/ua-client-hints.d.ts
vendored
Normal file
39
src/ua-client-hints/ua-client-hints.d.ts
vendored
Normal file
@ -0,0 +1,39 @@
|
||||
export type UABrowser = {
|
||||
brand: string | null,
|
||||
version: string | null
|
||||
};
|
||||
|
||||
export type UADataType = boolean | string | Array<UABrowser> | 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<UADataField, UADataType>;
|
||||
#parseHeader(str: string, type: HeaderType): UADataType;
|
||||
#serialize(data: UADataType, type: HeaderType): string;
|
||||
getSerializedUAData(): Record<HeaderField, string>;
|
||||
getUAData(props?: Array<UADataField>): Record<UADataField, UADataType>;
|
||||
setUAData(uaData: Record<UADataField, UADataType> | Record<HeaderField, string>): UAClientHints;
|
||||
};
|
130
src/ua-client-hints/ua-client-hints.js
Normal file
130
src/ua-client-hints/ua-client-hints.js
Normal file
@ -0,0 +1,130 @@
|
||||
//////////////////////////////////////////////
|
||||
/* A collection of utility methods for
|
||||
working with user-agent client hints
|
||||
https://github.com/faisalman/ua-parser-js
|
||||
Author: Faisal Salman <f@faisalman.com>
|
||||
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
|
||||
};
|
134
src/ua-client-hints/ua-client-hints.mjs
Normal file
134
src/ua-client-hints/ua-client-hints.mjs
Normal file
@ -0,0 +1,134 @@
|
||||
// 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 <f@faisalman.com>
|
||||
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
|
||||
};
|
@ -1,5 +1,5 @@
|
||||
const { isFrozenUA, unfreezeUA } = require('@ua-parser-js/user-agent-helpers');
|
||||
const { UACHParser } = require('@ua-parser-js/client-hints-helpers');
|
||||
const { UAClientHints } = require('@ua-parser-js/ua-client-hints');
|
||||
const assert = require('assert');
|
||||
|
||||
describe('isFrozenUA()', () => {
|
||||
@ -38,12 +38,12 @@ describe('isFrozenUA()', () => {
|
||||
const 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-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-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'
|
||||
};
|
||||
|
||||
@ -54,9 +54,13 @@ describe('unfreezeUA()', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('UACHParser()', () => {
|
||||
describe('Parse CH Headers', () => {
|
||||
it('parse client hints HTTP headers (sec-ch-ua) into a client hints-like JavaScript object', () => {
|
||||
assert.deepEqual(UACHParser(headers), {
|
||||
assert.deepEqual(new UAClientHints().setUAData(headers).getUAData(['architecture', 'bitness']), {
|
||||
"architecture": "arm",
|
||||
"bitness": "64"
|
||||
});
|
||||
assert.deepEqual(new UAClientHints().setUAData(headers).getUAData(), {
|
||||
"architecture": "arm",
|
||||
"bitness": "64",
|
||||
"brands": [
|
||||
@ -69,7 +73,7 @@ describe('UACHParser()', () => {
|
||||
"version": "93"
|
||||
},
|
||||
{
|
||||
"brand": " Not;A Brand",
|
||||
"brand": "Not;A Brand",
|
||||
"version": "99"
|
||||
}
|
||||
],
|
||||
@ -83,14 +87,16 @@ describe('UACHParser()', () => {
|
||||
"version": "93.0.1.2"
|
||||
},
|
||||
{
|
||||
"brand": " Not;A Brand",
|
||||
"brand": "Not;A Brand",
|
||||
"version": "99.0.1.2"
|
||||
}
|
||||
],
|
||||
"formFactor": null,
|
||||
"mobile": true,
|
||||
"model": "Pixel 99",
|
||||
"platform": "Linux",
|
||||
"platformVersion": "13"
|
||||
"platformVersion": "13",
|
||||
"wow64": null
|
||||
});
|
||||
});
|
||||
});
|
Loading…
x
Reference in New Issue
Block a user