Passer au contenu principal

Plugin Permissions

Chaque plugin Owncast fonctionne dans un bac à sable sans accès implicite à quoi que ce soit en dehors du plugin lui-même. Pour effectuer des travaux utiles (lire le chat, publier sur le fediverse, récupérer une URL, écrire dans un store clé-valeur), votre plugin demande l'hôte via les méthodes 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.

Lorsqu'un administrateur installe un plugin, l'onglet Autorisations sur la page de détails du plugin énumère exactement ce que le plugin a demandé, en termes simples. C'est la frontière de confiance : un administrateur peut installer un plugin tiers sans vérifier chaque ligne de code, car le manifeste est la limite supérieure de ce que le plugin peut faire.

L'onglet Autorisations sur la page de détails d'un plugin, listant chaque autorisation demandée avec une description en langage simple
Owncat informs youDisponible dans chaque SDK

Les identifiants d'autorisation et le modèle de confiance ci-dessous sont les mêmes, quel que soit le SDK utilisé. Les méthodes owncast.* sont référencées ici par leurs noms canoniques. Pour l'orthographe exacte dans votre langue, consultez la référence SDK JavaScript ou Python.

Comment ça fonctionne

  1. Vous déclarez des autorisations dans plugin.manifest.json :

    { "permissions": ["chat.send", "storage.kv"] }
  2. L'administrateur les examine lors de l'activation. La page de détails du plugin d'Owncast liste chaque autorisation avec une description lisible par un humain.

  3. L'hôte les applique à l'exécution. 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. L'hôte détecte le dérive. Votre plugin construit déclare les autorisations qu'il utilise à l'exécution. L'hôte compare cela avec le manifeste et refuse de charger le plugin si l'exécution demande plus que ce que le manifeste accorde. Vous ne pouvez pas vous faufiler un accès supplémentaire en remplaçant le fichier du plugin après coup.

Nouvelle approbation lorsque les autorisations s'étendent

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. Réduire les autorisations est silencieux.

Les capacités effectives d'un plugin installé ne croissent jamais sans que l'administrateur dise à nouveau oui.

Référence d'autorisation

chat.send

Accorde :

  • owncast.chat.send(text) : publier sous l'identité de bot du plugin
  • owncast.chat.sendAction(text) : publier un message "/me"
  • owncast.chat.sendTo(clientId, text) : envoyer un message privé à un client connecté
  • owncast.chat.replyTo(msg, text): whisper a reply back to whoever sent a chat message (sugar over sendTo)
  • owncast.chat.system(body) : publier un message système sans identité d'utilisateur, rendu comme une annonce serveur (le corps est HTML)

Les messages passent par le pipeline de chat normal d'Owncast (filtres, limites de fréquence, persistance, modération). Les plugins ne peuvent pas envoyer sous des noms arbitraires ou usurper de vrais utilisateurs.

chat.history

Accorde :

  • owncast.chat.history(limit?) : lire les messages récents du chat
  • owncast.chat.clients() : lister les clients de chat connectés

Lecture seule.

chat.moderate

Accorde :

  • owncast.chat.deleteMessage(messageId) : cacher un message aux spectateurs
  • owncast.chat.kick(clientId) : déconnecter un client de chat

chat.filter

Accorde la capacité de définir filterChatMessage(msg) : voir chaque message de chat avant qu'il ne soit diffusé, avec la possibilité de le réécrire ou de le supprimer.

Le filtrage se fait en ligne sur chaque message de chat, donc l'administrateur doit voir cela apparaître explicitement. L'hôte rejette le chargement si un plugin définit filterChatMessage sans déclarer cette autorisation.

users.read

Grants:

  • owncast.users.list() : lire la liste des utilisateurs du chat
  • owncast.users.get(id) : lire un enregistrement d'utilisateur unique

users.moderate

Accorde :

  • owncast.users.setEnabled(id, enabled, reason?) : activer ou désactiver un utilisateur
  • owncast.users.banIP(ip) : interdire un IP de rejoindre le 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.

C'est ainsi qu'un plugin transforme une connexion tierce (OAuth, Discord, un mot de passe partagé) en un véritable utilisateur Owncast avec une identité de chat authentifiée. À lui seul, il ne limite ni ne délivre de session : associez-le à auth.gate pour créer une porte d'entrée de connexion, ou utilisez-le seul pour distribuer des identités de chat vérifiées.

auth.gate

