Перейти к основному содержимому

Plugin Permissions

Каждый плагин Owncast работает в песочнице и не имеет неявного доступа к чему-либо за пределами самого плагина. Чтобы выполнять полезные задачи (читать чат, публиковать в fediverse, получать URL-адрес, записывать в хранилище ключ-значение), ваш плагин обращается к хосту через методы owncast.*. Almost every one of those methods is gated by a permission you declare in your manifest. The exceptions are a handful of ambient methods that reach nothing sensitive and need no permission: owncast.log.*, owncast.timer.*, reading your own bundled assets, and owncast.config.get.

Plugin permissions require Owncast v0.3.0

Plugins require Owncast 0.3.0 or later.

Когда администратор устанавливает плагин, вкладка Разрешения на странице деталей плагина точно указывает, какие разрешения плагин запрашивал, на простом языке. Это граница доверия: администратор может установить плагин от третьей стороны, не проверяя каждую строку кода, поскольку манифест — это верхняя граница того, что может делать плагин.

Вкладка Разрешения на странице деталей плагина, перечисляющая каждое запрошенное разрешение с описанием на простом языке
Owncat informs youДоступно в каждом SDK

Идентификаторы разрешений и модель доверия ниже одинаковы, независимо от того, какой SDK вы используете. Методы owncast.* здесь упоминаются по их каноническим именам. Для точного написания на вашем языке смотрите справку по JavaScript или Python SDK.

Как это работает

  1. Вы объявляете разрешения в plugin.manifest.json:

    { "permissions": ["chat.send", "storage.kv"] }
  2. Администратор проверяет их при включении. Страница деталей плагина Owncast перечисляет каждое разрешение с описанием, доступным для человека.

  3. Хост применяет их во время выполнения. Calling owncast.chat.send(...) without chat.send in your manifest never reaches Owncast: the host logs the denial and the call does nothing. Mutating calls that report an outcome raise an error (moderation, users.register, auth.grantSession, kv.set, videoConfig.write, actions.add, actions.clear, and every sql method), readers return an empty or zero value, and calls that return nothing become silent no-ops. fs.write, fs.delete, and storage.upload report failure in their return value instead of raising.

  4. Хост отслеживает изменения. Ваш установленный плагин объявляет разрешения, которые он использует во время выполнения. Хост сравнивает это с манифестом и отказывается загружать плагин, если во время выполнения запрашивается больше, чем разрешает манифест. Вы не можете тайком получить дополнительный доступ, заменив файл плагина после факта.

Повторное одобрение, когда разрешения увеличиваются

If you ship an update that asks for more permissions than the admin previously approved, the old approved version keeps running (it holds only the approved permissions) and the new package waits as pending. The plugin list shows a "needs re-approval" badge. The admin reviews the new permissions in the Permissions tab and clicks Approve to accept the expanded set and load the update. Сокращение разрешений проходит безмолвно.

Эффективные возможности установленного плагина никогда не увеличиваются без повторного согласия администратора.

Справочник разрешений

chat.send

Предоставляет:

  • owncast.chat.send(text): отправить от имени бота плагина
  • owncast.chat.sendAction(text): отправить сообщение "/me"
  • owncast.chat.sendTo(clientId, text): личное сообщение подключенному клиенту
  • owncast.chat.replyTo(msg, text): whisper a reply back to whoever sent a chat message (sugar over sendTo)
  • owncast.chat.system(body): отправить системное сообщение без пользовательской идентичности, отображенное как серверное уведомление (тело — это HTML)

Сообщения проходят через обычный поток чата Owncast (фильтры, ограничения по времени, сохранение, модерация). Плагины не могут отправлять сообщения от произвольных имен или выдавать себя за реальных пользователей.

chat.history

Предоставляет:

  • owncast.chat.history(limit?): читать последние сообщения чата
  • owncast.chat.clients(): список подключенных клиентов чата

Только для чтения.

chat.moderate

Предоставляет:

  • owncast.chat.deleteMessage(messageId): скрыть сообщение от зрителей
  • owncast.chat.kick(clientId): отключить клиента чата

chat.filter

Предоставляет возможность определить filterChatMessage(msg): видеть каждое сообщение чата перед его трансляцией, с возможностью переписать или удалить его.

