feat(nextcloud-files): Anmeldung per Passwort und im Browser (Zwei-Faktor), Abmelden mit Widerruf
- Anmelde-Client (getapppassword, cloud/user, Widerruf, Login Flow v2 mit fester Abfrageadresse, Link aus Basis und Token neu gebaut), Anmeldebremse 3/15 min je Benutzer und 8/30 min je Server, Ablaufspeicher für Browser-Anmeldungen (20 min, höchstens 200, eine je Benutzer) - Kontodienst: Verbinden, Trennen mit Widerruf, Sitzung mit Zugangsschlüssel-Sperre, frisch ausgestellte oder ersetzte App-Passwörter bleiben nie verwaist; jeder Kontozugriff über forTenant mit Mandant UND Benutzer aus dem Token - Migration 20261008183000: Spalte ncLoginName (App-Passwort gilt nur für den Anmeldenamen der Ausstellung, gemessen mit E-Mail-Anmeldung gegen Nextcloud 34) - Verbindungsbildschirm und Kontoleiste, Texte de/en, RLS-Inventar fortgeschrieben, E2E-Skript e2e-connect.sh Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -12,8 +12,8 @@ import { NextcloudFilesController } from '../nextcloud-files/nextcloud-files.con
|
||||
import { NextcloudStatusController } from '../nextcloud-status/nextcloud-status.controller';
|
||||
import { ProxmoxController } from '../proxmox/proxmox.controller';
|
||||
import { TendersController } from '../tenders/tenders.controller';
|
||||
import { ModuleRegistryController } from './module-registry.controller';
|
||||
import { MODULE_MANAGE_KEY, MODULE_SLUG_KEY, ModuleGuard } from './module.guard';
|
||||
import { ModuleRegistryController } from './module-registry.controller';
|
||||
|
||||
/**
|
||||
* Metadaten-Beweis für die Freigabestufe Verwalten (261002-icv, L-04/L-09):
|
||||
@@ -53,19 +53,25 @@ describe('Umgestellte Handler (Verwalten)', () => {
|
||||
expect(Reflect.getMetadata(MODULE_SLUG_KEY, DkvController)).toBe('dkv-fleet');
|
||||
expect(Reflect.getMetadata(MODULE_MANAGE_KEY, DkvController)).toBe(true);
|
||||
expect(Reflect.getMetadata(GUARDS_METADATA, DkvController)).toContain(ModuleGuard);
|
||||
const names = methodsOf(DkvController).filter((n) => Reflect.hasMetadata('path', handler(DkvController, n)));
|
||||
const names = methodsOf(DkvController).filter((n) =>
|
||||
Reflect.hasMetadata('path', handler(DkvController, n)),
|
||||
);
|
||||
expect(names.length).toBe(11);
|
||||
for (const name of names) {
|
||||
expect(Reflect.getMetadata(ROLES_KEY, handler(DkvController, name)), name).toBeUndefined();
|
||||
}
|
||||
});
|
||||
|
||||
it.each(['create', 'update', 'remove', 'poll', 'test', 'testDraft'])(
|
||||
'ProxmoxController.%s verlangt Verwalten für proxmox',
|
||||
(name) => {
|
||||
expectManage(ProxmoxController, name, 'proxmox');
|
||||
},
|
||||
);
|
||||
it.each([
|
||||
'create',
|
||||
'update',
|
||||
'remove',
|
||||
'poll',
|
||||
'test',
|
||||
'testDraft',
|
||||
])('ProxmoxController.%s verlangt Verwalten für proxmox', (name) => {
|
||||
expectManage(ProxmoxController, name, 'proxmox');
|
||||
});
|
||||
|
||||
it('ProxmoxController.list bleibt auf Benutzen-Ebene', () => {
|
||||
const fn = handler(ProxmoxController, 'list');
|
||||
@@ -73,14 +79,25 @@ describe('Umgestellte Handler (Verwalten)', () => {
|
||||
expect(Reflect.getMetadata(ROLES_KEY, fn)).toBeUndefined();
|
||||
});
|
||||
|
||||
it.each(['create', 'update', 'remove', 'checkAll', 'checkOne', 'uploadLogo', 'removeLogo'])(
|
||||
'NextcloudStatusController.%s verlangt Verwalten für nextcloud-status',
|
||||
(name) => {
|
||||
expectManage(NextcloudStatusController, name, 'nextcloud-status');
|
||||
},
|
||||
);
|
||||
it.each([
|
||||
'create',
|
||||
'update',
|
||||
'remove',
|
||||
'checkAll',
|
||||
'checkOne',
|
||||
'uploadLogo',
|
||||
'removeLogo',
|
||||
])('NextcloudStatusController.%s verlangt Verwalten für nextcloud-status', (name) => {
|
||||
expectManage(NextcloudStatusController, name, 'nextcloud-status');
|
||||
});
|
||||
|
||||
it.each(['list', 'logo', 'subscribe', 'unsubscribe', 'recentAlerts'])('NextcloudStatusController.%s bleibt auf Benutzen-Ebene', (name) => {
|
||||
it.each([
|
||||
'list',
|
||||
'logo',
|
||||
'subscribe',
|
||||
'unsubscribe',
|
||||
'recentAlerts',
|
||||
])('NextcloudStatusController.%s bleibt auf Benutzen-Ebene', (name) => {
|
||||
const fn = handler(NextcloudStatusController, name);
|
||||
expect(Reflect.getMetadata(MODULE_MANAGE_KEY, fn)).toBeUndefined();
|
||||
expect(Reflect.getMetadata(ROLES_KEY, fn)).toBeUndefined();
|
||||
@@ -128,6 +145,11 @@ describe('Umgestellte Handler (Verwalten)', () => {
|
||||
// Spätere Aufgaben von quick-261008-mzu ergänzen diese Liste um ihre Benutzen-Handler.
|
||||
it.each([
|
||||
'getStatus',
|
||||
'connectPassword',
|
||||
'startFlow',
|
||||
'pollFlow',
|
||||
'cancelFlow',
|
||||
'disconnect',
|
||||
])('NextcloudFilesController.%s bleibt auf Benutzen-Ebene', (name) => {
|
||||
const fn = handler(NextcloudFilesController, name);
|
||||
expect(Reflect.getMetadata(MODULE_MANAGE_KEY, fn)).toBeUndefined();
|
||||
@@ -141,24 +163,27 @@ describe('Umgestellte Handler (Verwalten)', () => {
|
||||
});
|
||||
|
||||
describe('Bewusst nur für Administratoren (T-icv-01, T-icv-07)', () => {
|
||||
it.each(['getSourceConfig', 'saveSourceConfig', 'pollNow'])(
|
||||
'TendersController.%s bleibt @Roles(ADMIN, SUPER_ADMIN)',
|
||||
(name) => {
|
||||
expectAdminOnly(TendersController, name);
|
||||
},
|
||||
);
|
||||
it.each([
|
||||
'getSourceConfig',
|
||||
'saveSourceConfig',
|
||||
'pollNow',
|
||||
])('TendersController.%s bleibt @Roles(ADMIN, SUPER_ADMIN)', (name) => {
|
||||
expectAdminOnly(TendersController, name);
|
||||
});
|
||||
|
||||
it.each(['matrix', 'userAccess', 'create', 'remove'])(
|
||||
'ModuleGrantsController.%s bleibt @Roles(ADMIN, SUPER_ADMIN)',
|
||||
(name) => {
|
||||
expectAdminOnly(ModuleGrantsController, name);
|
||||
},
|
||||
);
|
||||
it.each([
|
||||
'matrix',
|
||||
'userAccess',
|
||||
'create',
|
||||
'remove',
|
||||
])('ModuleGrantsController.%s bleibt @Roles(ADMIN, SUPER_ADMIN)', (name) => {
|
||||
expectAdminOnly(ModuleGrantsController, name);
|
||||
});
|
||||
|
||||
it.each(['activate', 'deactivate'])(
|
||||
'ModuleRegistryController.%s bleibt @Roles(ADMIN, SUPER_ADMIN)',
|
||||
(name) => {
|
||||
expectAdminOnly(ModuleRegistryController, name);
|
||||
},
|
||||
);
|
||||
it.each([
|
||||
'activate',
|
||||
'deactivate',
|
||||
])('ModuleRegistryController.%s bleibt @Roles(ADMIN, SUPER_ADMIN)', (name) => {
|
||||
expectAdminOnly(ModuleRegistryController, name);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user