Скопировать в буфер обмена как обычный текст

Я использую этот код в background.js в расширении Chrome, чтобы скопировать текст в буфер обмена пользователя:

chrome.runtime.onMessage.addListener(
    function(request, sender, sendResponse) {
        if (request.command == "copy") {
            executeCopy(request.text);
            sendResponse({farewell: "copy request received"});
        }
    }
);

function executeCopy(text){
    var copyDiv = document.createElement('div');
    copyDiv.contentEditable = true;
    document.body.appendChild(copyDiv);
    copyDiv.innerHTML = text;
    copyDiv.unselectable = "off";
    copyDiv.focus();
    document.execCommand('SelectAll');
    document.execCommand("Copy", false, null);
    document.body.removeChild(copyDiv);
}

Он копирует текст с форматированием. Как я могу скопировать текст в виде простого текста без форматирования?

Ответ 1

Код вопроса содержит общую проблему безопасности, известную как XSS. Поскольку вы берете ненадежный ввод и назначаете его .innerHTML, вы разрешаете злоумышленникам вставлять произвольный HTML в контексте вашего документа.

К счастью, злоумышленники не могут запускать скрипты в контексте вашего расширения, потому что расширение по умолчанию Политика безопасности контента запрещает встроенные скрипты. Этот CSP применяется в расширениях Chrome именно из-за таких ситуаций, чтобы предотвратить уязвимости XSS.

Правильный способ преобразования HTML в текст осуществляется через DOMParser API. Следующие две функции показывают, как копировать текст в виде текста, или для вашего случая HTML в виде текста:

// Copy text as text
function executeCopy(text) {
    var input = document.createElement('textarea');
    document.body.appendChild(input);
    input.value = text;
    input.focus();
    input.select();
    document.execCommand('Copy');
    input.remove();
}

// Copy HTML as text (without HTML tags)
function executeCopy2(html) {
    var doc = new DOMParser().parseFromString(html, 'text/html');
    var text = doc.body.textContent;
    return executeCopy(text);
}

Обратите внимание, что .textContent полностью игнорирует теги HTML. Если вы хотите интерпретировать <br> как разрывы строк, используйте нестандартное (но поддерживаемое в Chrome) свойство .innerText вместо .textContent.

Вот два из многих примеров того, как XSS можно злоупотреблять с помощью функции executeCopy из вашего вопроса:

// This does not only copy "Text", but also trigger a network request
// to example.com!
executeCopy('<img src="http://example.com/">Text');

// If you step through with a debugger, this will show an "alert" dialog
// (an arbitrary script supplied by the attacker!!)
debugger;
executeCopy('<iframe src="data:text/html,<script>alert(/XXS-ed!/);<\/script>"></iframe>');