fix(security): medium/low — event-lock, atomic config, a11y, diashow, hygiene
- social: likes/comments rejected on a closed event (e2e proven). - admin: patch_config validates-then-writes atomically; char-based length. - hashtag/comment models: atomic tag writes in edit + comment paths. - Modal: inert the background (modal-inert action) for screen readers. - sse.ts: idempotent visibilitychange listener (no duplicate reconnects). - diashow: videos advance on `ended` (transitions + page wiring). - docs/hygiene: README clone-case fix; removed stale committed .env.test and gitignored it; docker-compose.dev.yml tidy. Left documented as accepted-risk per plan: PIN-persist-after-logout, UUID-reachable hidden uploads, DECISION-media-auth.md. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -33,4 +33,39 @@ test.describe('Host — event lock', () => {
|
||||
// Currently no UI consumes the event-closed SSE on /feed. Add this banner
|
||||
// and flip fixme to test once it lands.
|
||||
});
|
||||
|
||||
// Regression for the review: likes/comments used to ignore uploads_locked_at,
|
||||
// so social writes still landed on a closed event. They now share the upload
|
||||
// handler's lock guard.
|
||||
test('a closed event rejects likes and comments', async ({ api, host, guest }) => {
|
||||
const BASE = process.env.E2E_FRONTEND_URL ?? 'http://localhost:3101';
|
||||
const g = await guest('SocialLocked');
|
||||
|
||||
// Upload while still open so there's a target to interact with.
|
||||
const { uploadRaw } = await import('../../helpers/upload-client');
|
||||
const { readFileSync } = await import('node:fs');
|
||||
const { join } = await import('node:path');
|
||||
const sample = join(process.cwd(), 'fixtures', 'media', 'sample.jpg');
|
||||
const upRes = await uploadRaw(g.jwt, readFileSync(sample), {
|
||||
filename: 'x.jpg',
|
||||
contentType: 'image/jpeg',
|
||||
});
|
||||
expect(upRes.status).toBe(201);
|
||||
const { id } = await upRes.json();
|
||||
|
||||
await api.closeEvent(host.jwt);
|
||||
|
||||
const likeRes = await fetch(`${BASE}/api/v1/upload/${id}/like`, {
|
||||
method: 'POST',
|
||||
headers: { Authorization: `Bearer ${g.jwt}` },
|
||||
});
|
||||
expect(likeRes.status).toBe(403);
|
||||
|
||||
const commentRes = await fetch(`${BASE}/api/v1/upload/${id}/comments`, {
|
||||
method: 'POST',
|
||||
headers: { Authorization: `Bearer ${g.jwt}`, 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ body: 'sollte blockiert sein' }),
|
||||
});
|
||||
expect(commentRes.status).toBe(403);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user