SerenityOS / serenity

The Serenity Operating System 🐞
https://serenityos.org
BSD 2-Clause "Simplified" License
29.77k stars 3.15k forks source link

LibWeb: Become a supported browser on Duolingo #22014

Closed awesomekling closed 2 months ago

awesomekling commented 7 months ago

We should figure out what's causing this error, and then fix it:

image

Funding

Fund with Polar

trflynn89 commented 7 months ago

Here's the (formatted) JS they use for browser support detection:

if ("/errors/not-supported.html" !== window.location.pathname) {
    for (
        var supportsAbortController =
                ("AbortController" in window) &&
                ("Request" in window) &&
                Object.hasOwnProperty.call(Request.prototype, "signal"),
            supportsElementAnimate = ("animate" in Element.prototype),
            supportsES2015 = (function () {
                if ("undefined" == typeof Symbol || "undefined" == typeof Proxy) return !1;
                try {
                    return (
                        new Function("(a = 0) => a")(),
                        new Function("class MyEvent extends Event{}")(),
                        !1 === new Function("return new Boolean(Symbol.match)")()
                            ? !1
                            : (new Function("new.target")(),
                              new Function(
                                  'class ಠ_ಠ extends Array {constructor(j = "a", ...c) {const q = (({u: e}) => {return { [`s${c}`]: Symbol(j) };})({});super(j, q, ...c);}}new Promise((f) => {const a = function* (){return "𠮷".match(/./u)[0].length === 2 || true;};for (let vre of a()) {const [uw, as, he, re] = [new Set(), new WeakSet(), new Map(), new WeakMap()];break;}f(new Proxy({}, {get: (han, h) => h in han ? han[h] : "42".repeat(0o10)}));}).then(bi => new ಠ_ಠ(bi.rd));'
                              )(),
                              !!new Function(
                                  "return (a, b,) => a.padStart(5, '0') === '0000x' && Object.values(b).length === 2"
                              )()("x", { a: 1, b: 2 }))
                    );
                } catch (e) {
                    return !1;
                }
            })(),
            supportsIntersectionObserver =
                ("IntersectionObserver" in window) &&
                ("IntersectionObserverEntry" in window) &&
                ("intersectionRatio" in window.IntersectionObserverEntry.prototype) &&
                ("isIntersecting" in window.IntersectionObserverEntry.prototype),
            supportsResizeObserver = ("ResizeObserver" in window),
            features = [
                supportsAbortController,
                supportsElementAnimate,
                supportsES2015,
                supportsIntersectionObserver,
                supportsResizeObserver,
            ],
            i = 0;
        i < features.length;
        i++
    ) {
        features[i] || (window.location.href = "/errors/not-supported.html");
    }
    (window.duo.disableMonetization = /[?&]utm_source=pwa_launch/.test(window.location.search)),
        (window.duo.l10n = { strings: {}, undeclared: {} }),
        (window.duo.uiLanguage = window.duo.uiLanguage || "en"),
        (window.duo.version = "1.195.3"),
        (window.duo.versionHash = "2a84ac2cffc51b7d784f24505baf933c63c03194");
    var isAbc = /^\/abc/.test(window.location.pathname),
        HIDE_APP_SMART_BANNER_PATH = [
            "/2022-campaigns",
            "/share/sm",
            "/share-direct/sm",
            "/super",
            "/plus",
            "/getplus",
            "/youtubeplus",
        ];
    if (HIDE_APP_SMART_BANNER_PATH.includes(window.location.pathname))
        (el = document.querySelector("[name=apple-itunes-app]")) && el.remove();
    else if (isAbc) {
        var el;
        (el = document.querySelector("[name=apple-itunes-app]")) &&
            el.setAttribute("content", "app-id=1440502568");
    }
}

Of those features, we do not implement Element.prototype.animate. So that part is #21570.

However, if I stub that out, rather than getting redirected to the error page, we get a reCAPTCHA error instead (after some timeout) :

Screenshot_20231121_220740

Lubrsi commented 7 months ago

I believe the main roadblock is missing transfer support in window.postMessage, as IIRC it creates a MessageChannel in the reCAPTCHA iframe, then transfers one of the ports to the parent window and uses that for communication.

ADKaster commented 4 months ago

After #23218, I get the same reCAPTCHA timeout failure, but it doesn't seem to be related to window.postMesage transfer support, as that should(?) work now.

90664.787 WebContent(744): ResourceLoader: Failed load of: "https://cdn.cookielaw.org/scripttemplates/otSDKStub.js", Error: URL was filtered, Duration: 1ms
90664.798 WebContent(744): HTMLScriptElement: Refusing to run script because the element's result is null.
90665.438 WebContent(744): Unhandled JavaScript exception: [ReferenceError] 'FontFace' is not defined
90665.439 WebContent(744):     at https://www.duolingo.com/:1:125
    at <unknown>
    at n (https://d35aaqx5ub95lt.cloudfront.net/js/manifest-2e205d95.js:1:157)
    at https://www.duolingo.com/:1:1196
    at a (https://d35aaqx5ub95lt.cloudfront.net/js/manifest-2e205d95.js:1:11971)
    at <unknown>
    at https://d35aaqx5ub95lt.cloudfront.net/js/manifest-2e205d95.js:1:12165
    at https://d35aaqx5ub95lt.cloudfront.net/js/manifest-2e205d95.js:1:12165
    at https://d35aaqx5ub95lt.cloudfront.net/js/manifest-2e205d95.js:1:12165

90667.153 WebContent(744): Potential FIXME: Returning from PerformanceObserver::observe() as we don't support the PerformanceEntry type 'longtask'
90667.234 WebSocket(750): Loaded 145 of 145 (100%) provided CA Certificates
90667.234 RequestServer(749): Loaded 145 of 145 (100%) provided CA Certificates
90682.154 WebContent(744): Unhandled JavaScript exception (in promise): Timeout (z)
90687.138 WebContent(744): Potential FIXME: Returning from PerformanceObserver::observe() as we don't support the PerformanceEntry type 'longtask'
90687.181 RequestServer(752): Loaded 145 of 145 (100%) provided CA Certificates
90687.181 WebSocket(754): Loaded 145 of 145 (100%) provided CA Certificates
90702.140 WebContent(744): Unhandled JavaScript exception (in promise): Timeout (z)
90706.100 WebContent(744): Unhandled JavaScript exception (in promise): Timeout
Lubrsi commented 4 months ago

IIRC reCAPTCHA requires this on MessagePort transfer: https://github.com/SerenityOS/serenity/blob/9aefc5c927be6202f49abca4d077f70657c097b2/Userland/Libraries/LibWeb/HTML/MessagePort.cpp#L68-L69 https://github.com/SerenityOS/serenity/blob/9aefc5c927be6202f49abca4d077f70657c097b2/Userland/Libraries/LibWeb/HTML/MessagePort.cpp#L101-L103

awesomekling commented 2 months ago

Thank you @ADKaster and @mattco98 for contributing to close this issue! ⭐

The rewards from this issue, totalling $200, has been shared with you.

What now?

  1. Create a Polar account
  2. See incoming rewards & setup Stripe to receive them
  3. Get payouts as backers finalize their payments

If you already have a Polar account setup, you don't need to do anything.