Фильтрация происходит в режиме реального времени для каждого сообщения чата, поэтому администратору нужно явно видеть это. Хост отклоняет загрузку, если плагин определяет filterChatMessage, не объявив это разрешение.

users.read

Grants:

  • owncast.users.list(): читать список пользователей чата
  • owncast.users.get(id): читать запись одного пользователя

users.moderate

Предоставляет:

  • owncast.users.setEnabled(id, enabled, reason?): включить или отключить пользователя
  • owncast.users.banIP(ip): заблокировать IP от участия в чате

users.register

Grants owncast.users.register({ authId, displayName?, scopes?, profileUrl?, handle?, public? }): find or create an authenticated Owncast user for an external identity and return its userId. The authId is a stable, provider-scoped identifier such as "github:583231". Pass it raw, without prefixing your slug. The host records the slug separately and scopes every lookup to that pair, so two plugins cannot collide with or spoof each other's users.

The optional profileUrl, handle, and public fields attach a verified external identity. The profile URL must be empty or an absolute HTTP(S) URL. Set public to true only after the viewer opts into public display. These profile fields are captured on the first registration.

Вот так плагин превращает сторонний логин (OAuth, Discord, общий пароль) в реального пользователя Owncast с аутентифицированной идентичностью чата. Сам по себе он не защищает сайт и не выдает сессию: комбинируйте его с auth.gate, чтобы создать входной узел, или используйте его отдельно для создания проверенных идентичностей чата.

auth.gate

Предоставляет входную точку для проверки пользователей:

  • owncast.auth.grantSession({ userId, ttl? }): issue a signed session for an already-registered user (see users.register)
  • owncast.auth.endSession(): очистить текущую сессию зрителя (выход)
  • опциональный обработчик onAuthCheck: повторная проверка сессии зрителя при каждой загрузке страницы

Плагин, содержащий auth.gate, является поставщиком идентичности. While it is enabled, viewers must authenticate through it before they can reach the page, chat, or the API. The operator selects one cumulative access mode on the plugin's Authentication tab to decide whether Owncast-hosted video and stream status also require a session. Только один плагин auth.gate может быть активирован одновременно, и входной узел работает в закрытом режиме: если плагин недоступен, зрителей не допускают, а не пропускают. Смотрите Аутентификация для полной модели.

storage.kv

Grants owncast.kv.get(key), owncast.kv.set(key, value), and the JSON helpers owncast.kv.getJSON(key, fallback?) and owncast.kv.setJSON(key, value): a per-plugin namespaced key/value store. Плагины не могут читать ключи друг друга.

Состояние сохраняется между перезагрузками и перезапусками хоста.

storage.upload

Grants owncast.storage.upload(name, data): upload a file to Owncast's public file area and get back a URL. Полезно для значков, динамически сгенерированных изображений, вложений в сообщения fediverse.

storage.fs

Grants owncast.fs.*: a private, sandboxed filesystem at data/plugin-storage/<your-slug>/files/ that your plugin can read, write, list, and delete within. Полезно для кэшей, файлов данных, созданных в виде логов в стиле добавления или всего, что нужно сохранить в виде реальных файлов, а не строк ключ/значение.

В отличие от storage.upload, эти файлы остаются серверной стороной: они никогда не обслуживаются по HTTP. Каждый путь ограничен собственным каталогом плагина: плагин не может читать файлы другого плагина или покинуть свою песочницу (../ и абсолютные пути возвращаются внутрь).

storage.sql

Grants owncast.sql.*: one private SQLite database per plugin, at data/plugin-storage/<your-slug>/db/plugin.db. owncast.sql.exec(sql, params?) runs statements, owncast.sql.query(sql, params?) returns matching rows, and owncast.sql.queryRow(sql, params?) reads a single row. Reach for this instead of storage.kv when you need to sort, filter, or aggregate rather than just remember a value. See owncast.sql.* for the methods in both languages, the per-call limits, and the SQL the host refuses.

The database is private to your plugin and separate from Owncast's own database. The storage.fs sandbox is rooted at files/, so db/ is not a path owncast.fs.* refuses but one it cannot express, and the filesystem quota walk covers files/ only, so the two quotas stay independent: the database has its own 128 MiB cap, and files written through storage.fs count against a separate 256 MiB quota.

