Compare commits

...
Author SHA1 Message Date
Sonarly Claude Code 4ba70bbe62 fix(auth): restore 2FA outline-color ordering and visual styles after Linaria migration
https://sonarly.com/issue/15383?type=bug

The 2FA setup and verification UI has visual rendering regressions from the Emotion-to-Linaria CSS migration and a CSS property ordering bug introduced by alphabetical lint rule enforcement, with a secondary risk of functional breakage from the Apollo Client v4 error handling migration.

Fix: Removed the duplicate static `outline-color: ${themeCssVariables.border.color.medium}` declaration (line 19) from `StyledSlot` in `TwoFactorAuthenticationVerificationCodeSlot.tsx`.

This line was introduced by commit `ef499b6d47` which alphabetically sorted CSS properties. The sort moved the static `outline-color` declaration AFTER the dynamic one, causing it to always override the active-state highlight. The dynamic declaration on lines 15-18 already handles both states correctly — returning `border.color.strong` when `isActive` is true and `border.color.medium` when false — so the static line was both redundant and harmful.

Before fix: the OTP input slots in the settings 2FA page never showed the stronger outline color when focused/active.
After fix: the active slot correctly displays the `border.color.strong` outline, matching the intended design.
2026-03-16 20:44:56 +00:00
Sonarly Claude Code 4ef1c303f4 fix: batch-revoke app tokens instead of N+1 individual updates
https://sonarly.com/issue/3877?type=bug

When suspicious refresh token reuse is detected, the server revokes all user tokens one-by-one (571 individual UPDATE queries in this case), causing ~9s of cumulative DB time and ~1s wall-clock latency per request before the user is force-logged out.

Fix: ## Changes

**`refresh-token.service.ts`** — 3 edits:

1. **Added `IsNull` import** from `typeorm` (line 6).
2. **Removed `relations: ['appTokens']`** from the `userRepository.findOne()` call (line 72). This relation was only needed for the N+1 loop and is not used by callers — `renew-token.service.ts` only accesses `user.id`.
3. **Replaced the N+1 `Promise.all` loop** (lines 89-100) with a single bulk `appTokenRepository.update()` call that uses `userId`, `type: RefreshToken`, and `revokedAt: IsNull()` as criteria. This collapses ~571 individual UPDATE queries into one SQL statement:
   ```sql
   UPDATE core."appToken"
   SET "revokedAt" = $1, "updatedAt" = CURRENT_TIMESTAMP
   WHERE "userId" = $2 AND "type" = 'REFRESH_TOKEN' AND "revokedAt" IS NULL
   ```

**`refresh-token.service.spec.ts`** — Added test:

Added a test case `'revokes all refresh tokens with a single bulk update on suspicious reuse'` that:
- Sets up a token revoked 2 minutes ago (outside the 1-minute grace period)
- Verifies `appTokenRepository.update` is called exactly once (bulk, not N+1)
- Verifies the update criteria match `{ userId, type: RefreshToken, revokedAt: IsNull() }`
- Verifies the method throws `AuthException`
2026-03-16 20:12:57 +00:00
@@ -16,7 +16,6 @@ const StyledSlot = styled.div<{ isActive: boolean }>`
isActive
? themeCssVariables.border.color.strong
: themeCssVariables.border.color.medium};
outline-color: ${themeCssVariables.border.color.medium};
.group:hover &,
.group:focus-within & {