fix(08): apply code review findings (CR-01, CR-02, WR-01–05, IN-01)

- CR-01: fix SSRF bypass — isPrivateIpv6 now delegates ::ffff:<ipv4> to
  isPrivateIpv4, covering 172.16-31.x and 169.254.x ranges
- CR-02: add ParseUUIDPipe to GET /favorites widgetId param + service guard
  so missing widgetId returns 400 instead of leaking all user favorites
- WR-01: link-widget — replace raw 'link.error' key with t('link.error') (4 sites)
- WR-02: favorites-widget — fix load-path error to use t('favorites.error')
- WR-03: widget-catalog-modal — move aria-hidden from outer wrapper to backdrop
- WR-04: calculator — remove duplicate M button (MR clone); MC/MR/M+/M−/MS remain
- WR-05: schema — add FavoriteLink→WidgetInstance FK with onDelete:Cascade
- IN-01: create-widget.dto.ts — update comment from four to eight supported types

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-07-01 11:03:16 +02:00
parent 54e4731b36
commit eebceb298d
9 changed files with 45 additions and 35 deletions
+2 -1
View File
@@ -1,4 +1,4 @@
import { Injectable, NotFoundException } from '@nestjs/common';
import { BadRequestException, Injectable, NotFoundException } from '@nestjs/common';
import { PrismaService } from '../prisma/prisma.service';
import { CreateFavoriteDto } from './dto/create-favorite.dto';
import { UpdateFavoriteDto } from './dto/update-favorite.dto';
@@ -24,6 +24,7 @@ export class FavoritesService {
* Scoped by userId AND widgetId (Pitfall 3 — separate widgets must not share links).
*/
async list(userId: string, widgetId: string) {
if (!widgetId) throw new BadRequestException('widgetId is required');
return this.prisma.favoriteLink.findMany({
where: { userId, widgetId },
orderBy: [{ position: 'asc' }, { title: 'asc' }],