security: critical fixes (test route, edit authz, nostr signature, calendar IDOR)

- Remove unauthenticated /test route that dispatched FetchNostrProfileJob
  for a hardcoded user (routes/web.php).
- Enforce created_by ownership check in meetup and lecturer Livewire edit
  components; mirror the existing services/edit pattern.
- Replace blind-trust nostrLoggedIn handler with NIP-42-style signed event
  verification: server-issued challenge stored in session, client signs a
  kind:22242 event, server verifies signature via swentel/nostr-php and
  derives npub. Challenge is single-use with 5-minute TTL.
- Validate the ?my[] parameter on the calendar download endpoint as an
  array of integers and intersect with the authenticated user's meetups.
This commit is contained in:
Claude
2026-05-03 12:51:10 +00:00
parent 1f9e5309d2
commit 90835f8b1f
6 changed files with 139 additions and 20 deletions
+15 -7
View File
@@ -1,5 +1,3 @@
import {npubEncode} from "nostr-tools/nip19";
export default () => ({
pollingInterval: null,
errorCheckInterval: null,
@@ -13,11 +11,21 @@ export default () => ({
},
async openNostrLogin() {
const pubkey = await window.nostr.getPublicKey();
const npub = npubEncode(pubkey);
console.log(pubkey);
console.log(npub);
this.$dispatch('nostrLoggedIn', {pubkey: npub});
const livewireComponent = this.$el.closest('[wire\\:id]')?.__livewire;
const challenge = livewireComponent?.$wire?.nostrChallenge;
if (!challenge) {
this.showAuthError('Login challenge missing. Please reload and try again.');
return;
}
const signedEvent = await window.nostr.signEvent({
kind: 22242,
created_at: Math.floor(Date.now() / 1000),
tags: [['challenge', challenge]],
content: '',
});
this.$dispatch('nostrLoggedIn', {signedEvent});
},
initErrorPolling() {