Plugin databases are not included in Owncast's database backups, so treat the contents as rebuildable or export what matters yourself. SQL data is retained when a plugin is uninstalled, the same as its config and its storage.fs files, so a reinstall finds its tables where it left them. An admin who wants the space back deletes data/plugin-storage/<your-slug>/.

network.fetch

Предоставляет owncast.http.fetch(url, opts?): синхронный исходящий HTTP.

Требуется список разрешенных хостов network.allowedHosts в манифесте. Хост отклоняет загрузку, если network.fetch предоставляется без списка разрешенных. Каждый вызов проверяется на соответствие списку разрешенных. Хосты, которые не соответствуют, возвращают ошибку, прежде чем какие-либо байты покинут сервер.

{
"permissions": ["network.fetch"],
"network": { "allowedHosts": ["api.discord.com", "*.weather.com"] }
}

Широкий символ "*" разрешен, но должен быть явно записан, чтобы администраторы, проверяющие манифест, видели масштаб. Пользовательский интерфейс администратора отображает полный список allowedHosts на вкладке Разрешения рядом с строкой network.fetch, поэтому оператор сервера, проверяющий плагин, точно видит, к каким хостам он может получить доступ, не распаковывая .ocpkg.

events.emit

Grants owncast.events.emit(eventType, payload). Pass the receiving plugin's fully qualified <recipient-slug>.<hook> name. The host does not rewrite the emitted name. Declaring and receiving a plugin-owned custom hook does not require a permission.

http.serve

