Plugin Permissions
Todo plugin Owncast é executado em um sandbox sem acesso implícito a nada fora do próprio plugin. Para realizar um trabalho útil (ler chat, publicar no fediverse, buscar uma URL, escrever em uma loja de chave-valor) seu plugin solicita ao host através dos métodos 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.
Plugins require Owncast 0.3.0 or later.
Quando um administrador instala um plugin, a aba Permissões na página de detalhes do plugin lista exatamente o que o plugin pediu, em linguagem simples. Essa é a fronteira de confiança: um administrador pode instalar um plugin de terceiros sem revisar cada linha de código, porque o manifesto é o limite superior do que o plugin pode fazer.
Os identificadores de permissões e o modelo de confiança abaixo são os mesmos, independentemente de qual SDK você use. Os métodos owncast.* são referenciados aqui por seus nomes canônicos. Para a grafia exata no seu idioma, consulte a referência do SDK JavaScript ou Python.
Como funciona
-
Você declara permissões em
plugin.manifest.json:{ "permissions": ["chat.send", "storage.kv"] } -
O administrador as revisa ao habilitá-las. A página de detalhes do plugin do Owncast lista cada permissão com uma descrição legível por humanos.
-
O host as aplica em tempo de execução. Calling
owncast.chat.send(...)withoutchat.sendin 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 everysqlmethod), readers return an empty or zero value, and calls that return nothing become silent no-ops.fs.write,fs.delete, andstorage.uploadreport failure in their return value instead of raising. -
O host capta desvios. Seu plugin construído declara as permissões que usa em tempo de execução. O host compara isso com o manifesto e se recusa a carregar o plugin se o tempo de execução solicitar mais do que o manifesto concede. Você não pode obter acesso extra trocando o arquivo do plugin depois.
Reaprovação quando as permissões se expandem
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. Reduzir permissões é silencioso.
As capacidades efetivas de um plugin instalado nunca aumentam sem que o administrador diga sim novamente.
Referência de permissões
chat.send
Concede:
owncast.chat.send(text): publica como a identidade do bot do pluginowncast.chat.sendAction(text): publica uma mensagem "/me"owncast.chat.sendTo(clientId, text): envie uma mensagem privada a um cliente conectadoowncast.chat.replyTo(msg, text): whisper a reply back to whoever sent a chat message (sugar oversendTo)owncast.chat.system(body): publica uma mensagem do sistema sem identidade de usuário, exibida como um anúncio de servidor (o corpo é HTML)
As mensagens passam pelo pipeline de chat normal do Owncast (filtros, limites de taxa, persistência, moderação). Os plugins não podem enviar sob nomes arbitrários ou se passar por usuários reais.
chat.history
Concede:
owncast.chat.history(limit?): lê mensagens de chat recentesowncast.chat.clients(): lista clientes de chat conectados
Somente leitura.
chat.moderate
Concede:
owncast.chat.deleteMessage(messageId): oculta uma mensagem dos espectadoresowncast.chat.kick(clientId): desconecta um cliente de chat
chat.filter
Concede a capacidade de definir filterChatMessage(msg): vê cada mensagem de chat antes de ser transmitida, com a capacidade de reescrever ou descartar.
A filtragem acontece em linha em cada mensagem de chat, então o administrador precisa ver isso explicitamente mencionado. O host rejeita o carregamento se um plugin definir filterChatMessage sem declarar esta permissão.
users.read
Grants:
owncast.users.list(): lê a lista de usuários do chatowncast.users.get(id): lê um único registro de usuário
users.moderate
Concede:
owncast.users.setEnabled(id, enabled, reason?): habilita ou desabilita um usuárioowncast.users.banIP(ip): banir um IP de participar do chat
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.
Essa é a forma como um plugin transforma um login de terceiros (OAuth, Discord, uma senha compartilhada) em um usuário Owncast real com uma identidade de chat autenticada. Sozinho não fornece acesso ao site nem emite uma sessão: combine-o com auth.gate para construir um portão de login, ou use-o sozinho para criar identidades de chat verificadas.
auth.gate
Concede o portão de autenticação do visualizador:
owncast.auth.grantSession({ userId, ttl? }): issue a signed session for an already-registered user (seeusers.register)owncast.auth.endSession(): limpa a sessão do visualizador atual (sair)- o manipulador opcional
onAuthCheck: revalida a sessão de um visualizador em cada carga de página
Um plugin segurando auth.gate é um provedor de identidade. 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. Apenas um plugin auth.gate pode ser ativado por vez, e o portão falha fechado: se o plugin estiver indisponível, os visualizadores são mantidos fora, em vez de deixados entrar. Veja Autenticação para o modelo completo.
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. Os plugins não podem ler as chaves uns dos outros.
O estado persiste entre recargas e reinicializações do host.
storage.upload
Grants owncast.storage.upload(name, data): upload a file to Owncast's public file area and get back a URL. Útil para emblemas, imagens geradas dinamicamente, anexos de publicações do 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. Útil para caches, arquivos de dados gerados, logs de estilo de anexação, ou qualquer coisa que você precise persistir como arquivos reais em vez de strings de chave/valor.
Ao contrário de storage.upload, esses arquivos permanecem do lado do servidor: eles nunca são servidos via HTTP. Cada caminho é restrito ao diretório do seu próprio plugin: um plugin não pode ler os arquivos de outro plugin ou escapar do seu sandbox (../ e caminhos absolutos são colapsados de volta dentro).
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
Concede owncast.http.fetch(url, opts?): HTTP de saída síncrono.
Requer uma lista de network.allowedHosts no manifesto. O host rejeita o carregamento se network.fetch for concedido sem uma lista de permitidos. Cada chamada é verificada contra a lista de permitidos. Hosts que não correspondem retornam um erro antes que quaisquer bytes deixem o servidor.
{
"permissions": ["network.fetch"],
"network": { "allowedHosts": ["api.discord.com", "*.weather.com"] }
}
O caractere curinga "*" é permitido, mas deve ser escrito explicitamente para que os administradores que revisam o manifesto vejam o escopo. A UI de administrador exibe a lista completa de allowedHosts na aba Permissões ao lado da linha network.fetch, para que um operador de servidor que revisar um plugin veja exatamente quais hosts ele pode alcançar sem desembalar o .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
Concede permissão ao roteador HTTP do host para enviar requisições para /plugins/<seu-slug>/* ao seu plugin. Isso abrange tanto arquivos estáticos no seu diretório public/ quanto requisições dinâmicas direcionadas ao seu manipulador onHttpRequest.
Sem essa permissão, todo o espaço de URL /plugins/<seu-slug>/ retorna 404.
http.sse
Concede owncast.sse.send(channel, event, data) e expõe um endpoint propriedade do host em /plugins/<seu-slug>/_sse/<channel> ao qual os navegadores se conectam com EventSource. Independente de http.serve. Um plugin pode enviar eventos sem fornecer outras rotas.
server.read
Concede as APIs de stream somente leitura e estado do servidor:
owncast.stream.current(): estado da transmissão ao vivoowncast.stream.broadcaster(): telemetria de codificação de entradaowncast.server.info(): nome do servidor, versão, resumoowncast.server.socials(): links sociais configuradosowncast.server.emotes(): custom chat emotes configured on this serverowncast.server.federation(): configurações do fediverseowncast.server.tags(): tags configuradas
videoconfig.read
Concede owncast.videoConfig.read(): lê a configuração de saída e transcodificação (codecs, nível de latência, variantes de stream).
videoconfig.write
Concede owncast.videoConfig.write(partial): modifica a configuração de saída do vídeo.
Alta confiança. As mudanças se aplicam na próxima início do stream. O host não reinicia uma transmissão ativa. Os administradores devem conceder com moderação.
notifications.send
Concede as APIs de notificação do broadcaster:
owncast.notifications.discord(text): através do webhook do Discord configurado pelo streamerowncast.notifications.browserPush({ title, body, url? }): to subscribed browsersowncast.notifications.fediverse({ type, body, image?, link? }): fediverse-formatted notification
fediverse.inbound
Concede a assinatura de todos os sete eventos de plugin inbound do Fediverse:
fediverse.followfediverse.likefediverse.repostfediverse.quotefediverse.mentionfediverse.replyfediverse.activity
O fediverse.activity genérico recebe o objeto JSON bruto da atividade verificada. Ele é executado além de qualquer evento especializado correspondente. Esta permissão cobre apenas o recebimento de atividade. Publicar da conta Owncast requer a permissão separada fediverse.post.
fediverse.post
Concede owncast.fediverse.post(text): faz uma postagem pública no fediverse da conta Owncast.
Alta confiança: as postagens saem sob o próprio handle do streamer no fediverse e não podem ser revogadas silenciosamente. Os administradores devem conceder com moderação.
ui.modify
Concede a capacidade de colocar UI dentro do próprio chrome do Owncast:
- Declarando
manifest.actions(botões de ação abaixo do stream). - Chamando
owncast.actions.add(...)/.clear()em tempo de execução. - Declarando
manifest.styles(CSS inlined na página do visualizador). - Declarando
manifest.scripts(JavaScript inlined na página do visualizador). - Declarando
manifest.extraPageContent(um bloco HTML prependido à área de conteúdo extra do visualizador). - Declarando
manifest.tabs(abas adicionais na linha de abas da página do visualizador). - Implementando um manipulador
onPageStylesouonPageScripts(CSS ou JavaScript retornados no momento da requisição, sem campo manifesto).
Sem essa permissão, manifestos que declaram qualquer um desses campos são rejeitados ao carregar. Os manipuladores onPageStyles e onPageScripts não têm campo manifesto, então não são rejeitados ao carregar. O host simplesmente não os chama a menos que o plugin possua ui.modify. Cada um desses alcança a página do visualizador em vez de ficar dentro do próprio espaço de URL do plugin, então o administrador precisa ver a permissão para entender que o plugin está pintando na UI do host.
Nenhum dos quatro campos de injeção de visualizador requer http.serve, e nem os dois manipuladores. O host lê cada arquivo do diretório assets/ do plugin (não a partir de uma URL), ou chama o manipulador, e insere o resultado nas respostas de configuração existentes / custom-JS, então ui.modify por si só é suficiente.
Tabela de resumo
| Permissão | Concede |
|---|---|
chat.send | owncast.chat.send, .sendAction, .sendTo, .replyTo, .system |
chat.history | owncast.chat.history, .clients |
chat.moderate | owncast.chat.deleteMessage, .kick |
chat.filter | Inscreva-se em filterChatMessage (ler, modificar ou descartar cada mensagem de chat). |
users.read | owncast.users.list, .get |
users.moderate | owncast.users.setEnabled, .banIP |
users.register | owncast.users.register: encontrar ou criar um usuário autenticado para uma identidade externa |
auth.gate | owncast.auth.grantSession, .endSession, e o manipulador onAuthCheck: ser o portão de autenticação do site |
storage.kv | Armazenamento de chave/valor com namespace por plugin |
storage.upload | Carregar arquivos na área pública de arquivos do Owncast |
storage.fs | Private, sandboxed server-side filesystem at data/plugin-storage/<your-slug>/files/ |
storage.sql | Private per-plugin SQLite database at data/plugin-storage/<your-slug>/db/plugin.db |
network.fetch | Saída HTTP. Também requer network.allowedHosts |
events.emit | Emitir eventos personalizados para outros plugins |
http.serve | Servir HTTP em /plugins/<your-slug>/* |
http.sse | Enviar eventos em tempo real via owncast.sse.send e o endpoint /_sse/ |
server.read | Ler o estado do fluxo, configuração do servidor, codificar telemetria |
videoconfig.read | Ler a configuração de saída/transcodificação |
videoconfig.write | Modificar a configuração de saída de vídeo (aplica-se na próxima inicialização do fluxo) |
notifications.send | Enviar notificações do Discord, push do navegador ou notificações do fediverse |
fediverse.inbound | Inscrever-se em todos os sete eventos de entrada: fediverse.follow, .like, .repost, .quote, .mention, .reply, e .activity |
fediverse.post | Publicar para o fediverse (com limitação de taxa) |
ui.modify | Adicionar botões de ação ou abas ao chrome do visualizador do Owncast. CSS, JavaScript ou HTML de plugin embutido na página do visualizador |
Princípio do privilégio mínimo
Declare apenas o que você realmente usa. Quanto mais restrito for seu manifesto, mais fácil será a decisão de confiança do administrador. Se você se encontrar listando todas as permissões, recuar e ver se seu plugin não deveria ser realmente dois plugins.
Se você parar de usar uma permissão durante o desenvolvimento, remova-a do manifesto. Encolher é silencioso. Não há atrito em remover entradas não utilizadas.
Improve this page
See something missing or incorrect? Edit this page and improve the documentation for everyone.
Gabe Kangas