Вставка пользовательского элемента с помощью AngleSharp

Я пытаюсь обновить сайт, который использует дезинфицирующее средство на основе AngleSharp для обработки пользовательского HTML-контента. Пользователи сайта должны иметь возможность встраивать фреймы, и я пытаюсь использовать белый список, чтобы контролировать, какие домены может загружать фрейм. Я хотел бы переписать «заблокированные» iframe в новый настраиваемый элемент «blocked-iframe», который затем будет удален дезинфицирующим средством, чтобы мы могли проверить, нужно ли добавлять другие домены в белый список.

Я пытаюсь использовать решение, основанное на этом ответе: https://stackoverflow.com/a/55276825/794

Это выглядит так:

    string BlockIFrames(string content)
    {
        var parser = new HtmlParser(new HtmlParserOptions { });

        var doc = parser.Parse(content);

        foreach (var element in doc.QuerySelectorAll("iframe"))
        {
            var src = element.GetAttribute("src");

            if (string.IsNullOrEmpty(src) || !Settings.Sanitization.IFrameWhitelist.Any(wls => src.StartsWith(wls)))
            {
                var newElement = doc.CreateElement("blocked-iframe");
                foreach (var attr in element.Attributes)
                {
                    newElement.SetAttribute(attr.Name, attr.Value);
                }

                element.Insert(AdjacentPosition.BeforeBegin, newElement.OuterHtml);

                element.Remove();
            }
        }

        return doc.FirstElementChild.OuterHtml;
    }

Это якобы работает, но я заметил, что угловые скобки в теге нового элемента экранируются при вставке, поэтому результат просто записывается на страницу в виде текста. Я думаю, что мог бы построить карту замен и просто выполнить их для строки перед отправкой обратно, но мне интересно, есть ли способ сделать это с помощью API AngleSharp. В настоящее время на сайте используется версия 0.9.9, и я не уверен, насколько далеко мы сможем обновиться, учитывая некоторые другие зависимости в игре.


person AlexCuse    schedule 06.05.2020    source источник


Ответы (1)


Копаясь в исходниках, я нашел метод ReplaceChild в INode, который работает, если вызывается из родителя element.

    string BlockIFrames(string content)
    {
        var parser = new HtmlParser(new HtmlParserOptions { });

        var doc = parser.Parse(content);

        foreach (var element in doc.QuerySelectorAll("iframe"))
        {
            var src = element.GetAttribute("src");

            if (string.IsNullOrEmpty(src) ||
                !Settings.Sanitization.IFrameWhitelist.Any(wls => src.StartsWith(wls)))
            {
                var newElement = doc.CreateElement("blocked-iframe");
                foreach (var attr in element.Attributes)
                {
                    newElement.SetAttribute(attr.Name, attr.Value);
                }

                element.Parent.ReplaceChild(newElement, element);
            }
        }

        return doc.FirstElementChild.OuterHtml;
    }

Я продолжу тестирование, но мне это кажется достаточно приличным, если есть лучший способ, я бы хотел его услышать.

person AlexCuse    schedule 08.05.2020