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.
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.
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
-
Vous déclarez des autorisations dans
plugin.manifest.json:{ "permissions": ["chat.send", "storage.kv"] } -
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.
-
L'hôte les applique à l'exécution. 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. -
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 pluginowncast.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 oversendTo)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 chatowncast.chat.clients(): lister les clients de chat connectés
Lecture seule.
chat.moderate
Accorde :
owncast.chat.deleteMessage(messageId): cacher un message aux spectateursowncast.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 chatowncast.users.get(id): lire un enregistrement d'utilisateur unique
users.moderate
Accorde :
owncast.users.setEnabled(id, enabled, reason?): activer ou désactiver un utilisateurowncast.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é (voirusers.register)owncast.auth.endSession(): effacer la session actuelle du spectateur (déconnexion)- le gestionnaire
onAuthCheckoptionnel : 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 directowncast.stream.broadcaster(): télémétrie d'encodage entrantowncast.server.info(): nom du serveur, version, résuméowncast.server.socials(): liens sociaux configurésowncast.server.emotes(): custom chat emotes configured on this serverowncast.server.federation(): paramètres du fediverseowncast.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 streamerowncast.notifications.browserPush({ title, body, url? }): aux navigateurs abonnésowncast.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.followfediverse.likefediverse.repostfediverse.quotefediverse.mentionfediverse.replyfediverse.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
onPageStylesouonPageScripts(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
| Permission | Accès |
|---|---|
chat.send | owncast.chat.send, .sendAction, .sendTo, .replyTo, .system |
chat.history | owncast.chat.history, .clients |
chat.moderate | owncast.chat.deleteMessage, .kick |
chat.filter | Abonnez-vous à filterChatMessage (lire, modifier ou supprimer chaque message de chat). |
users.read | owncast.users.list, .get |
users.moderate | owncast.users.setEnabled, .banIP |
users.register | owncast.users.register: trouver ou créer un utilisateur authentifié pour une identité externe |
auth.gate | owncast.auth.grantSession, .endSession, et le gestionnaire onAuthCheck: être la porte d'authentification du site |
storage.kv | Magasin de clés/valeurs par nom de plugin |
storage.upload | Télécharger des fichiers dans l'espace public de fichiers d'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 | HTTP sortant. Nécessite également network.allowedHosts |
events.emit | Émettre des événements personnalisés pour d'autres plugins |
http.serve | Servir HTTP à /plugins/<your-slug>/* |
http.sse | Envoyer des événements en temps réel via owncast.sse.send et le point de terminaison /_sse/ |
server.read | Lire l'état du flux, config du serveur, encoder la télémétrie |
videoconfig.read | Lire la configuration de sortie/transcodage |
videoconfig.write | Modifier la configuration de sortie vidéo (appliqué au démarrage du prochain flux) |
notifications.send | Envoyer des notifications Discord, de navigateur, ou fediverse |
fediverse.inbound | Abonnez-vous à tous les sept événements entrants : fediverse.follow, .like, .repost, .quote, .mention, .reply, et .activity |
fediverse.post | Publication publique dans le fediverse (limité par le taux) |
ui.modify | Ajouter 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.
Gabe Kangas