XFE Git
XFE Studio Git
Git 首页 全局搜索
XFE 主站 文档 NuGet

XFESystem

【Rust】XFE系统,基于Rust和汇编

公开
关注 0 Fork 0 Star 0
UTF-8
using System.Globalization;
using System.Text;
using AngleSharp.Dom;

namespace XFESystem.Browser;

public sealed partial class BrowserService
{
    private string? remoteEvidenceAddress, remoteBodySha256;
    private bool remoteCertificateValidated;
    private void RecordRemoteResponseEvidence(string? address, string? bodyHash, bool certificateValidated)
    { remoteEvidenceAddress = address; remoteBodySha256 = bodyHash; remoteCertificateValidated = certificateValidated; }

    /// <summary>Read actual DOM, loaded resources and existing layout commands on the owning worker.
    /// No script, resource load or screenshot enters this readback.</summary>
    public string ReadRemotePageProof(long snapshotSequence = 0) => WithGate(() =>
    {
        if (document is null || displayList is null || currentAddress?.Scheme is not ("http" or "https") ||
            remoteEvidenceAddress != currentAddress.AbsoluteUri || string.IsNullOrEmpty(remoteBodySha256)) return "{}";
        var visible = new BrowserRect(0, 0, viewport.Width, viewport.Height);
        var json = new StringBuilder("{\"Kind\":\"ActualRemotePageDomReadback\",\"Address\":").Append(JavaScriptString(currentAddress.AbsoluteUri))
            .Append(",\"Title\":").Append(JavaScriptString(document.Title ?? "")).Append(",\"BodySha256\":").Append(JavaScriptString(remoteBodySha256))
            .Append(",\"CertificateValidated\":").Append(remoteCertificateValidated ? "true" : "false")
            .Append(",\"SnapshotSequence\":").Append(snapshotSequence)
            .Append(",\"DocumentGeneration\":").Append(DocumentGeneration)
            .Append(",\"ViewportWidth\":").Append(Number(viewport.Width)).Append(",\"ViewportHeight\":").Append(Number(viewport.Height))
            .Append(",\"ScrollY\":").Append(Number(viewport.ScrollY)).Append(",\"TextRuns\":[");
        bool comma = false; int count = 0;
        foreach (var command in displayList.Commands)
        {
            if (command.Kind != BrowserDrawKind.Text || command.Opacity <= 0 || string.IsNullOrWhiteSpace(command.Text)) continue;
            var bounds = command.ViewportPinned ? command.Bounds : command.Bounds.Translate(-viewport.ScrollX, -viewport.ScrollY);
            if (bounds.Intersect(visible) is not { Width: > 0, Height: > 0 }) continue;
            if (comma) json.Append(','); comma = true;
            json.Append("{\"Text\":").Append(JavaScriptString(command.Text.Length > 256 ? command.Text[..256] : command.Text))
                .Append(",\"Bounds\":").Append(Rect(bounds)).Append(",\"Color\":").Append(JavaScriptString("#" + command.Color.ToString("X6"))).Append('}');
            if (++count == 64) break;
        }
        json.Append("],\"SearchInputs\":["); comma = false;
        foreach (var element in document.QuerySelectorAll("input[name],textarea[name]").Take(16))
        {
            if (comma) json.Append(','); comma = true;
            json.Append("{\"Name\":").Append(JavaScriptString(element.GetAttribute("name") ?? ""))
                .Append(",\"Bounds\":").Append(Rect(displayList.GetBoundingClientRect(element))).Append('}');
        }
        json.Append("],\"LoadedStyles\":["); comma = false;
        foreach (var receipt in LoadedResources.Where(item => item.Kind == "style").Take(128))
        {
            if (comma) json.Append(','); comma = true;
            json.Append("{\"Address\":").Append(JavaScriptString(receipt.Address))
                .Append(",\"FinalAddress\":").Append(JavaScriptString(receipt.Address))
                .Append(",\"RequestedAddress\":").Append(JavaScriptString(receipt.RequestedAddress ?? receipt.Address))
                .Append(",\"Characters\":").Append(receipt.Characters).Append('}');
        }
        json.Append("],\"DeclaredStyleLinks\":["); comma = false;
        foreach (var link in document.QuerySelectorAll("link[rel~=stylesheet][href]").Take(128))
        {
            if (!Uri.TryCreate(currentAddress, link.GetAttribute("href"), out var uri)) continue;
            if (comma) json.Append(','); comma = true; json.Append(JavaScriptString(uri.AbsoluteUri));
        }
        json.Append("],\"InlineStyleCount\":").Append(document.QuerySelectorAll("style").Length)
            .Append(",\"DeclaredCsp\":").Append(cspDeclared ? "true" : "false")
            .Append(",\"AuthorStylesBlockedByCsp\":").Append(cspBlocksAuthorStyles ? "true" : "false")
            .Append(",\"BaseHrefCount\":").Append(document.QuerySelectorAll("base[href]").Length)
            .Append(",\"Diagnostics\":").Append(JavaScriptString(pageDiagnostics?.ToString() ?? ""))
            .Append(",\"ReadOnly\":true,\"NoHostScreenshotSubstitution\":true}");
        return json.ToString();
    });

    private static string Number(double value) => double.IsFinite(value) ? value.ToString("0.###", CultureInfo.InvariantCulture) : "0";
    private static string Rect(BrowserRect value) => "{\"X\":" + Number(value.X) + ",\"Y\":" + Number(value.Y) +
        ",\"Width\":" + Number(value.Width) + ",\"Height\":" + Number(value.Height) + "}";
}