Accorde la porte d'authentification des spectateurs :

  • owncast.auth.grantSession({ userId, ttl? }) : délivrer une session signée pour un utilisateur déjà enregistré (voir users.register)
  • owncast.auth.endSession() : effacer la session actuelle du spectateur (déconnexion)
  • le gestionnaire onAuthCheck optionnel : re-valider la session d'un spectateur à chaque chargement de page

Un plugin détenant auth.gate est un fournisseur d'identité. 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. Un seul plugin auth.gate peut être activé à la fois, et la porte échoue en mode fermé : si le plugin n'est pas disponible, les spectateurs sont exclus plutôt que de laisser entrer. Voir Authentification pour le modèle complet.

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. Les plugins ne peuvent pas lire les clés des autres.

L'état persiste entre les rechargements et les redémarrages de l'hôte.

storage.upload

Grants owncast.storage.upload(name, data): upload a file to Owncast's public file area and get back a URL. Utile pour les badges, les images générées dynamiquement, les pièces jointes de publications dans le 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. Utile pour les caches, les fichiers de données générés, les journaux de type append, ou tout ce que vous avez besoin de persister sous forme de fichiers réels plutôt que de chaînes clé/valeur.

Contrairement à storage.upload, ces fichiers restent côté serveur : ils ne sont jamais servis via HTTP. Chaque chemin est confiné au répertoire de votre plugin : un plugin ne peut pas lire les fichiers d'un autre plugin ni sortir de son bac à sable (../ et les chemins absolus sont réduits à l'intérieur).

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

Accorde owncast.http.fetch(url, opts?) : HTTP sortant synchrone.

Nécessite une liste network.allowedHosts en complément dans le manifeste. L'hôte rejette le chargement si network.fetch est accordé sans liste d'autorisation. Chaque appel est vérifié contre la liste d'autorisation. Les hôtes qui ne correspondent pas retournent une erreur avant que des octets ne quittent le serveur.

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

Le caractère générique "*" est autorisé mais doit être écrit explicitement afin que les administrateurs examinant le manifeste voient la portée. L'UI administrateur affiche la liste complète des allowedHosts dans l'onglet Autorisations à côté de la ligne network.fetch, donc un opérateur de serveur examinant un plugin voit exactement quels hôtes il peut atteindre sans déballer le .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

Accorde à l'API du routeur HTTP de l'hôte la permission d'envoyer des requêtes à /plugins/<your-slug>/* à votre plugin. Cela inclut à la fois les fichiers statiques dans votre répertoire public/ et les requêtes dynamiques routées vers votre gestionnaire onHttpRequest.

Sans cette autorisation, tout l'espace d'URL /plugins/<your-slug>/ retourne 404.

http.sse

Accorde owncast.sse.send(channel, event, data) et expose un point de terminaison détenu par l'hôte à /plugins/<your-slug>/_sse/<channel> auquel les navigateurs se connectent avec EventSource. Indépendant de http.serve. Un plugin peut pousser des événements sans servir d'autres routes.

server.read

Accorde les API de flux en lecture seule et d'état du serveur :

  • owncast.stream.current() : état du flux en direct
  • owncast.stream.broadcaster() : télémétrie d'encodage entrant
  • owncast.server.info() : nom du serveur, version, résumé
  • owncast.server.socials() : liens sociaux configurés
  • owncast.server.emotes(): custom chat emotes configured on this server
  • owncast.server.federation() : paramètres du fediverse
  • owncast.server.tags() : tags configurés

videoconfig.read

Accorde owncast.videoConfig.read() : lire la configuration de sortie et de transcodage (codecs, niveau de latence, variantes de flux).

videoconfig.write

Accorde owncast.videoConfig.write(partial) : modifier la configuration de sortie vidéo.

Forte confiance. Les changements s'appliquent au prochain démarrage de flux. L'hôte ne redémarre pas une diffusion active. Les administrateurs devraient accorder parcimonieusement.

notifications.send

Accorde les API de notification du diffuseur :

  • owncast.notifications.discord(text) : via le webhook Discord configuré par le streamer
  • owncast.notifications.browserPush({ title, body, url? }) : aux navigateurs abonnés
  • owncast.notifications.fediverse({ type, body, image?, link? }) : notification formatée pour le fediverse

fediverse.inbound

Accorde l'abonnement à tous les sept événements entrants du plugin Fediverse :

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

L'objet JSON brut de l'activité vérifiée est reçu par fediverse.activity. Il s'exécute en complément de tout événement spécialisé correspondant. Cette permission ne couvre que la réception d'activité. Publier depuis le compte Owncast nécessite l'autorisation séparée fediverse.post.

