fediverse-sse.js 66 lignes · 2550 octets
// RFC 0023 Slice B iter. 3 — Server-Sent Events listener for the
// fediverse login flow. Loaded from the `login_waiting.html` template.
//
// ANSSI FUI-CSP-1: previously an inline <script>, externalised so the
// global Content-Security-Policy can drop `script-src 'unsafe-inline'`
// for this template. The challenge_id is passed via a `data-*`
// attribute on the script tag itself.
(function () {
    var script = document.getElementById("fediverse-sse-script");
    if (!script) {
        return;
    }
    var challengeId = script.getAttribute("data-challenge-id");
    if (!challengeId) {
        return;
    }
    var sse = new EventSource("/login/fediverse/sse/" + challengeId);

    sse.addEventListener("status", function (ev) {
        var payload;
        try {
            payload = JSON.parse(ev.data);
        } catch (_err) {
            return;
        }
        var state = payload.state;
        if (state === "approved") {
            // L'IdP a approuvé : appeler /api/v1/auth/login/fediverse/consume/{id}
            // qui pose le cookie JWT remote, puis redirection /home.
            fetch("/api/v1/auth/login/fediverse/consume/" + challengeId, {
                method: "POST",
                credentials: "same-origin",
            })
                .then(function (r) {
                    if (r.ok) {
                        window.location.href = "/home";
                    } else {
                        window.location.href = "/login/fediverse/error?reason=unknown";
                    }
                })
                .catch(function () {
                    window.location.href = "/login/fediverse/error?reason=unknown";
                });
            sse.close();
        } else if (state === "rejected") {
            sse.close();
            window.location.href = "/login/fediverse/error?reason=rejected";
        } else if (state === "expired") {
            sse.close();
            window.location.href = "/login/fediverse/error?reason=timeout";
        } else if (state === "consumed") {
            sse.close();
            window.location.href = "/home";
        }
        // state === "pending" → rien à faire, on attend le prochain poll.
    });

    sse.onerror = function () {
        // Connexion perdue ; le serveur va relancer mais on protège
        // l'UX si le navigateur abandonne après plusieurs tentatives.
        sse.close();
        setTimeout(function () {
            window.location.href = "/login/fediverse/error?reason=timeout";
        }, 30000);
    };
})();