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:
@@ -57,10 +57,9 @@ export function WidgetCatalogModal({
|
||||
<div
|
||||
className="fixed inset-0 z-50 flex items-center justify-center"
|
||||
onClick={onClose}
|
||||
aria-hidden="true"
|
||||
>
|
||||
{/* Backdrop */}
|
||||
<div className="fixed inset-0 bg-black/50" />
|
||||
{/* Backdrop — visually only, hidden from assistive tech */}
|
||||
<div className="fixed inset-0 bg-black/50" aria-hidden="true" />
|
||||
|
||||
{/* Dialog */}
|
||||
<div
|
||||
|
||||
@@ -337,7 +337,6 @@ export function CalculatorWidget({ isEditMode }: WidgetProps) {
|
||||
<button type="button" className={memBtn} onClick={memoryAdd}>M+</button>
|
||||
<button type="button" className={memBtn} onClick={memorySubtract}>M−</button>
|
||||
<button type="button" className={memBtn} onClick={memoryStore}>MS</button>
|
||||
<button type="button" className={memBtn} onClick={memoryRecall} disabled={memory === 0}>M</button>
|
||||
</div>
|
||||
|
||||
{/* Keypad — 4 columns × 5 rows */}
|
||||
|
||||
@@ -70,8 +70,7 @@ export function FavoritesWidget({
|
||||
const data = await fetchFavorites(instanceId);
|
||||
if (!cancelled) setFavorites(data);
|
||||
} catch {
|
||||
// Use a stable error key — t is excluded from deps intentionally
|
||||
if (!cancelled) setError('favorites.error');
|
||||
if (!cancelled) setError(t('favorites.error'));
|
||||
} finally {
|
||||
if (!cancelled) setLoading(false);
|
||||
}
|
||||
|
||||
@@ -63,7 +63,7 @@ export function LinkWidget({
|
||||
if (!cancelled) setLink(data[0] ?? null);
|
||||
} catch {
|
||||
// Stable error key — t excluded from deps to prevent re-fetch loops
|
||||
if (!cancelled) setError('link.error');
|
||||
if (!cancelled) setError(t('link.error'));
|
||||
} finally {
|
||||
if (!cancelled) setLoading(false);
|
||||
}
|
||||
@@ -107,7 +107,7 @@ export function LinkWidget({
|
||||
setNewTitle('');
|
||||
setNewUrl('');
|
||||
} catch {
|
||||
setError('link.error');
|
||||
setError(t('link.error'));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -144,7 +144,7 @@ export function LinkWidget({
|
||||
setLink(updated);
|
||||
cancelEdit();
|
||||
} catch {
|
||||
setError('link.error');
|
||||
setError(t('link.error'));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -156,7 +156,7 @@ export function LinkWidget({
|
||||
setLink(null);
|
||||
cancelEdit();
|
||||
} catch {
|
||||
setError('link.error');
|
||||
setError(t('link.error'));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user