├── src ├── manifest.json └── injected-javascript.js ├── LICENSE └── README.rst /src/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "content_scripts": [ 3 | { 4 | "js": [ 5 | "injected-javascript.js" 6 | ], 7 | "matches": [ 8 | "" 9 | ], 10 | "run_at": "document_start" 11 | } 12 | ], 13 | "manifest_version": 2, 14 | "name": "modify-page", 15 | "version": "1.0" 16 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | This software uses parts of the webgl-mock.js library: Copyright (c) 2016 Kevin Birk 4 | 5 | Copyright (c) 2018 GimmiCOOKIE 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining a copy 8 | of this software and associated documentation files (the "Software"), to deal 9 | in the Software without restriction, including without limitation the rights 10 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | copies of the Software, and to permit persons to whom the Software is 12 | furnished to do so, subject to the following conditions: 13 | 14 | The above copyright notice and this permission notice shall be included in all 15 | copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | SOFTWARE. 24 | -------------------------------------------------------------------------------- /README.rst: -------------------------------------------------------------------------------- 1 | ============= 2 | spoofHeadless 3 | ============= 4 | WebExtension that spoofs some webGl data and few other features unique to headless browsers, so they'll be harder to detect/fingerprint 5 | 6 | * sets navigator.webdriver to false 7 | * sets navigator.languages to random value 8 | * emulates some webGL 1.0 functions/extensions (for best results use with Canvas Defender) 9 | * returns random height/width from broken images 10 | * supports hairline (css modernizr) 11 | 12 | ------- 13 | Usage 14 | ------- 15 | 16 | 1. Zip files from src **zip -rj extension.zip src/\*** 17 | 2. Change archive extension to \*.xpi **mv extension.zip extension.xpi** 18 | 3. Load into webdriver 19 | 20 | .. code-block:: 21 | 22 | from selenium import webdriver 23 | 24 | options = webdriver.FirefoxOptions() 25 | options.add_argument('--headless') 26 | 27 | driver = webdriver.Firefox(firefox_options=options) 28 | extension_path = 'path_to_extension_in_xpi_format' 29 | # True flag enables installation of unsigned extensions 30 | driver.install_addon(extension_path, True) 31 | # Check what data is spoofed 32 | driver.get('https://browserleaks.com/webgl') 33 | driver.quit() 34 | 35 | *Tip: for best results use with extension like CanvasBlocker* 36 | 37 | ----- 38 | TODO 39 | ----- 40 | 41 | * implement more webGL functions/extensions 42 | * find a way to return fake webGl hash for generated canva 43 | -------------------------------------------------------------------------------- /src/injected-javascript.js: -------------------------------------------------------------------------------- 1 | var scriptCode = '(' + function () { 2 | // get random element from input list 3 | function get_random_item(list) { 4 | return list[Math.floor((Math.random() * list.length))]; 5 | } 6 | function get_random_items(list, n) { 7 | var result = new Array(n), 8 | len = list.length, 9 | taken = new Array(len); 10 | if (n > len) 11 | n = len 12 | while (n--) { 13 | var x = Math.floor(Math.random() * len); 14 | result[n] = list[x in taken ? taken[x] : x]; 15 | taken[x] = --len in taken ? taken[len] : len; 16 | } 17 | return result; 18 | } 19 | // ensure langauge is set 20 | Object.defineProperty(navigator, 'languages', { 21 | get: function () { 22 | var availableLanguages = Array('en', 'pl', 'cs', 'ru', 'fr', 'fr-fr', 'lb', 'no') 23 | return ['en-US', get_random_item(availableLanguages)]; 24 | }, 25 | }); 26 | // fake webdriver property (headless has it as true) 27 | Object.defineProperty(navigator, 'webdriver', { 28 | get: () => false, 29 | }); 30 | 31 | // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! WebGlRenderingContext 32 | var functions = [ 33 | 'viewport', 34 | 'vertexAttribPointer', 35 | 'vertexAttrib4fv', 36 | 'vertexAttrib4f', 37 | 'vertexAttrib3fv', 38 | 'vertexAttrib3f', 39 | 'vertexAttrib2fv', 40 | 'vertexAttrib2f', 41 | 'vertexAttrib1fv', 42 | 'vertexAttrib1f', 43 | 'validateProgram', 44 | 'useProgram', 45 | 'uniformMatrix4fv', 46 | 'uniformMatrix3fv', 47 | 'uniformMatrix2fv', 48 | 'uniform4iv', 49 | 'uniform4i', 50 | 'uniform4fv', 51 | 'uniform4f', 52 | 'uniform3iv', 53 | 'uniform3i', 54 | 'uniform3fv', 55 | 'uniform3f', 56 | 'uniform2iv', 57 | 'uniform2i', 58 | 'uniform2fv', 59 | 'uniform2f', 60 | 'uniform1iv', 61 | 'uniform1i', 62 | 'uniform1fv', 63 | 'uniform1f', 64 | 'texSubImage2D', 65 | 'texParameteri', 66 | 'texParameterf', 67 | 'texImage2D', 68 | 'stencilOpSeparate', 69 | 'stencilOp', 70 | 'stencilMaskSeparate', 71 | 'stencilMask', 72 | 'stencilFuncSeparate', 73 | 'stencilFunc', 74 | 'shaderSource', 75 | 'scissor', 76 | 'sampleCoverage', 77 | 'renderbufferStorage', 78 | 'readPixels', 79 | 'polygonOffset', 80 | 'pixelStorei', 81 | 'linkProgram', 82 | 'lineWidth', 83 | 'isTexture', 84 | 'isShader', 85 | 'isRenderbuffer', 86 | 'isProgram', 87 | 'isFramebuffer', 88 | 'isEnabled', 89 | 'isContextLost', 90 | 'isBuffer', 91 | 'hint', 92 | 'getVertexAttribOffset', 93 | 'getVertexAttrib', 94 | 'getUniformLocation', 95 | 'getUniform', 96 | 'getTexParameter', 97 | 'getSupportedExtensions', 98 | 'getShaderSource', 99 | 'getShaderPrecisionFormat', 100 | 'getShaderParameter', 101 | 'getShaderInfoLog', 102 | 'getRenderbufferParameter', 103 | 'getProgramParameter', 104 | 'getProgramInfoLog', 105 | 'getParameter', 106 | 'getFramebufferAttachmentParameter', 107 | 'getExtension', 108 | 'getError', 109 | 'getContextAttributes', 110 | 'getBufferParameter', 111 | 'getAttribLocation', 112 | 'getAttachedShaders', 113 | 'getActiveUniform', 114 | 'getActiveAttrib', 115 | 'generateMipmap', 116 | 'frontFace', 117 | 'framebufferTexture2D', 118 | 'framebufferRenderbuffer', 119 | 'flush', 120 | 'finish', 121 | 'enableVertexAttribArray', 122 | 'enable', 123 | 'drawElements', 124 | 'drawArrays', 125 | 'disableVertexAttribArray', 126 | 'disable', 127 | 'detachShader', 128 | 'depthRange', 129 | 'depthMask', 130 | 'depthFunc', 131 | 'deleteTexture', 132 | 'deleteShader', 133 | 'deleteRenderbuffer', 134 | 'deleteProgram', 135 | 'deleteFramebuffer', 136 | 'deleteBuffer', 137 | 'cullFace', 138 | 'createTexture', 139 | 'createShader', 140 | 'createRenderbuffer', 141 | 'createProgram', 142 | 'createFramebuffer', 143 | 'createBuffer', 144 | 'copyTexSubImage2D', 145 | 'copyTexImage2D', 146 | 'compressedTexSubImage2D', 147 | 'compressedTexImage2D', 148 | 'compileShader', 149 | 'colorMask', 150 | 'clearStencil', 151 | 'clearDepth', 152 | 'clearColor', 153 | 'clear', 154 | 'checkFramebufferStatus', 155 | 'bufferSubData', 156 | 'bufferData', 157 | 'blendFuncSeparate', 158 | 'blendFunc', 159 | 'blendEquationSeparate', 160 | 'blendEquation', 161 | 'blendColor', 162 | 'bindTexture', 163 | 'bindRenderbuffer', 164 | 'bindFramebuffer', 165 | 'bindBuffer', 166 | 'bindAttribLocation', 167 | 'attachShader', 168 | 'activeTexture' 169 | ]; 170 | 171 | var enumerates = { 172 | 'ZERO': 0, 173 | 'VIEWPORT': 2978, 174 | 'VERTEX_SHADER': 35633, 175 | 'VERTEX_ATTRIB_ARRAY_TYPE': 34341, 176 | 'VERTEX_ATTRIB_ARRAY_STRIDE': 34340, 177 | 'VERTEX_ATTRIB_ARRAY_SIZE': 34339, 178 | 'VERTEX_ATTRIB_ARRAY_POINTER': 34373, 179 | 'VERTEX_ATTRIB_ARRAY_NORMALIZED': 34922, 180 | 'VERTEX_ATTRIB_ARRAY_ENABLED': 34338, 181 | 'VERTEX_ATTRIB_ARRAY_BUFFER_BINDING': 34975, 182 | 'VERSION': 7938, 183 | 'VENDOR': 7936, 184 | 'VALIDATE_STATUS': 35715, 185 | 'UNSIGNED_SHORT': 5123, 186 | 'UNSIGNED_SHORT_5_6_5': 33635, 187 | 'UNSIGNED_SHORT_5_5_5_1': 32820, 188 | 'UNSIGNED_SHORT_4_4_4_4': 32819, 189 | 'UNSIGNED_INT': 5125, 190 | 'UNSIGNED_BYTE': 5121, 191 | 'UNPACK_PREMULTIPLY_ALPHA_WEBGL': 37441, 192 | 'UNPACK_FLIP_Y_WEBGL': 37440, 193 | 'UNPACK_COLORSPACE_CONVERSION_WEBGL': 37443, 194 | 'UNPACK_ALIGNMENT': 3317, 195 | 'UNMASKED_VENDOR_WEBGL': 37445, 196 | 'UNMASKED_RENDERER_WEBGL': 37446, 197 | 'TRIANGLES': 4, 198 | 'TRIANGLE_STRIP': 5, 199 | 'TRIANGLE_FAN': 6, 200 | 'TEXTURE9': 33993, 201 | 'TEXTURE8': 33992, 202 | 'TEXTURE7': 33991, 203 | 'TEXTURE6': 33990, 204 | 'TEXTURE5': 33989, 205 | 'TEXTURE4': 33988, 206 | 'TEXTURE31': 34015, 207 | 'TEXTURE30': 34014, 208 | 'TEXTURE3': 33987, 209 | 'TEXTURE29': 34013, 210 | 'TEXTURE28': 34012, 211 | 'TEXTURE27': 34011, 212 | 'TEXTURE26': 34010, 213 | 'TEXTURE25': 34009, 214 | 'TEXTURE24': 34008, 215 | 'TEXTURE23': 34007, 216 | 'TEXTURE22': 34006, 217 | 'TEXTURE21': 34005, 218 | 'TEXTURE20': 34004, 219 | 'TEXTURE2': 33986, 220 | 'TEXTURE19': 34003, 221 | 'TEXTURE18': 34002, 222 | 'TEXTURE17': 34001, 223 | 'TEXTURE16': 34000, 224 | 'TEXTURE15': 33999, 225 | 'TEXTURE14': 33998, 226 | 'TEXTURE13': 33997, 227 | 'TEXTURE12': 33996, 228 | 'TEXTURE11': 33995, 229 | 'TEXTURE10': 33994, 230 | 'TEXTURE1': 33985, 231 | 'TEXTURE0': 33984, 232 | 'TEXTURE': 5890, 233 | 'TEXTURE_WRAP_T': 10243, 234 | 'TEXTURE_WRAP_S': 10242, 235 | 'TEXTURE_MIN_FILTER': 10241, 236 | 'TEXTURE_MAG_FILTER': 10240, 237 | 'TEXTURE_CUBE_MAP': 34067, 238 | 'TEXTURE_CUBE_MAP_POSITIVE_Z': 34073, 239 | 'TEXTURE_CUBE_MAP_POSITIVE_Y': 34071, 240 | 'TEXTURE_CUBE_MAP_POSITIVE_X': 34069, 241 | 'TEXTURE_CUBE_MAP_NEGATIVE_Z': 34074, 242 | 'TEXTURE_CUBE_MAP_NEGATIVE_Y': 34072, 243 | 'TEXTURE_CUBE_MAP_NEGATIVE_X': 34070, 244 | 'TEXTURE_BINDING_CUBE_MAP': 34068, 245 | 'TEXTURE_BINDING_2D': 32873, 246 | 'TEXTURE_2D': 3553, 247 | 'SUBPIXEL_BITS': 3408, 248 | 'STREAM_DRAW': 35040, 249 | 'STENCIL_WRITEMASK': 2968, 250 | 'STENCIL_VALUE_MASK': 2963, 251 | 'STENCIL_TEST': 2960, 252 | 'STENCIL_REF': 2967, 253 | 'STENCIL_PASS_DEPTH_PASS': 2966, 254 | 'STENCIL_PASS_DEPTH_FAIL': 2965, 255 | 'STENCIL_INDEX8': 36168, 256 | 'STENCIL_INDEX': 6401, 257 | 'STENCIL_FUNC': 2962, 258 | 'STENCIL_FAIL': 2964, 259 | 'STENCIL_CLEAR_VALUE': 2961, 260 | 'STENCIL_BUFFER_BIT': 1024, 261 | 'STENCIL_BITS': 3415, 262 | 'STENCIL_BACK_WRITEMASK': 36005, 263 | 'STENCIL_BACK_VALUE_MASK': 36004, 264 | 'STENCIL_BACK_REF': 36003, 265 | 'STENCIL_BACK_PASS_DEPTH_PASS': 34819, 266 | 'STENCIL_BACK_PASS_DEPTH_FAIL': 34818, 267 | 'STENCIL_BACK_FUNC': 34816, 268 | 'STENCIL_BACK_FAIL': 34817, 269 | 'STENCIL_ATTACHMENT': 36128, 270 | 'STATIC_DRAW': 35044, 271 | 'SRC_COLOR': 768, 272 | 'SRC_ALPHA': 770, 273 | 'SRC_ALPHA_SATURATE': 776, 274 | 'SHORT': 5122, 275 | 'SHADING_LANGUAGE_VERSION': 35724, 276 | 'SHADER_TYPE': 35663, 277 | 'SCISSOR_TEST': 3089, 278 | 'SCISSOR_BOX': 3088, 279 | 'SAMPLES': 32937, 280 | 'SAMPLER_CUBE': 35680, 281 | 'SAMPLER_2D': 35678, 282 | 'SAMPLE_COVERAGE': 32928, 283 | 'SAMPLE_COVERAGE_VALUE': 32938, 284 | 'SAMPLE_COVERAGE_INVERT': 32939, 285 | 'SAMPLE_BUFFERS': 32936, 286 | 'SAMPLE_ALPHA_TO_COVERAGE': 32926, 287 | 'RGBA4': 32854, 288 | 'RGBA': 6408, 289 | 'RGB565': 36194, 290 | 'RGB5_A1': 32855, 291 | 'RGB': 6407, 292 | 'REPLACE': 7681, 293 | 'REPEAT': 10497, 294 | 'RENDERER': 7937, 295 | 'RENDERBUFFER': 36161, 296 | 'RENDERBUFFER_WIDTH': 36162, 297 | 'RENDERBUFFER_STENCIL_SIZE': 36181, 298 | 'RENDERBUFFER_RED_SIZE': 36176, 299 | 'RENDERBUFFER_INTERNAL_FORMAT': 36164, 300 | 'RENDERBUFFER_HEIGHT': 36163, 301 | 'RENDERBUFFER_GREEN_SIZE': 36177, 302 | 'RENDERBUFFER_DEPTH_SIZE': 36180, 303 | 'RENDERBUFFER_BLUE_SIZE': 36178, 304 | 'RENDERBUFFER_BINDING': 36007, 305 | 'RENDERBUFFER_ALPHA_SIZE': 36179, 306 | 'RED_BITS': 3410, 307 | 'POLYGON_OFFSET_UNITS': 10752, 308 | 'POLYGON_OFFSET_FILL': 32823, 309 | 'POLYGON_OFFSET_FACTOR': 32824, 310 | 'POINTS': 0, 311 | 'PACK_ALIGNMENT': 3333, 312 | 'OUT_OF_MEMORY': 1285, 313 | 'ONE': 1, 314 | 'ONE_MINUS_SRC_COLOR': 769, 315 | 'ONE_MINUS_SRC_ALPHA': 771, 316 | 'ONE_MINUS_DST_COLOR': 775, 317 | 'ONE_MINUS_DST_ALPHA': 773, 318 | 'ONE_MINUS_CONSTANT_COLOR': 32770, 319 | 'ONE_MINUS_CONSTANT_ALPHA': 32772, 320 | 'NOTEQUAL': 517, 321 | 'NONE': 0, 322 | 'NO_ERROR': 0, 323 | 'NICEST': 4354, 324 | 'NEVER': 512, 325 | 'NEAREST': 9728, 326 | 'NEAREST_MIPMAP_NEAREST': 9984, 327 | 'NEAREST_MIPMAP_LINEAR': 9986, 328 | 'MIRRORED_REPEAT': 33648, 329 | 'MEDIUM_INT': 36340, 330 | 'MEDIUM_FLOAT': 36337, 331 | 'MAX_VIEWPORT_DIMS': 3386, 332 | 'MAX_VERTEX_UNIFORM_VECTORS': 36347, 333 | 'MAX_VERTEX_TEXTURE_IMAGE_UNITS': 35660, 334 | 'MAX_VERTEX_ATTRIBS': 34921, 335 | 'MAX_VARYING_VECTORS': 36348, 336 | 'MAX_TEXTURE_SIZE': 3379, 337 | 'MAX_TEXTURE_IMAGE_UNITS': 34930, 338 | 'MAX_RENDERBUFFER_SIZE': 34024, 339 | 'MAX_FRAGMENT_UNIFORM_VECTORS': 36349, 340 | 'MAX_CUBE_MAP_TEXTURE_SIZE': 34076, 341 | 'MAX_COMBINED_TEXTURE_IMAGE_UNITS': 35661, 342 | 'LUMINANCE': 6409, 343 | 'LUMINANCE_ALPHA': 6410, 344 | 'LOW_INT': 36339, 345 | 'LOW_FLOAT': 36336, 346 | 'LINK_STATUS': 35714, 347 | 'LINES': 1, 348 | 'LINEAR': 9729, 349 | 'LINEAR_MIPMAP_NEAREST': 9985, 350 | 'LINEAR_MIPMAP_LINEAR': 9987, 351 | 'LINE_WIDTH': 2849, 352 | 'LINE_STRIP': 3, 353 | 'LINE_LOOP': 2, 354 | 'LESS': 513, 355 | 'LEQUAL': 515, 356 | 'KEEP': 7680, 357 | 'INVERT': 5386, 358 | 'INVALID_VALUE': 1281, 359 | 'INVALID_OPERATION': 1282, 360 | 'INVALID_FRAMEBUFFER_OPERATION': 1286, 361 | 'INVALID_ENUM': 1280, 362 | 'INT': 5124, 363 | 'INT_VEC4': 35669, 364 | 'INT_VEC3': 35668, 365 | 'INT_VEC2': 35667, 366 | 'INCR': 7682, 367 | 'INCR_WRAP': 34055, 368 | 'IMPLEMENTATION_COLOR_READ_TYPE': 35738, 369 | 'IMPLEMENTATION_COLOR_READ_FORMAT': 35739, 370 | 'HIGH_INT': 36341, 371 | 'HIGH_FLOAT': 36338, 372 | 'GREEN_BITS': 3411, 373 | 'GREATER': 516, 374 | 'GEQUAL': 518, 375 | 'GENERATE_MIPMAP_HINT': 33170, 376 | 'FUNC_SUBTRACT': 32778, 377 | 'FUNC_REVERSE_SUBTRACT': 32779, 378 | 'FUNC_ADD': 32774, 379 | 'FRONT': 1028, 380 | 'FRONT_FACE': 2886, 381 | 'FRONT_AND_BACK': 1032, 382 | 'FRAMEBUFFER': 36160, 383 | 'FRAMEBUFFER_UNSUPPORTED': 36061, 384 | 'FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT': 36055, 385 | 'FRAMEBUFFER_INCOMPLETE_DIMENSIONS': 36057, 386 | 'FRAMEBUFFER_INCOMPLETE_ATTACHMENT': 36054, 387 | 'FRAMEBUFFER_COMPLETE': 36053, 388 | 'FRAMEBUFFER_BINDING': 36006, 389 | 'FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL': 36050, 390 | 'FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE': 36051, 391 | 'FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE': 36048, 392 | 'FRAMEBUFFER_ATTACHMENT_OBJECT_NAME': 36049, 393 | 'FRAGMENT_SHADER': 35632, 394 | 'FLOAT': 5126, 395 | 'FLOAT_VEC4': 35666, 396 | 'FLOAT_VEC3': 35665, 397 | 'FLOAT_VEC2': 35664, 398 | 'FLOAT_MAT4': 35676, 399 | 'FLOAT_MAT3': 35675, 400 | 'FLOAT_MAT2': 35674, 401 | 'FASTEST': 4353, 402 | 'EQUAL': 514, 403 | 'ELEMENT_ARRAY_BUFFER': 34963, 404 | 'ELEMENT_ARRAY_BUFFER_BINDING': 34965, 405 | 'DYNAMIC_DRAW': 35048, 406 | 'DST_COLOR': 774, 407 | 'DST_ALPHA': 772, 408 | 'DONT_CARE': 4352, 409 | 'DITHER': 3024, 410 | 'DEPTH_WRITEMASK': 2930, 411 | 'DEPTH_TEST': 2929, 412 | 'DEPTH_STENCIL': 34041, 413 | 'DEPTH_STENCIL_ATTACHMENT': 33306, 414 | 'DEPTH_RANGE': 2928, 415 | 'DEPTH_FUNC': 2932, 416 | 'DEPTH_COMPONENT16': 33189, 417 | 'DEPTH_COMPONENT': 6402, 418 | 'DEPTH_CLEAR_VALUE': 2931, 419 | 'DEPTH_BUFFER_BIT': 256, 420 | 'DEPTH_BITS': 3414, 421 | 'DEPTH_ATTACHMENT': 36096, 422 | 'DELETE_STATUS': 35712, 423 | 'DECR': 7683, 424 | 'DECR_WRAP': 34056, 425 | 'CW': 2304, 426 | 'CURRENT_VERTEX_ATTRIB': 34342, 427 | 'CURRENT_PROGRAM': 35725, 428 | 'CULL_FACE': 2884, 429 | 'CULL_FACE_MODE': 2885, 430 | 'CONTEXT_LOST_WEBGL': 37442, 431 | 'CONSTANT_COLOR': 32769, 432 | 'CONSTANT_ALPHA': 32771, 433 | 'COMPRESSED_TEXTURE_FORMATS': 34467, 434 | 'COMPILE_STATUS': 35713, 435 | 'COLOR_WRITEMASK': 3107, 436 | 'COLOR_CLEAR_VALUE': 3106, 437 | 'COLOR_BUFFER_BIT': 16384, 438 | 'COLOR_ATTACHMENT0': 36064, 439 | 'CLAMP_TO_EDGE': 33071, 440 | 'CCW': 2305, 441 | 'BYTE': 5120, 442 | 'BUFFER_USAGE': 34661, 443 | 'BUFFER_SIZE': 34660, 444 | 'BROWSER_DEFAULT_WEBGL': 37444, 445 | 'BOOL': 35670, 446 | 'BOOL_VEC4': 35673, 447 | 'BOOL_VEC3': 35672, 448 | 'BOOL_VEC2': 35671, 449 | 'BLUE_BITS': 3412, 450 | 'BLEND': 3042, 451 | 'BLEND_SRC_RGB': 32969, 452 | 'BLEND_SRC_ALPHA': 32971, 453 | 'BLEND_EQUATION': 32777, 454 | 'BLEND_EQUATION_RGB': 32777, 455 | 'BLEND_EQUATION_ALPHA': 34877, 456 | 'BLEND_DST_RGB': 32968, 457 | 'BLEND_DST_ALPHA': 32970, 458 | 'BLEND_COLOR': 32773, 459 | 'BACK': 1029, 460 | 'ATTACHED_SHADERS': 35717, 461 | 'ARRAY_BUFFER': 34962, 462 | 'ARRAY_BUFFER_BINDING': 34964, 463 | 'ALWAYS': 519, 464 | 'ALPHA': 6406, 465 | 'ALPHA_BITS': 3413, 466 | 'ALIASED_POINT_SIZE_RANGE': 33901, 467 | 'ALIASED_LINE_WIDTH_RANGE': 33902, 468 | 'ACTIVE_UNIFORMS': 35718, 469 | 'ACTIVE_TEXTURE': 34016, 470 | 'ACTIVE_ATTRIBUTES': 35721 471 | }; 472 | 473 | function loseContext () { 474 | } 475 | function restoreContext () { 476 | } 477 | function drawBuffersWEBGL () { 478 | } 479 | 480 | var extensions = { 481 | // ratified 482 | 'OES_texture_float': {}, 483 | 'OES_texture_half_float': {}, 484 | 'WEBGL_lose_context': { 485 | loseContext, 486 | restoreContext 487 | }, 488 | 'OES_standard_derivatives': {}, 489 | 'OES_vertex_array_object': {}, 490 | 'WEBGL_debug_renderer_info': { 491 | 'UNMASKED_VENDOR_WEBGL': 37445, 492 | 'UNMASKED_RENDERER_WEBGL': 37446 493 | }, 494 | 'WEBGL_debug_shaders': {}, 495 | 'WEBGL_depth_texture': {}, 496 | 'OES_element_index_uint': {}, 497 | 'EXT_texture_filter_anisotropic': { 498 | 'MAX_TEXTURE_MAX_ANISOTROPY_EXT': 34047, 499 | 'TEXTURE_MAX_ANISOTROPY_EXT': 34046 500 | }, 501 | 'EXT_frag_depth': {}, 502 | 'WEBGL_draw_buffers': { 503 | 'MAX_DRAW_BUFFERS_WEBGL': 34852, 504 | 'MAX_COLOR_ATTACHMENTS_WEBGL': 36063, 505 | 'DRAW_BUFFER9_WEBGL': 34862, 506 | 'DRAW_BUFFER8_WEBGL': 34861, 507 | 'DRAW_BUFFER7_WEBGL': 34860, 508 | 'DRAW_BUFFER6_WEBGL': 34859, 509 | 'DRAW_BUFFER5_WEBGL': 34858, 510 | 'DRAW_BUFFER4_WEBGL': 34857, 511 | 'DRAW_BUFFER3_WEBGL': 34856, 512 | 'DRAW_BUFFER2_WEBGL': 34855, 513 | 'DRAW_BUFFER15_WEBGL': 34868, 514 | 'DRAW_BUFFER14_WEBGL': 34867, 515 | 'DRAW_BUFFER13_WEBGL': 34866, 516 | 'DRAW_BUFFER12_WEBGL': 34865, 517 | 'DRAW_BUFFER11_WEBGL': 34864, 518 | 'DRAW_BUFFER10_WEBGL': 34863, 519 | 'DRAW_BUFFER1_WEBGL': 34854, 520 | 'DRAW_BUFFER0_WEBGL': 34853, 521 | 'COLOR_ATTACHMENT9_WEBGL': 36073, 522 | 'COLOR_ATTACHMENT8_WEBGL': 36072, 523 | 'COLOR_ATTACHMENT7_WEBGL': 36071, 524 | 'COLOR_ATTACHMENT6_WEBGL': 36070, 525 | 'COLOR_ATTACHMENT5_WEBGL': 36069, 526 | 'COLOR_ATTACHMENT4_WEBGL': 36068, 527 | 'COLOR_ATTACHMENT3_WEBGL': 36067, 528 | 'COLOR_ATTACHMENT2_WEBGL': 36066, 529 | 'COLOR_ATTACHMENT15_WEBGL': 36079, 530 | 'COLOR_ATTACHMENT14_WEBGL': 36078, 531 | 'COLOR_ATTACHMENT13_WEBGL': 36077, 532 | 'COLOR_ATTACHMENT12_WEBGL': 36076, 533 | 'COLOR_ATTACHMENT11_WEBGL': 36075, 534 | 'COLOR_ATTACHMENT10_WEBGL': 36074, 535 | 'COLOR_ATTACHMENT1_WEBGL': 36065, 536 | 'COLOR_ATTACHMENT0_WEBGL': 36064, 537 | drawBuffersWEBGL 538 | }, 539 | 'ANGLE_instanced_arrays': null, 540 | 'OES_texture_float_linear': {}, 541 | 'OES_texture_half_float_linear': {}, 542 | 'EXT_blend_minmax': {}, 543 | 'EXT_shader_texture_lod': {}, 544 | 'WEBGL_compressed_texture_atc': null, 545 | 'WEBGL_compressed_texture_pvrtc': null, 546 | 'EXT_color_buffer_half_float': {}, 547 | 'WEBGL_color_buffer_float': {}, 548 | 'EXT_sRGB': {}, 549 | 'WEBGL_compressed_texture_etc1': null, 550 | 'WEBGL_compressed_texture_astc': {}, 551 | 'WEBGL_compressed_texture_etc': {}, 552 | 'WEBGL_compressed_texture_s3tc': {}, 553 | 'WEBGL_compressed_texture_s3tc_srgb': {}, 554 | }; 555 | 556 | function WebGLRenderingContext(canvas) { 557 | this.canvas = canvas; 558 | this.drawingBufferWidth = canvas.width; 559 | this.drawingBufferHeight = canvas.height; 560 | }; 561 | 562 | functions.forEach(function (func) { 563 | WebGLRenderingContext.prototype[func] = function () { 564 | return {}; 565 | }; 566 | }); 567 | 568 | Object.keys(enumerates).forEach(function (key) { 569 | WebGLRenderingContext.prototype[key] = enumerates[key]; 570 | }); 571 | 572 | WebGLRenderingContext.prototype.getExtension = function (ext) { 573 | console.log("WebGLRenderingContext.getExtension" + ext); 574 | return extensions[ext]; 575 | }; 576 | 577 | try { 578 | const getContext = HTMLCanvasElement.prototype.getContext; 579 | HTMLCanvasElement.prototype.getContext = function () { 580 | var name = arguments[0]; 581 | console.log("HTMLCanvasElement app requested extension: " + name); 582 | console.log(JSON.stringify(arguments, null, 4)); 583 | if (name == 'webgl' || name == 'webgl-experimental' || name == 'experimental-webgl' || name == 'moz-webgl') { 584 | var y = new WebGLRenderingContext(this); 585 | console.log("WEBGL " + y); 586 | console.log(JSON.stringify(y, null, 4)); 587 | return y; 588 | } 589 | if (name == 'webgl2' || name == 'experimental-webgl2' || name == 'fake-webgl') { 590 | console.log("WEBGL2") 591 | return null; 592 | } 593 | var ext = getContext.apply(this, arguments); 594 | console.log("HTMLCanvasElement extension " + name + " " + (ext ? "found" : "not found")); 595 | console.log(ext); 596 | return ext; 597 | } 598 | } catch (e) { } 599 | 600 | // fake webgl rendering 601 | try { 602 | const getParameter = WebGLRenderingContext.prototype.getParameter; 603 | WebGLRenderingContext.prototype.getParameter = function () { 604 | var name = arguments[0]; 605 | console.log("WebGLRenderingContext - getParameter: " + name); 606 | // https://developer.mozilla.org/en-US/docs/Web/API/WebGL_API/Constants 607 | // UNMASKED_VENDOR_WEBGL 608 | if (name == 37445) { 609 | // UNMASKED_VENDOR_WEBGL 610 | var options = ['Intel Open Source Technology Center', 'X.Org', 'Vendor Google Inc.']; 611 | return get_random_item(options); 612 | } else if (name == 37446) { 613 | // UNMASKED_RENDERER_WEBGL 614 | var options = ['Mesa DRI Intel(R) Ivybridge Mobile', 'AMD KAVERI (DRM 2.43.0 / 4.4.0-119-generic, LLVM 5.0.0)', 'Renderer Google SwiftShader', 'AMD ARUBA (DRM 2.43.0 / 4.4.0-119-generic, LLVM 5.0.0)', 'Mesa DRI Intel(R) HD Graphics 630 (Kaby Lake GT2)', 'Gallium 0.4 on AMD KAVERI (DRM 2.43.0 / 4.4.0-83-generic, LLVM 3.8.0)']; 615 | return get_random_item(options); 616 | } else if (name == 7937 || name == 7936) { 617 | // RENDERER // VENDOR 618 | return 'Mozilla'; 619 | } else if (name == 35724) { 620 | // SHADING_LANGUAGE_VERSION 621 | return 'WebGL GLSL ES 1.0'; 622 | } else if (name == 7937 || name == 7938) { 623 | // VERSION 624 | return 'WebGL 1.0'; 625 | } else if (name == 7937 || name == 33901 || name == 33902) { 626 | // ALIASED_LINE_WIDTH_RANGE // ALIASED_POINT_SIZE_RANGE 627 | var option = new Float32Array([1, 8192]); 628 | return option; 629 | } else if (name == 3413 || name == 3412 || name == 3411 || name == 3410 || name == 34852) { 630 | return get_random_item([2, 4, 8, 16]); 631 | } else if (name == 3415) { 632 | return 0; 633 | } else if (name == 3414) { 634 | return 24; 635 | } else if (name == 34047 || name == 34921) { 636 | // MAX_TEXTURE_MAX_ANISOTROPY_EXT // MAX_VERTEX_ATTRIBS 637 | return get_random_items([2, 4, 8, 16]); 638 | } else if (name == 35661) { 639 | // MAX_COMBINED_TEXTURE_IMAGE_UNITS 640 | return get_random_items([128, 192, 256]); 641 | } else if (name == 34076 || name == 34024 || name == 3379) { 642 | // MAX_CUBE_MAP_TEXTURE_SIZE // MAX_RENDERBUFFER_SIZE 643 | return get_random_item([16384, 32768]) ; 644 | } else if (name == 36349 || name == 36347) { 645 | // MAX_FRAGMENT_UNIFORM_VECTORS // MAX_VERTEX_UNIFORM_VECTORS 646 | return get_random_item([4096, 8192]); 647 | } else if (name == 34930 || name == 36348 || name == 35660) { 648 | // MAX_TEXTURE_IMAGE_UNITS // MAX_VARYING_VECTORS // MAX_VERTEX_TEXTURE_IMAGE_UNITS 649 | return get_random_item([16, 32, 64]); 650 | } else if (name == 3386) { 651 | var value = get_random_item([8192, 16384, 32768]) 652 | var options = new Int32Array([value, value]); 653 | return options; 654 | } else if (name == 3415) { 655 | return 0; 656 | } else { 657 | console.log("Retuning random value for: " + name); 658 | return get_random_item([0, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096]); 659 | } 660 | var ext = getParameter.apply(this, arguments); 661 | console.log("WebGLRenderingContext extension " + name + " " + (ext ? "found" : "not found")); 662 | console.log(JSON.stringify(ext, null, 4)); 663 | 664 | return ext; 665 | } 666 | } catch (a) { } 667 | 668 | const getSupportedExtensions = WebGLRenderingContext.prototype.getSupportedExtensions; 669 | WebGLRenderingContext.prototype.getSupportedExtensions = function () { 670 | try { 671 | console.log("WebGLRenderingContext.getSupportedExtensions") 672 | var availableExtensions = Object.keys(extensions); 673 | console.log(availableExtensions); 674 | var itemsToGet = Math.floor(Math.random() * (availableExtensions.length - 6) + 5); 675 | console.log(itemsToGet); 676 | var selectedExtensions = get_random_items(availableExtensions, itemsToGet); 677 | console.log(selectedExtensions); 678 | return selectedExtensions; 679 | } catch (a) { 680 | console.log(a) 681 | return Object.keys(extensions); 682 | } 683 | } 684 | // in case of broken image return random height/width 685 | var size = 0; 686 | ['height', 'width'].forEach(property => { 687 | const imageDescriptor = Object.getOwnPropertyDescriptor(HTMLImageElement.prototype, property); 688 | Object.defineProperty(HTMLImageElement.prototype, property, { 689 | imageDescriptor, 690 | get: function () { 691 | if (this.complete && this.naturalHeight == 0) { 692 | if (!size) { 693 | size = Math.floor(Math.random() * (30 - 10 + 1)) + 10; 694 | } 695 | return size; 696 | } 697 | return imageDescriptor.get.apply(this); 698 | }, 699 | }); 700 | }); 701 | // hairline feature (headless can't render it normally) 702 | const imageDescriptor = Object.getOwnPropertyDescriptor(HTMLElement.prototype, 'offsetHeight'); 703 | Object.defineProperty(HTMLElement.prototype, 'offsetHeight', { 704 | ...imageDescriptor, 705 | get: function () { 706 | if (this.id == 'modernizr') { 707 | return 1; 708 | } 709 | return imageDescriptor.get.apply(this); 710 | }, 711 | }); 712 | } + ')();'; 713 | 714 | var script = document.createElement('script'); 715 | script.textContent = scriptCode; 716 | (document.head || document.documentElement).appendChild(script); 717 | script.remove(); --------------------------------------------------------------------------------