char/avril
(wip) why'd you have to go and make things so complicaaaaated?
git clone https://git.t4t.associates/char/avril
44fe2c6
main
1import { 2ObjectCreate , 3ObjectFreeze as freeze , 4ReflectApply as apply , 5SymbolIterator , 6TypeError , 7WeakMap , 8WeakMapPrototypeSet as set , 9} from "ext:core/primordials" ; 10import { onRuntimeStart } from "ext:core/bootstrap" ; 11import { 12op_navigator_metadata as getMetadata , 13op_navigator_user_agent_data as getUserAgentData , 14} from "ext:core/ops" ; 15import { isObject , required , state , string , usv } from "./idl.js" ; 16import { registerUncloneable } from "./serialization.js" ; 17 18const secret = ObjectCreate ( null ) as { readonly navigatorToken :unique symbol }; 19interface NavigatorMetadata { 20platform :string ; 21hardwareConcurrency :number ; 22} 23interface Brand { 24brand :string ; 25version :string ; 26} 27interface UserAgentData { 28brands :readonly Brand []; 29mobile :boolean ; 30platform :string ; 31architecture :string ; 32bitness :string ; 33model :string ; 34platformVersion :string ; 35uaFullVersion :string ; 36fullVersionList :readonly Brand []; 37wow64 :boolean ; 38} 39interface EntropyValues { 40brands :Brand []; 41mobile :boolean ; 42platform :string ; 43architecture ?:string ; 44bitness ?:string ; 45model ?:string ; 46platformVersion ?:string ; 47uaFullVersion ?:string ; 48fullVersionList ?:Brand []; 49wow64 ?:boolean ; 50} 51const navigators = new WeakMap < object , NavigatorMetadata >(); 52registerUncloneable ( navigators ); 53const metadata = ObjectCreate ( null ) as NavigatorMetadata , 54uaRecord = ObjectCreate ( null ) as UserAgentData ; 55let userAgent :string ; 56const languages = freeze ([ "en-US" ]); 57onRuntimeStart (() => { 58const info = getMetadata ( null ); 59metadata . platform = info [ 0 ]; 60metadata . hardwareConcurrency = info [ 1 ]; 61userAgent = info [ 2 ]; 62const raw = getUserAgentData ( null ); 63const frozenBrands :Brand [] = []; 64for ( let i = 0 ; i < raw . brands . length ; i ++ ) { 65frozenBrands [ frozenBrands . length ] = freeze ({ 66brand :raw . brands [ i ]. brand , 67version :raw . brands [ i ]. version , 68}); 69} 70uaRecord . brands = freeze ( frozenBrands ); 71uaRecord . mobile = raw . mobile ; 72uaRecord . platform = raw . platform ; 73uaRecord . architecture = raw . architecture ; 74uaRecord . bitness = raw . bitness ; 75uaRecord . model = raw . model ; 76uaRecord . platformVersion = raw . platformVersion ; 77uaRecord . uaFullVersion = raw . uaFullVersion ; 78uaRecord . fullVersionList = raw . fullVersionList ; 79uaRecord . wow64 = raw . wow64 ; 80}); 81const uaDataStates = new WeakMap < object , UserAgentData >(); 82registerUncloneable ( uaDataStates ); 83 84function copyBrands ( list :readonly Brand []) :Brand [] { 85const out :Brand [] = []; 86for ( let i = 0 ; i < list . length ; i ++ ) { 87out [ out . length ] = { brand :list [ i ]. brand , version :list [ i ]. version }; 88} 89return out ; 90} 91 92class NavigatorUAData { 93constructor ( key :typeof secret ); 94constructor () { 95if ( arguments [ 0 ] !== secret ) throw new TypeError ( "Illegal constructor" ); 96set ( uaDataStates , this , uaRecord ); 97} 98get brands () { 99return state ( uaDataStates , this ). brands ; 100} 101get mobile () { 102return state ( uaDataStates , this ). mobile ; 103} 104get platform () { 105return state ( uaDataStates , this ). platform ; 106} 107async getHighEntropyValues ( hints :unknown ) :Promise < EntropyValues > { 108const current = state ( uaDataStates , this ); 109required ( arguments . length , 1 ); 110if ( ! isObject ( hints )) { 111throw new TypeError ( "Expected an iterable of strings" ); 112} 113const method = hints [ SymbolIterator ]; 114if ( typeof method !== "function" ) { 115throw new TypeError ( "Expected an iterable of strings" ); 116} 117const iterator = apply ( method , hints , []); 118if ( ! isObject ( iterator )) throw new TypeError ( "Invalid hints iterator" ); 119const next = iterator . next ; 120if ( typeof next !== "function" ) { 121throw new TypeError ( "Invalid hints iterator" ); 122} 123const result :EntropyValues = { 124brands :copyBrands ( current . brands ), 125mobile :current . mobile , 126platform :current . platform , 127}; 128while ( true ) { 129const step = apply ( next , iterator , []); 130if ( ! isObject ( step )) throw new TypeError ( "Invalid hints iterator result" ); 131if ( step . done ) break ; 132const hint = usv ( step . value ); 133if ( hint === "architecture" ) result . architecture = current . architecture ; 134else if ( hint === "bitness" ) result . bitness = current . bitness ; 135else if ( hint === "model" ) result . model = current . model ; 136else if ( hint === "platformVersion" ) { 137result . platformVersion = current . platformVersion ; 138} else if ( hint === "uaFullVersion" ) { 139result . uaFullVersion = current . uaFullVersion ; 140} else if ( hint === "fullVersionList" ) { 141result . fullVersionList = copyBrands ( current . fullVersionList ); 142} else if ( hint === "wow64" ) result . wow64 = current . wow64 ; 143} 144return result ; 145} 146toJSON () :Pick < UserAgentData , "brands" | "mobile" | "platform" > { 147const current = state ( uaDataStates , this ); 148return { 149brands :copyBrands ( current . brands ), 150mobile :current . mobile , 151platform :current . platform , 152}; 153} 154} 155 156const uaData = new NavigatorUAData ( secret ); 157 158class WorkerNavigator { 159constructor ( key :typeof secret ); 160constructor () { 161if ( arguments [ 0 ] !== secret ) throw new TypeError ( "Illegal constructor" ); 162set ( navigators , this , metadata ); 163} 164get appCodeName () { 165state ( navigators , this ); 166return "Mozilla" ; 167} 168get appName () { 169state ( navigators , this ); 170return "Netscape" ; 171} 172get appVersion () { 173state ( navigators , this ); 174return "4.0" ; 175} 176get platform () { 177return state ( navigators , this ). platform ; 178} 179get product () { 180state ( navigators , this ); 181return "Gecko" ; 182} 183get userAgent () { 184state ( navigators , this ); 185return userAgent ; 186} 187set userAgent ( value ) { 188state ( navigators , this ); 189userAgent = string ( value ); 190} 191get language () { 192state ( navigators , this ); 193return languages [ 0 ]; 194} 195get languages () { 196state ( navigators , this ); 197return languages ; 198} 199get hardwareConcurrency () { 200return state ( navigators , this ). hardwareConcurrency ; 201} 202get onLine () { 203state ( navigators , this ); 204return true ; 205} 206get userAgentData () { 207state ( navigators , this ); 208return uaData ; 209} 210} 211 212const navigator = new WorkerNavigator ( secret ); 213export { navigator , NavigatorUAData , userAgent , WorkerNavigator };