Предоставляет разрешение HTTP маршрутизатора хоста для отправки запросов по адресу /plugins/<your-slug>/* в ваш плагин. Это охватывает как статические файлы в вашем каталоге public/, так и динамические запросы, маршрутизируемые к вашему обработчику onHttpRequest.

Без этого разрешения весь URL-адрес /plugins/<your-slug>/ возвращает 404.

http.sse

Предоставляет owncast.sse.send(channel, event, data) и открывает конечную точку, принадлежащую хосту, по адресу /plugins/<your-slug>/_sse/<channel>, к которой браузеры подключаются через EventSource. Независимо от http.serve. Плагин может отправлять события без обслуживания каких-либо других маршрутов.

server.read

Предоставляет API для чтения потоков и состояния сервера:

  • owncast.stream.current(): состояние живого потока
  • owncast.stream.broadcaster(): входная телееметрия
  • owncast.server.info(): имя сервера, версия, сводка
  • owncast.server.socials(): настроенные социальные ссылки
  • owncast.server.emotes(): custom chat emotes configured on this server
  • owncast.server.federation(): настройки fediverse
  • owncast.server.tags(): настроенные теги

videoconfig.read

Предоставляет owncast.videoConfig.read(): читать выходные и кодирующие параметры (кодеки, уровень задержки, варианты потоков).

videoconfig.write

Предоставляет owncast.videoConfig.write(partial): изменять параметры конфигурации видеовыхода.

Высокое доверие. Изменения применяются при следующем запуске потока. Хост не перезапускает активную трансляцию. Администраторы должны предоставлять это с осторожностью.

notifications.send

Предоставляет API уведомлений для ведущего:

  • owncast.notifications.discord(text): через настроенный веб-хук Discord стримера
  • owncast.notifications.browserPush({ title, body, url? }): to subscribed browsers
  • owncast.notifications.fediverse({ type, body, image?, link? }): fediverse-formatted notification

fediverse.inbound

Предоставляет подписку на все семь входящих событий плагина Fediverse:

  • fediverse.follow
  • fediverse.like
  • fediverse.repost
  • fediverse.quote
  • fediverse.mention
  • fediverse.reply
  • fediverse.activity

fediverse.activity принимает сырый JSON-объект проверенной активности. Это выполняется дополнительно к любому соответствующему специализированному событию. Это разрешение охватывает только получение активности. Публикация от имени учетной записи Owncast требует отдельного разрешения fediverse.post.

fediverse.post

Предоставляет owncast.fediverse.post(text): сделать публичную публикацию в fediverse от имени учетной записи Owncast.

Высокое доверие: публикации выходят под личным именем стримера в fediverse и не могут быть тихо отменены. Администраторы должны предоставлять это с осторожностью.

ui.modify

Предоставляет возможность размещать пользовательский интерфейс внутри собственного хрома Owncast:

  • Объявление manifest.actions (кнопки действий под потоком).
  • Вызов owncast.actions.add(...) / .clear() во время выполнения.
  • Объявление manifest.styles (CSS встроено в страницу просмотра).
  • Объявление manifest.scripts (JavaScript встроено в страницу просмотра).
  • Объявление manifest.extraPageContent (HTML-блок, добавленный перед дополнительной областью контента зрителя).
  • Объявление manifest.tabs (дополнительные вкладки в строке вкладок страницы зрителя).
  • Реализация обработчика onPageStyles или onPageScripts (CSS или JavaScript, возвращаемые в момент запроса, без поля манифеста).

Без этого разрешения манифесты, которые объявляют любое из этих полей, отклоняются при загрузке. Обработчики onPageStyles и onPageScripts не имеют поля манифеста, поэтому они не отклоняются при загрузке. Хост просто не вызывает их, если плагин не имеет ui.modify. Каждое из этих полей попадает внутрь страницы просмотра, а не остается в пространстве URL плагина, поэтому администратору необходимо видеть разрешение, чтобы понять, что плагин взаимодействует с хост-UI.

Ни одно из четырех полей внедрения не требует http.serve, как и две обработчика. Хост читает каждый файл из каталога assets/ плагина (не из URL) или вызывает обработчик, и встраивает результат в существующие конфигурации / пользовательские ответы JS, так что ui.modify само по себе достаточно.

Сводная таблица

РазрешениеПредоставляет
chat.sendowncast.chat.send, .sendAction, .sendTo, .replyTo, .system
chat.historyowncast.chat.history, .clients
chat.moderateowncast.chat.deleteMessage, .kick
chat.filterПодписка на filterChatMessage (чтение, изменение или удаление каждого сообщения чата).
users.readowncast.users.list, .get
users.moderateowncast.users.setEnabled, .banIP
users.registerowncast.users.register: найти или создать аутентифицированного пользователя для внешней идентичности
auth.gateowncast.auth.grantSession, .endSession и обработчик onAuthCheck: быть авторизационными воротами сайта
storage.kvХранилище ключей/значений с пространством имен для каждого плагина
storage.uploadЗагрузить файлы в публичную область файлов Owncast
storage.fsPrivate, sandboxed server-side filesystem at data/plugin-storage/<your-slug>/files/
storage.sqlPrivate per-plugin SQLite database at data/plugin-storage/<your-slug>/db/plugin.db
network.fetchИсходящий HTTP. Также требует network.allowedHosts
events.emitСоздавать пользовательские события для других плагинов
http.serveОбслуживать HTTP по адресу /plugins/<your-slug>/*
http.sseОтправлять события в реальном времени через owncast.sse.send и конечную точку /_sse/
server.readСчитывать состояние потока, конфигурацию сервера, кодировать телеметрию
videoconfig.readЧитать конфигурацию выхода/трансляции
videoconfig.writeИзменять конфигурацию видео вывода (применяется при следующем запуске потока)
notifications.sendОтправлять уведомления Discord, браузера или федиверса
fediverse.inboundПодписаться на все семь входящих событий: fediverse.follow, .like, .repost, .quote, .mention, .reply, и .activity
fediverse.postПубликация в федиверсе (с ограничением по скорости)
ui.modifyДобавить кнопки действий или вкладки в интерфейс просмотра Owncast. Встраивание CSS, JavaScript или HTML плагина в страницу просмотра

Принцип минимальных привилегий

Объявляйте только то, что вы действительно используете. Чем уже ваш манифест, тем проще решение о доверии администратора. Если вы обнаружите, что перечисляете каждое разрешение, отступите и посмотрите, действительно ли ваш плагин должен быть двумя плагинами.

Если вы перестали использовать разрешение во время разработки, уберите его из манифеста. Сжатие молчаливо. Убирая неиспользуемые записи, нет трения.


Improve this page

See something missing or incorrect? Edit this page and improve the documentation for everyone.

Contributors to this documentation
Gabe KangasGabe Kangas
G
Gabe Kangas