Files
proxy-manager/manifest.ts
T
pastilhas da86186df2 say what this plugin is for, in the store's words
tags are how the marketplace is browsed rather than scrolled: a list of them on
the left, the plugins that carry one on the right. a closed vocabulary
(PLUGIN_TAGS in the platform) because free text becomes homelab, home-lab, Home
Lab and selfhosted inside a month, and a filter list of synonyms is worse than
no filter at all.

declared here rather than curated in the catalogue, so a plugin can say what it
is and nobody edits a table when one ships. the marketplace caches it on sync,
exactly as it already does for label and summary.
2026-08-27 06:49:35 +00:00

54 lines
2.5 KiB
TypeScript

import type { PluginManifest } from '@@/plugins/manifest';
// Nginx Proxy Manager, inside Officer.
//
// ── The name ──
//
// The container is called `npm` and the owner calls it NPM. This plugin is `proxy-manager` anyway: in a
// repository where every other sentence is about bun, lockfiles and `npm install`, a plugin directory
// called `npm` would collide with the package manager in every grep and every conversation. The label
// says the real name; the id says what it does. Same reasoning that renamed `officer-claude` to
// `officer-anthropic-proxy`.
//
// ── The permission, and why settings are carved out ──
//
// Reading which hosts exist, whether their certificates are healthy and whether one is offline is
// genuinely useful to somebody who is not the owner. The CREDENTIAL is not: it is an NPM admin login,
// and NPM has no read-only role, so anyone holding it can redirect any hostname on this machine.
//
// So the permission is grantable and `/_config` is owner-only — the split `ownerOnly` exists for, and
// the same shape Jellyfin uses for its admin token.
export const manifest: PluginManifest = {
publisher: 'officerdev',
version: '0.1.0',
platform: '>=1.0.0',
label: 'Proxy Manager',
summary: 'Nginx Proxy Manager — hosts, certificates and access lists',
/** what is exposed, and the certificates for it. */
tags: ['Server Management', 'Security'],
icon: 'Route',
color: '#f97316',
permissions: [
{
key: 'proxy-manager',
label: 'Proxy Manager',
description: 'Nginx Proxy Manager — proxy hosts, redirections, streams and certificates',
// The connection form and the probe. Everything under here reads or writes the admin credential,
// and the match is by PREFIX — so `/_config/test` is covered too, deliberately.
//
// There is no `readOnlyWrites` here, and the omission is the decision rather than an oversight.
// `POST /_config/test` is a genuine read-only write: it validates a credential and stores nothing.
// Declaring it would still change nothing, because `authorize.ts` asks `isOwnerOnlyRoute` before
// `isRequestAllowedAtLevel` — ownerOnly wins, so the entry would be inert.
//
// And it should be inert. The test request carries the admin secret in its BODY. A member who can
// call it can offer this server a credential and be told whether it works, which is an oracle
// pointed at somebody else's password. Testing a connection belongs to whoever owns it.
ownerOnly: ['/_config'],
},
],
};