Clipboard API: учитывайте намерение пользователя
Проектируйте запись, чтение, разрешения и запасные пути Clipboard API вокруг явного действия пользователя.
BotBrowser Team
Нужна структурированная документация по теме Платформа?
Эта статья относится к редакционной библиотеке. Для пошаговой настройки, справки и постоянных обновлений переходите сразу в соответствующий раздел docs.
API буфера обмена позволяет разрешённой странице записывать данные в системный буфер обмена или читать их, но результат API не доказывает, что человек хотел раскрыть это содержимое. BotBrowser может повторить собственную страницу с объявленным профилем и записать видимые состояния разрешения, запасного пути и статуса; он не может читать настоящий буфер пользователя, выдавать разрешение или решать, было ли действие намеренным. Безопасный дизайн начинается с задачи пользователя и запрашивает минимальную операцию, которая её выполняет.
Спецификация API буфера обмена W3C отделяет асинхронные операции от правил разрешений и активации пользователя. В справочнике API буфера обмена на MDN описана поверхность браузера, а руководство web.dev по асинхронной работе с буфером показывает progressive enhancement. Эти источники поддерживают важную границу: выполненная promise сообщает, что принял браузер, а не то, что человек вставил, проверил или разрешил удалённому сервису.
Кратко
- Начинайте с видимого действия и указывайте, будет ли страница записывать, читать или преобразовывать данные буфера.
- Считайте
navigator.clipboard.writeText()иnavigator.clipboard.readText()разными решениями о приватности с отдельными запасными путями. - Оставляйте поле для выделения, клавиатурный путь и сообщение состояния, когда защищённый контекст, фокус, политика или разрешение блокируют API.
- Записывайте сокращённое состояние вроде
write-successилиread-denied, но не содержимое буфера. - Сравнивайте ветки поддержки и отказа на синтетической фикстуре; BotBrowser не создаёт настоящий буфер или решение о разрешении.
Содержание
- Определите действие и намерение
- Разделите запись и чтение
- Обработайте текст и богатые форматы
- Оставьте запасной путь и фокус видимыми
- Записывайте результаты без сбора секретов
- Проверьте поведение ограниченной фикстурой
- Практический итог
Определите Действие И Намерение
Работа с буфером начинается с конкретной задачи, а не со скрытой проверки. «Скопировать номер счёта» означает запись выбранного видимого значения. «Вставить код в форму» означает чтение после выбора поля назначения. «Импортировать форматированный текст» может потребовать ClipboardItem и списка разрешённых форматов. Запишите задачу в подписи элемента и состоянии до вызова navigator.clipboard, чтобы человек понимал результат.
Контекст браузера имеет значение. Модель W3C и материалы MDN описывают защищённый контекст и проверки, зависящие от origin, фокуса, встраивания, политики и кратковременной активации. Загрузка страницы не является намерением пользователя. Не вызывайте readText() из таймера, скрытого iframe, аналитического callback или предварительной загрузки маршрута только потому, что значение может понадобиться. Отказ или пустой результат не доказывает отсутствие данных в буфере.
Используйте общий словарь состояний для интерфейса и записи поддержки: idle, intent-recorded, write-requested, read-requested, completed, denied, cancelled, unsupported и failed. completed означает, что страница получила результат браузера и обновила видимый элемент. Это не означает, что ОС показала уведомление, другая программа приняла вставку или сервер сохранил значение.
Руководство по разрешениям браузера объясняет, почему состояние разрешения может наблюдаться, но не быть утверждением личности. То же правило действует здесь: состояние буфера нужно текущему действию, а не постоянному профилю. Привязывайте операцию к идентификатору вроде clip-17 и завершайте его при смене задачи или маршрута.
Разделите Запись И Чтение
Запись значения, выбранного страницей, обычно раскрывает меньше, чем чтение произвольного буфера. Дайте кнопке точную подпись, например «Скопировать код восстановления», и покажите исходное значение. После клика приложение может вызвать navigator.clipboard.writeText(value), затем объявить write-success или write-denied. При отказе promise оставьте значение в выделяемом поле, а не сообщайте об успехе.
Чтение: другое решение. Попросите человека поставить фокус в поле назначения, объясните, что страница прочитает буфер, и вызывайте navigator.clipboard.readText() только из этого действия. Не делайте тихое чтение перед поиском аккаунта или сортировкой подсказок. В буфере могут быть пароль, личное сообщение или платёжные данные. Используйте результат один раз, проверьте формат поля и удалите его из временного состояния.
Проверка функции отличает отсутствующий API от отклонённого запроса, но не предсказывает разрешение. До показа основного пути проверьте globalThis.isSecureContext и navigator.clipboard?.writeText или readText. Таблица отделяет наблюдение браузера от решения продукта.
| Наблюдение браузера | Состояние продукта | Видимое действие |
|---|---|---|
| Метод API отсутствует | unsupported | Оставить поле для выделения или клавиатурную вставку. |
Promise отклонена с NotAllowedError | denied | Объяснить отказ браузера и сохранить запасной путь. |
| Пользователь закрыл или покинул поток | cancelled | Вернуть фокус исходному элементу без автоматического повтора. |
| Promise выполнена после записи | completed | Сообщить, что страница передала выбранное значение браузеру. |
| Прочитанный текст не прошёл проверку | failed | Не менять поле и показать требуемый формат. |
Руководство по границам разрешений Web Share рассматривает близкую возможность с действием пользователя. Правило такое же: запасной путь является обычной частью договора, а не скрытым обходом политики. Оставляйте копирование или вставку доступными с первого отображения.
Обработайте Текст И Богатые Форматы
Текстовые сценарии проще объяснить: до записи можно задать длину и набор символов. Обрезайте пробелы только когда это предусмотрено задачей; иначе сохраняйте выбранный текст точно. Для кода после чтения проверяйте форму вроде AB-1234 и отклоняйте дополнительные строки без записи содержимого. Успешная проверка означает лишь соответствие этому полю, а не подлинность значения.
Богатые операции требуют более узкого договора. ClipboardItem может содержать text/plain и text/html, поэтому приложение должно запрашивать или записывать только нужные типы. Санитизируйте HTML перед вставкой; представление браузера не является доверенной разметкой. В фикстуре задайте предел 256 KiB и отвергайте неожиданные MIME-типы до разбора. Спецификация определяет интерфейс, но не делает прикладной HTML безопасным.
Не превращайте чтение богатого формата в молчаливый импорт произвольного текста. Сообщите выбранное представление, покажите предпросмотр сложных данных и дайте отмену или очистку. Если text/html нет, предложите text/plain с видимым предупреждением о потере форматирования. Для изображения лимиты декодирования и хранения должны быть частью договора приложения.
При записи устанавливайте представление обычного текста, если оно является допустимым запасным вариантом. Кнопка, записывающая только HTML, может оставить пользователя клавиатуры или терминал без полезного результата. Простая фикстура выражает ожидаемую поверхность:
const value = selectedValue;
const result = { operation: 'write', fixtureId: 'clip-17', state: 'requested' };
if (!globalThis.isSecureContext || !navigator.clipboard?.writeText) {
result.state = 'unsupported';
} else {
try {
await navigator.clipboard.writeText(value);
result.state = 'write-success';
} catch (error) {
result.state = error?.name === 'NotAllowedError' ? 'write-denied' : 'write-failed';
}
}
Запись намеренно исключает value. Тест может проверить видимый статус с синтетическими данными clip-17, не сохраняя содержимое. При переводе сохраняйте одинаковыми MIME-имена, пределы и идентификаторы.
Оставьте Запасной Путь И Фокус Видимыми
Progressive enhancement должна сохранять задачу, когда API буфера обмена отсутствует или отклонён. Для копирования можно выделить <input readonly> и показать клавиатурную инструкцию. Для вставки оставьте поле редактируемым, чтобы работал системный ярлык. Богатый импорт может принимать файл или обычный текст. Эти пути должны быть доступны без повторного открытия запроса разрешения.
Сообщение состояния: часть корректности. Объявляйте write-success, read-denied или unsupported в live-регионе, после успеха переводите фокус к следующему смысловому элементу, а при ошибке возвращайте его к исходной кнопке. Не отключайте единственное рабочее поле во время promise. Повтор должен требовать нового клика и не использовать старое значение после навигации.
Клавиатурный и ассистивный путь имеет ту же границу намерения. Активация подписанной кнопки является действием, эффект при загрузке им не является. Используйте точное доступное имя, не называйте операцию буфера просто «Продолжить» и сообщайте, скопировано ли значение, вставлено или доступно для ручного выбора. Проверяйте масштабирование, контраст, экранный диктор и длинные локализованные подписи.
Встраивание меняет запасной путь. Междоменный frame может столкнуться с политикой браузера или границей фокуса даже при защищённой верхней странице. Он должен указать владельца исправления и предлагать переход к странице первой стороны только при наличии такого маршрута. Никогда не переносите текст буфера между frame через query string.
Записывайте Результаты Без Сбора Секретов
Телеметрия должна отвечать «какую ветку выбрал продукт?», а не «что было в буфере?». В allowlist могут входить fixtureId, operation, state, mimeType, browserVersion, context и fallback. В него не входят текст, HTML, байты изображения, идентификаторы аккаунта и полные URL. Строка read-denied помогает поддержке, а скопированный пароль нет.
Разделяйте ответственность браузера и приложения. Браузер решает, раскрывать ли запрос, и может отказать. Страница проверяет и показывает результат. Сервер может подтвердить отправленное значение, но это не доказывает чтение или запись буфера браузером. Записывайте этапы отдельно, чтобы поздний ответ не перезаписал новую попытку clip-17.
Состояние разрешения не является безопасным отпечатком. Версия, профиль, фокус, политика, действие пользователя и интеграция ОС меняют результат. Не объединяйте доступность буфера со шрифтами, устройствами и другими разрешениями для оценки риска. Руководство по защищённым контекстам формулирует общее правило: проверка способности служит объявленной функции, а не идентификации человека.
Срок хранения должен быть коротким и определённым. Храните синтетическую запись только на время сравнения версии, затем агрегируйте состояние или удаляйте его. Для поддержки запрашивайте минимальный обезличенный идентификатор этапа. Не просите скриншот личного содержимого, полный профиль или необезличенное событие.
Проверьте Поведение Ограниченной Фикстурой
Используйте собственную страницу и синтетическое значение для всей матрицы. Начните с clip-17, видимой кнопки копирования, редактируемого поля вставки и live-региона status. Запустите фикстуру в защищённом контексте, затем повторите с удалённым методом, отклонённой promise и выбранным запасным путем. Сохраняйте рядом browserVersion, viewport, origin и fixtureRevision. Сравнивайте первый изменившийся заявленный параметр, а не поведение всех систем.
Руководство web.dev по асинхронной работе с буфером помогает с progressive enhancement, а W3C и MDN определяют семантику и поверхность. Перечитайте все три источника до изменения текста о поддержке. Не используйте старое объявление Chrome или сломанную ссылку Chrome как доказательство; публичный набор этого материала: спецификация W3C, справочник MDN и руководство web.dev.
Компактная строка аудита выглядит так:
{
"fixtureId": "clip-17",
"operation": "write",
"state": "write-success",
"fallback": "none",
"mimeType": "text/plain",
"browserVersion": "156.0",
"viewport": "1280x800"
}
Строка описывает результат на границе браузера, но не доказывает, что человек вставил значение. Если первое отличие: unsupported, проверьте защищённый контекст и feature detection. Если write-denied, проверьте активацию, фокус, политику и решение пользователя. Если видимый статус неверен при выполненной promise, проверьте машину состояний и live-регион.
BotBrowser может повторить этот объявленный синтетический путь в контролируемом контексте и сохранить входные данные профиля и viewport. Он не может читать настоящий буфер, создавать системную вставку, выдавать разрешение или подтверждать приём значения другой программой. Итог ограничивайте фикстурой, версией, origin и реально наблюдённым результатом.
Публичные Источники
- API буфера обмена, W3C
- API буфера обмена, MDN
- Асинхронная работа с буфером, web.dev
- Согласованность автоматизации BotBrowser
Практический Итог
Просите видимое действие, разделяйте запись и чтение, проверяйте форматы до использования и оставляйте выделяемый запасной путь. Записывайте только состояние операции и объявленный контекст; не превращайте содержимое или разрешение в сигнал личности. BotBrowser может повторить авторизованный синтетический поток, но браузер, человек, страница и сервер сохраняют собственные границы.
Эта статья входит в руководство: Поверхности веб-платформы: карта проверки
Похожие статьи
Данные совместимости Browser API и резервные пути
ПлатформаWeb Share API: границы разрешений и безопасные запасные варианты
ПлатформаIdle Detection API: контроль, разрешения и приватность
ПлатформаОт стандартов браузера к статусу реализации
ПлатформаПоддержка функции браузером не равна качеству функции
ПлатформаWeb Share API и обмен по действию пользователя
Переведите BotBrowser из исследований в продакшн
Используйте эти руководства, чтобы понять модель, а затем перейти к кроссплатформенной валидации, изолированным контекстам и масштабируемому браузерному развертыванию.