Die Ladezeiten der Bilder ist zu hoch, weil die Original geladen werden.
Bei /association/project-support lade in der Übersicht und in der Einzel-Ansicht /association/project-support/badgebox-for-nostr-manage-your-badges nur die Conversions der Bilder, also die kleinere Versionen.
## Security Audit: Fehlende zentralisierte Autorisierung
### Problem
Die Anwendung hat **keine Laravel Policy-Klassen**. Autorisierungslogik ist verstreut in:
- **Blade Templates:** Inline `@if`-Checks gegen `config('einundzwanzig.config.current_board')`
- **Livewire Trait:** `app/Livewire/Traits/WithNostrAuth.php` setzt `$isAllowed` und `$canEdit` Booleans
- **Component-Mount-Methoden:** z.B. in `project-support/form/create.blade.php` (Zeile 41-47)
Die Board-Member-Autorisierung funktioniert über einen Vergleich mit hartkodierten npubs in `config/einundzwanzig/config.php`:
```php
'current_board' => [
'npub1pt0kw36...', 'npub1gvqkjc...', // etc.
]
```
**Probleme:**
- Keine zentrale Stelle für Berechtigungsprüfungen
- Autorisierung kann leicht vergessen werden wenn neue Endpoints hinzukommen
- Board-Member-Check wird an vielen Stellen dupliziert
- Livewire-Actions können ggf. direkt aufgerufen werden ohne UI-seitige Prüfung
### Lösung
**1. Laravel Policies erstellen:**
```bash
php artisan make:policy ProjectProposalPolicy --model=ProjectProposal --no-interaction
php artisan make:policy VotePolicy --model=Vote --no-interaction
php artisan make:policy ElectionPolicy --model=Election --no-interaction
```
**2. Policy-Methoden implementieren:**
Für `ProjectProposalPolicy`:
- `viewAny()` – Jeder darf die Liste sehen
- `view()` – Jeder darf ein Proposal sehen
- `create()` – Nur authentifizierte User mit `association_status > 1` und bezahlter Mitgliedschaft im aktuellen Jahr
- `update()` – Nur der Ersteller ODER Board-Members
- `delete()` – Nur Board-Members
- `accept()` – Nur Board-Members (custom method für `accepted`-Flag)
Für `VotePolicy`:
- `create()` – Authentifizierte User, die noch nicht für dieses Proposal abgestimmt haben
- `update()` / `delete()` – Nur der eigene Vote
Für `ElectionPolicy`:
- `viewAny()` / `view()` – Jeder
- `create()` / `update()` / `delete()` – Nur Board-Members
- `vote()` – Authentifizierte Mitglieder mit gültigem Status
**3. Auth-Checks in der Nostr-Auth-Architektur:**
Die App nutzt eine Custom NostrAuth (`app/Support/NostrAuth.php`, `app/Auth/NostrUser.php`). Die Policies müssen mit `NostrUser` funktionieren. Prüfe ob `NostrUser` das `Authenticatable` Interface korrekt implementiert, damit `$this->authorize()` und `Gate::allows()` in Livewire-Components funktionieren.
**4. Policies in Livewire-Components nutzen:**
Ersetze die inline-Checks in den Components durch Policy-Aufrufe:
```php
// Vorher (verstreut in Blade/Component):
if (in_array($this->currentPleb->npub, config('einundzwanzig.config.current_board'), true)) { ... }
// Nachher (zentralisiert):
$this->authorize('update', $projectProposal);
```
### Betroffene Dateien
- **Neue Dateien:** `app/Policies/ProjectProposalPolicy.php`, `app/Policies/VotePolicy.php`, `app/Policies/ElectionPolicy.php`
- **Anpassen:** `app/Livewire/Traits/WithNostrAuth.php` – Board-Check in Policy auslagern
- **Anpassen:** Livewire-Components in `app/Livewire/Association/ProjectSupport/` – `$this->authorize()` nutzen
- **Anpassen:** Livewire-Components in `app/Livewire/Association/Election/` – `$this->authorize()` nutzen
- **Prüfen:** `app/Auth/NostrUser.php` – Kompatibilität mit Policy-System
- **Prüfen:** `config/einundzwanzig/config.php` – Board-Member-Liste wird weiterhin als Datenquelle genutzt
### Vorgehen
1. `search-docs` nutzen: `queries: ['policies', 'authorization', 'gates']` und `packages: ['laravel/framework']`
2. Prüfe wie `NostrUser` mit Laravel's Authorization-System zusammenspielt
3. Policies mit `php artisan make:policy` erstellen
4. Policy-Methoden implementieren (Board-Check-Logik zentralisieren)
5. Livewire-Components auf Policy-Aufrufe umstellen
6. Blade-Templates: `@can` / `@cannot` Directives nutzen statt inline `@if`
7. Pest Feature-Tests für jede Policy-Methode schreiben
8. `vendor/bin/pint --dirty` und `php artisan test --compact`
### Akzeptanzkriterien
- 3 Policy-Klassen existieren und sind registriert
- Board-Member-Check ist an EINER Stelle definiert (in Policy oder Helper)
- Livewire-Components nutzen `$this->authorize()` statt inline-Checks
- Blade-Templates nutzen `@can` / `@cannot` Directives
- Pest-Tests decken alle Policy-Methoden ab (allow & deny)
- Bestehende Funktionalität bleibt erhalten
- ✅ Introduce `getSignedMediaUrl` in models for temporary signed URLs
- 🗂️ Migrate media collections to private disk for added security
- 🔧 Add `media:move-to-private` command to streamline migration
- ⚙️ Update views and components to use signed media URLs
- ✏️ Adjust route `media.signed` for signed file access handling
🔒 refactor(auth): streamline access control logic in election and project support forms
✨ add(styles): include partial styles for better layout management
🚀 feat(layout): integrate new styles partial into main layout for consistent design
🆕 create(partials): add styles partial to manage CSS styles more effectively
🗃️ refactor(project): rename project support route for clarity and consistency.
🗑️ chore(project): implement delete confirmation for project proposals in the index view.
🔧 fix(editor): adjust initialization delay for SimpleMDE editor to improve responsiveness.
📸 fix(media): update fallback image URL in ProjectProposal model for better asset management.
🔧 fix(ApplicationForm): change validation rule for reason to nullable string
📝 update(profile): simplify membership status messages and remove unnecessary fields
🎨 style(election): adjust import formatting for better readability
🎨 style(association): reduce icon sizes in association navigation links for consistency
🎨 style(app): reorder script includes for better organization in app layout
✨ feat(plebTable): implement confirmation dialogs for accepting and deleting entries in Pleb table
This commit introduces handling for logout events in nostr-login across various pages. When a user logs out, the current public key and other related information are reset to null. The nostrLogin.js file has also been updated to dispatch a 'nostrLoggedOut' event when this occurs. Additionally, the nostr-login package has been added to the project dependencies.
- Added a check to update the 'paid' status of a user's paymentEvents if the current year's payment has been made
- Updated the user profile view to display past payments
- Added 'paymentEvents' to the query in EinundzwanzigPlebTable.php to fetch the current year's payments
- Added a 'payment' column to the table in EinundzwanzigPlebTable.php to display the amount of the user's current year's payment
- Added the `simplesoftwareio/simple-qrcode` package to the project
- Created a new JavaScript file `nostrZap.js` to handle Nostr events
- Added the `nostrZap` function to the Alpine.js data property in `app.js`
- Updated the `services.php` configuration file to include the `nostr` environment variable
- Created a new database migration to add a `payment_event` field to the `einundzwanzig_plebs` table
- Made adjustments in the `Election:year.blade.php` view file to handle potential null values
- Updated `composer.lock` and `package.json` with the new dependencies
This commit updates the README file by removing previous Laravel content and adds information about maintainers in a new 'maintainers.yaml' file. It also includes a new "Issues/Feedback" link on the application's layout page.
This commit introduces a new changelog view that fetches and displays the git commit history. It also adds a navigation link to this changelog in the application layout.