Berechtigungen und permissionsChange
Eine App bekommt genau die Berechtigungen, die sie in pithyx.json deklariert und ein Administrator bestätigt. Der Administrator kann jede später entziehen und wieder erteilen; das Fenster bekommt dann permissionsChange mit der vollständigen neuen Liste. Eine API zu benutzen erteilt nichts: Ein Aufruf ohne die Berechtigung scheitert mit app.permission.denied. Baue die Oberfläche aus app.context.permissions und halte sie mit dem Ereignis aktuell.
Die Berechtigungen
Abschnitt betitelt „Die Berechtigungen“| Berechtigung | Erlaubt der App |
|---|---|
files.read |
Dateien in freigegebenen Ordnern (mit files.shares) und Dateien, die der Benutzer ihr gibt, lesen |
files.write |
diese Dateien schreiben |
files.shares |
die freigegebenen Ordner des Benutzers listen und mit seinen Rechten durchsuchen |
notifications |
Benachrichtigungen mit app.notify zeigen |
directory.read |
alle Benutzer und Gruppen mit app.directory.users() und groups() listen |
network.internet |
Verbindungen ins Internet aus dem Fenster (connect-src https:) und aus dem Backend öffnen |
network.lan |
Verbindungen aus dem Backend zu anderen Geräten im lokalen Netzwerk öffnen; das Fenster und die Box selbst bleiben unerreichbar |
Alles andere braucht keine Berechtigung: der Kontext, Fensteraufrufe, app.storage, app.session, Logs, das Backend und Speicheranfragen, die der Administrator zugeordnet hat. Welche Benutzer die App überhaupt öffnen dürfen, ist eine eigene Freigabe pro Benutzer und Gruppe, keine Berechtigung der App.
Wer directory.read verlangt, bekommt im Installationsdialog den Vorschlag “nur Administratoren”, wie bei root-Containern und Sonderrechten; verlange es nur, wenn die App wirklich die Namen aller braucht.
Beispiel
Abschnitt betitelt „Beispiel“Das Manifest deklariert "permissions": ["notifications", "directory.read"]. Das Board funktioniert ohne beide und bietet mit ihnen mehr:
// A team board that offers what its permissions allow and follows when an administrator changes them.// pithyx.json declares: "permissions": ["notifications", "directory.read"]import { PithyxError, type DirectoryUser, type PithyxApp } from '@pithyx/sdk';
interface Features { notify: boolean; pickPeople: boolean;}
/** What the app may do now; context.permissions is always the current, complete list. */export function features(app: PithyxApp): Features { const has = (permission: string) => app.context.permissions.includes(permission); return { notify: has('notifications'), pickPeople: has('directory.read') };}
/** Everyone to assign a card to, or only the signed-in user without `directory.read`. */export async function people( app: PithyxApp,): Promise<Pick<DirectoryUser, 'id' | 'name' | 'displayName'>[]> { const { user } = app.context; if (!features(app).pickPeople) { return [{ id: user.id, name: user.name, displayName: user.displayName }]; } try { return await app.directory.users(); } catch (error) { // Revoked between the check and the call: the SDK or the daemon refuses with the missing permission. if (error instanceof PithyxError && error.code === 'app.permission.denied') { return [{ id: user.id, name: user.name, displayName: user.displayName }]; } throw error; }}
export async function remind(app: PithyxApp, title: string): Promise<boolean> { if (!features(app).notify) { return false; } try { await app.notify({ title, level: 'info', tag: 'board-reminder' }); return true; } catch (error) { if (error instanceof PithyxError && error.code === 'app.permission.denied') { return false; } throw error; }}
/** Renders once and again after every change; returns the function that stops following. */export function follow(app: PithyxApp, render: (features: Features) => void): () => void { render(features(app)); return app.on('permissionsChange', () => { // The SDK has replaced context.permissions and dropped its backend token before handlers run. render(features(app)); });}Wie Änderungen ankommen
Abschnitt betitelt „Wie Änderungen ankommen“- Bei der Installation listet der Dialog jede deklarierte Berechtigung, und der Administrator bestätigt sie. Ein Update, das eine neue Berechtigung deklariert, wartet, bis ein Administrator sie bestätigt; eine entzogene Berechtigung bleibt über Updates hinweg entzogen.
- Erteilt oder entzieht ein Administrator eine, bekommt jedes offene Fenster der App
permissionsChangemit der ganzen Liste. Bevor deine Handler laufen, ersetzt das SDKcontext.permissionsund verwirft sein Backend-Token, sodass der nächste Backend-Aufruf ein frisches bekommt. - Ein Aufruf, der eine entzogene Berechtigung braucht, scheitert mit
app.permission.denied;params.permissionnennt sie. Das SDK lehntdirectory.*sofort ab, der Daemon prüft jeden Aufruf erneut. - Verliert der Benutzer den Zugriff auf die App selbst (die Freigabe wird entzogen oder die App deaktiviert oder entfernt), schließen sich ihre Fenster, und die Sockets dieses Benutzers zum Backend werden geschlossen.
Sonderfälle
Abschnitt betitelt „Sonderfälle“- Wettlauf. Eine Berechtigung kann zwischen deiner Prüfung und deinem Aufruf verschwinden. Behandle
app.permission.deniedbei jedem Aufruf, der eine braucht, wie das Beispiel. network.internetsteckt in der Content-Security-Policy des Fensters, die der Browser beim Laden der Seite festlegt. Eine Änderung gilt für das Fenster nach einem Neuladen. Ein Backend bekommt oder verliert sein Internet-Netzwerk mit einem Neustart.network.lanwirkt für das Backend genauso.- Administratoren haben jede App, aber eine App hält trotzdem nur die Berechtigungen, die für sie bestätigt sind.
- Freigegebene Ordner brauchen
files.sharesfür die Liste undfiles.readoderfiles.writefür den Inhalt; der eigene Zugriff des Benutzers auf jeden freigegebenen Ordner gilt zusätzlich. Siehe Dateien und App-Speicher. - Mock-Desktop. Das Panel von
pithyx devlistet die Berechtigungen des Manifests als Schalter; jeder Schalter sendetpermissionsChange. Der Mock lehntnotifications,directory.*und seine Dateiaufrufe ohne die Berechtigung ab, wie die Box.
Fehlercodes
Abschnitt betitelt „Fehlercodes“app.permission.denied, app.token.invalid, app.app.not_found. Ein Administrator, der eine Berechtigung erteilt, die das Manifest nicht deklariert, bekommt app.permission.not_requested; die App sieht das nie.