feat(auth,a11y): Telegram CloudStorage token recovery + blocking-screen a11y

Telegram CloudStorage token recovery (resilience against WebView localStorage wipes):
- mirror the refresh token to per-user CloudStorage on login, remove it on logout
- restoreRefreshTokenFromCloud() recovers the refresh token in initialize() when
  localStorage is empty, then the normal refresh flow re-establishes the session
- move the initialize() bootstrap call from auth.ts module-load into main.tsx after
  the Telegram SDK init(), since launch params + CloudStorage are unavailable before init
- best-effort: no-ops outside Telegram and on any error -> falls back to prior behavior

Accessibility:
- role=alertdialog + aria-modal + aria-labelledby + focus management (useFocusTrap)
  on Maintenance, Blacklisted, ChannelSubscription and AccountDeleted blocking screens
- aria-label on ColorPicker Hue/Saturation/Lightness range inputs
This commit is contained in:
c0mrade
2026-05-25 23:43:17 +03:00
parent 0caba3dffb
commit f31160208a
8 changed files with 122 additions and 13 deletions

View File

@@ -13,7 +13,12 @@ import {
consumeReferralCode,
getPendingReferralCode,
} from '../utils/referral';
import { tokenStorage, isTokenValid, tokenRefreshManager } from '../utils/token';
import {
tokenStorage,
isTokenValid,
tokenRefreshManager,
restoreRefreshTokenFromCloud,
} from '../utils/token';
import { usePermissionStore } from './permissions';
export interface TelegramWidgetData {
@@ -162,11 +167,16 @@ export const useAuthStore = create<AuthState>()(
tokenStorage.migrateFromLocalStorage();
const accessToken = tokenStorage.getAccessToken();
const refreshToken = tokenStorage.getRefreshToken();
let refreshToken = tokenStorage.getRefreshToken();
if (!refreshToken) {
set({ isLoading: false, isAuthenticated: false });
return;
// localStorage may have been wiped by the Telegram WebView; try to
// recover the refresh token from Telegram CloudStorage before giving up.
refreshToken = await restoreRefreshTokenFromCloud();
if (!refreshToken) {
set({ isLoading: false, isAuthenticated: false });
return;
}
}
if (!isTokenValid(accessToken)) {
@@ -384,4 +394,5 @@ export const useAuthStore = create<AuthState>()(
captureCampaignFromUrl();
captureReferralFromUrl();
useAuthStore.getState().initialize();
// Note: initialize() is kicked off from main.tsx after the Telegram SDK is set up,
// so CloudStorage-backed token recovery can run during bootstrap.