Skip to content

LibWeb: Cloudflare Turnstile differences between us and other engines #226

@Lubrsi

Description

@Lubrsi
Contributor

NOTE: This is a living document, it does not contain every difference currently and will be added to.

Neat site for checking the connection side of things (not sure of trustworthiness, take it with a grain of salt): https://cloudflare.manfredi.io/en/tools/connection/

  • navigator.plugins is empty (presumably because we report no PDF support, see navigator.pdfViewerEnabled)
    navigator.mimeTypes is empty (presumably because we report no PDF support, see navigator.pdfViewerEnabled)
    Missing first-input performance entry type
    Missing paint performance entry type (including first-paint and first-contentful-paint)
    Missing navigation performance entry type
    Missing resource performance entry type (definitely needs implementing, disabling dom.enable_resource_timing in Firefox makes it never pass)
    Missing visibility-state performance entry type
    Missing long-animation-frame performance entry type
    Missing WEBGL_debug_renderer_info extension for unmasked vendor/renderer info
    Blob URLs for workers don't work, reporting DedicatedWorkerHost: Unable to fetch script blob:https://localhost:8080/c838e9e6-b238-4210-a349-9c909821d0a5 because script was null
    navigator.hardwareConcurrency always reports 1
    window.outerWidth and window.outerHeight report 0 (used in zoom calculation if it thinks we're chromium: Math.round((window.outerWidth / window.innerWidth) * 100) / 100)
    Thinks we're Firefox due to missing window.chrome and window.webkitRequestAnimationFrame, which makes it resort to probing min--moz-device-pixel-ratio via window.matchMedia for zoom calculation, and reporting "ff" in the same test
    typeof document.all is not "undefined"
    Missing screen.availTop
    Missing screen.availLeft
    Missing screen.orientation (angle, onchange, lock, unlock, type, inherits EventTarget)
    Missing screen.onchange
    Missing screen.isExtended
    Screen does not inherit EventTarget
    Missing OfflineAudioContext (random fingerprint challenge, see LibWeb: Implement OfflineAudioContext #224)
    This spec issue for WWW-Authenticate needs resolving:
    // 1. Needs testing: multiple `WWW-Authenticate` headers, missing, parsing issues.
    // (Red box in the spec, no-op)
    This spin in execute_script causes the SubtleCrypto::digest task to run out of order in the layout fingerprint challenge, effectively causing an assertion failure in the Turnstile VM:
    if (!m_document->ready_to_run_scripts())
    main_thread_event_loop().spin_until([&] { return m_document->ready_to_run_scripts(); });
    Assuming it scans all HTTP headers sent, we likely need to implement this:
    // FIXME: 13. Append the Fetch metadata headers for httpRequest.
    Additionally, the priority header, shipped in Firefox and Safari and soon for Chrome: https://chromestatus.com/feature/5109106573049856
    Missing HTMLScriptElement#async (7f0920b)
    Missing Document#lastModified
    Missing navigator.maxTouchPoints
    Missing AnalyserNode#getFloatTimeDomainData
    Missing AudioBuffer#copyFromChannel
    Missing HTMLCanvasElement#captureStream
    Missing AnalyserNode#maxDecibels
    Missing AnalyserNode#getByteTimeDomainData
    Missing CanvasRenderingContext2D#getLineDash
    Missing BiquadFilterNode#getFrequencyResponse
    Missing SVGTextContentElement#getExtentOfChar
    Missing OffscreenCanvasRenderingContext2D#isPointInStroke
    Missing Window.closed
    UIEvent.detail always reports 0 instead of the current click count
    MouseEvent.movementX and MouseEvent.movementY always reports 0
    Missing MouseEvent.relatedTarget
    Missing MouseEvent.layerX and MouseEvent.layerY
    click event doesn't dispatch a PointerEvent, but instead a MouseEvent, including synthetic clicks via Element#click (likely an issue for other events too)
    Missing PointerEvent and all of it's attributes and functions
    We don't set Event#timestamp, defaulted to 0 (at least for click event)
    <link rel="preload" as="..."> doesn't follow the spec at all, using ResourceLoader directly (missing fetch headers, missing window load event delay, etc.)
    Missing console.dirxml
    Missing console.table
    JSON.stringify(window.getComputedStyle(document.body)) returns {} instead of the serialization of all the properties and their values
    Missing WebGLRenderingContextBase.getParameter
    Missing WebGLRenderingContext2#bufferData()
    Missing WebGLRenderingContext2#readPixels()
    Content Security Policy

CSS and serialization via cssText:

  • url() function serialize with the base URL of the origin, when it shouldn't, e.g. hosted on https://localhost:8080, this:
.OwaTZc4{background-image:url('/cdn-cgi/challenge-platform/h/b/cmg/1/hV7fTYrIy7e%2FC5FuCgYHr5Utjf5x6tY32TUpCSZd1P8%3D'); background-position: -1px -1px; background-repeat:no-repeat;}

Serializes as:

.OwaTZc4 { background-image: url(\"https://localhost:8080/cdn-cgi/challenge-platform/h/b/cmg/1/hV7fTYrIy7e%2FC5FuCgYHr5Utjf5x6tY32TUpCSZd1P8%3D\"); background-position: left -1px top -1px; background-repeat: no-repeat no-repeat; }
  • Combined percentages in @keyframe are serialized separately instead of together, e.g.:
@keyframes scale {
    0%, 100% {
        transform: none;
    }
    50% {
	transform: scale3d(1, 1, 1);
    }
}

Should serialize as:

@keyframes scale { 
  0%, 100% { transform: none; }
  50% { transform: scale3d(1, 1, 1); }
}

But we serialize it as:

@keyframes "scale" {
    0% {
        transform: none;
    }

    100% {
        transform: none;
    }

    50% {
        transform: scale3d(1, 1, 1);
    }
}
  • Fail to parse and serialize multiple animations declared in one animation property, e.g. animation: fillfail 0.4s ease-in-out 0.4s forwards, scale 0.3s ease-in-out 0.9s both;

  • Some properties are serialized as full form when they shouldn't:

    • text-decoration: underline; -> text-decoration: underline auto solid currentcolor;
    • border-radius: 50%; -> border-radius: 50% 50% 50% 50% / 50% 50% 50% 50%;
    • animation: scale-up-center 0.6s cubic-bezier(0.55, 0.085, 0.68, 0.53) both; -> animation: cubic-bezier(0.55, 0.085, 0.68, 0.53) normal scale-up-center running 0s 0.6s both 1; (note that this is also serialized out of order)
    • background: #fff; -> background: rgb(255, 255, 255) none left 0% top 0% auto auto repeat repeat scroll padding-box border-box;
    • Weird one: flex-flow: column nowrap; (as specified in the actual style sheet) should serialize as flex-flow: column, but we keep it as is
    • Same with flex-flow: row nowrap; and flex-flow: row-reverse nowrap;
  • Missing stroke-dashoffset and it's serialization

    Missing stroke-linecap and it's serialization

    Missing stroke-miterlimit and it's serialization

    Missing stroke-dasharray and it's serialization

    Missing stroke-linejoin and it's serialization

    This:

margin: 0;
margin-top: 6px;
margin-left: 16px;

Should serialize as:

margin: 6px 0px 0px 16px;
  • This:
background-color: white;

Should stay as is, but we serialize it as:

background-color: rgb(255, 255, 255);

Activity

added
bugSomething isn't working
enhancementNew feature or request
reduction of web contentIssue has a simplified reduction based on real-world web content.
task listThis issue contains a list of tasks.
on Jun 20, 2024
shlyakpavel

shlyakpavel commented on Dec 7, 2024

@shlyakpavel
Contributor

As far as I understand, we have

  1. WebGLRenderingContextBase.getParameter implemented as part of f3a24d1
  2. CanvasRenderingContext2D#getLineDash implemented aș combination of e9001da and 9f71d65
Lubrsi

Lubrsi commented on Dec 28, 2024

@Lubrsi
ContributorAuthor

I cloned WebKit locally and it passes Turnstile. As an experiment to find what changes we can potentially get away with, I modified it until it stopped passing, then undid that change. From that, I found:

  • It doesn't need WebGL (i.e. return null context from HTMLCanvasElement#getContext when it's WebGL)
  • In turn, this means it doesn't need WEBGL_debug_renderer_info
  • It doesn't require <link> elements to work (I added a return to HTMLLinkElement::process, so it wouldn't even load stylesheets, let alone preloads)
  • PDF Viewer Enabled can be false (and in turn, the plugins and mimeTypes arrays can be empty)
  • Doesn't need navigation timing
  • Requires resource timing, but it doesn't really check if the values make sense. In this case, I returned 0 from requestStart, 200000 from responseEnd and 0 for both transferSize and encodedBodySize

This isn't to say that it doesn't dock points from the bot score however, though we don't have any insight into that.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingenhancementNew feature or requestreduction of web contentIssue has a simplified reduction based on real-world web content.task listThis issue contains a list of tasks.web compatibility

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

      Development

      No branches or pull requests

        Participants

        @shlyakpavel@Lubrsi

        Issue actions