fediverse.post

Accorde owncast.fediverse.post(text) : faire une publication publique au fediverse depuis le compte Owncast.

Forte confiance : les publications sortent sous la propre identification fediverse du streamer et ne peuvent pas être révoquées silencieusement. Les administrateurs devraient accorder parcimonieusement.

ui.modify

Accorde la capacité de placer une interface utilisateur à l'intérieur du chrome d'Owncast :

  • Déclarer manifest.actions (boutons d'action sous le flux).
  • Appeler owncast.actions.add(...) / .clear() à l'exécution.
  • Déclarer manifest.styles (CSS intégré dans la page du spectateur).
  • Déclarer manifest.scripts (JavaScript intégré dans la page du spectateur).
  • Déclarer manifest.extraPageContent (un bloc HTML ajouté à la zone de contenu supplémentaire du spectateur).
  • Déclarer manifest.tabs (onglets supplémentaires dans la ligne d'onglets de la page du spectateur).
  • Implémenter un gestionnaire onPageStyles ou onPageScripts (CSS ou JavaScript retourné au moment de la demande, sans champ de manifeste).

Sans cette autorisation, les manifestes qui déclarent l'un de ces champs sont rejetés lors du chargement. Les gestionnaires onPageStyles et onPageScripts n'ont pas de champ de manifeste, donc ils ne sont pas rejetés lors du chargement. L'hôte ne les appelle tout simplement pas à moins que le plugin détienne ui.modify. Chacun de ces éléments s'intègre dans la page du spectateur plutôt que de rester dans l'espace URL du plugin lui-même, donc l'administrateur doit voir la permission pour comprendre comment le plugin s'intègre à l'interface utilisateur de l'hôte.

Aucun des quatre champs d'injection de spectateur ne nécessite http.serve, et les deux gestionnaires non plus. L'hôte lit chaque fichier depuis le répertoire assets/ du plugin (et non depuis une URL), ou appelle le gestionnaire, et intègre le résultat dans les réponses configurées / JS personnalisées existantes, donc ui.modify seul suffit.

Tableau récapitulatif

PermissionAccès
chat.sendowncast.chat.send, .sendAction, .sendTo, .replyTo, .system
chat.historyowncast.chat.history, .clients
chat.moderateowncast.chat.deleteMessage, .kick
chat.filterAbonnez-vous à filterChatMessage (lire, modifier ou supprimer chaque message de chat).
users.readowncast.users.list, .get
users.moderateowncast.users.setEnabled, .banIP
users.registerowncast.users.register: trouver ou créer un utilisateur authentifié pour une identité externe
auth.gateowncast.auth.grantSession, .endSession, et le gestionnaire onAuthCheck: être la porte d'authentification du site
storage.kvMagasin de clés/valeurs par nom de plugin
storage.uploadTélécharger des fichiers dans l'espace public de fichiers d'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.fetchHTTP sortant. Nécessite également network.allowedHosts
events.emitÉmettre des événements personnalisés pour d'autres plugins
http.serveServir HTTP à /plugins/<your-slug>/*
http.sseEnvoyer des événements en temps réel via owncast.sse.send et le point de terminaison /_sse/
server.readLire l'état du flux, config du serveur, encoder la télémétrie
videoconfig.readLire la configuration de sortie/transcodage
videoconfig.writeModifier la configuration de sortie vidéo (appliqué au démarrage du prochain flux)
notifications.sendEnvoyer des notifications Discord, de navigateur, ou fediverse
fediverse.inboundAbonnez-vous à tous les sept événements entrants : fediverse.follow, .like, .repost, .quote, .mention, .reply, et .activity
fediverse.postPublication publique dans le fediverse (limité par le taux)
ui.modifyAjouter des boutons d'action ou des onglets au chrome du visualiseur d'Owncast. Intégrer CSS, JavaScript ou HTML de plugin dans la page du visualiseur

Principe du moindre privilège

Déclarez seulement ce que vous utilisez réellement. Plus votre manifeste est étroit, plus la décision de confiance de l'administrateur est facile. Si vous vous trouvez à énumérer chaque permission, prenez du recul et voyez si votre plugin devrait vraiment être deux plugins.

Si vous cessez d'utiliser une permission pendant le développement, retirez-la du manifeste. Réduire est silencieux. Il n'y a pas de friction à retirer des entrées non utilisées.


Improve this page

See something missing or incorrect? Edit the English version of this page or help improve translations.

Contributors to this documentation
Gabe KangasGabe Kangas
G
Gabe Kangas