# All files / src/utils authCleanup.ts

0% Statements 0/79
0% Branches 0/49
0% Functions 0/10
0% Lines 0/67

Press n or j to go to the next uncovered block, b, p or k for the previous block.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173

     /**
     * Utility functions for cleaning up authentication state
     * This helps prevent infinite refresh loops and auth errors
     */

    export const authCleanup = {
      /**
       * Clear all authentication data from localStorage and cookies
       */
      clearAllAuthData(): void {
        if (typeof window === 'undefined') return;

        try {
          // Clear localStorage
          localStorage.removeItem('iptv_auth_token');
          localStorage.removeItem('iptv_user_data');
          // Also clear any legacy keys if present
          localStorage.removeItem('auth_token');
          localStorage.removeItem('user_data');

          // Clear sessionStorage as well
          sessionStorage.removeItem('iptv_auth_token');
          sessionStorage.removeItem('iptv_user_data');
          sessionStorage.removeItem('auth_token');
          sessionStorage.removeItem('user_data');

          // Clear cookies
          const cookieNames = ['iptv_auth_token', 'iptv_user_data', 'auth_token', 'user_data'];
          const paths = ['/', '/admin', '/reseller'];
          for (const name of cookieNames) {
            // Standard root-path removal
            document.cookie = `${name}=; path=/; expires=Thu, 01 Jan 1970 00:00:00 GMT`;
            // Defensive: attempt to clear cookies that might have been set on sub-paths
            for (const p of paths) {
              document.cookie = `${name}=; path=${p}; expires=Thu, 01 Jan 1970 00:00:00 GMT`;
            }
          }

          // Auth data cleared successfully
        } catch {
          // Error clearing auth data - silently ignore
        }
      },

      /**
       * Check if token exists but is malformed
       */
      isTokenCorrupted(): boolean {
        if (typeof window === 'undefined') return false;

        try {
          const token = localStorage.getItem('iptv_auth_token');
          if (!token) return false;

          // Check if token has proper JWT structure (3 parts separated by dots)
          const parts = token.split('.');
          if (parts.length !== 3) return true;

          // Try to decode the payload
          try {
            const payload = JSON.parse(atob(parts[1]));
            // Check if payload has required fields
            if (!payload.exp || !payload.iat || !payload.sub) return true;

            return false;
          } catch {
            return true;
          }
        } catch {
          return true;
        }
      },

      /**
       * Check if user data exists but is malformed
       */
      isUserDataCorrupted(): boolean {
        if (typeof window === 'undefined') return false;

        try {
          const userData = localStorage.getItem('iptv_user_data');
          if (!userData) return false;

          const user = JSON.parse(userData);
          // Check if user has required fields
          if (!user.id || !user.username || !user.role) return true;

          return false;
        } catch {
          return true;
        }
      },

      /**
       * Perform a complete auth state check and cleanup if needed
       */
      performHealthCheck(): boolean {
        if (typeof window === 'undefined') return true;

        const tokenCorrupted = this.isTokenCorrupted();
        const userDataCorrupted = this.isUserDataCorrupted();

        if (tokenCorrupted || userDataCorrupted) {
          this.clearAllAuthData();
          return false;
        }

        return true;
      },

      /**
       * Safe redirect to login page
       */
      redirectToLogin(_reason?: string): void {
        if (typeof window === 'undefined') return;

        // Clear auth data first
        this.clearAllAuthData();

        // Use replace to avoid back button issues
        const currentPath = window.location.pathname;
        const sanitizedPath = sanitizeRedirectPath(currentPath) ?? '/';
        const redirectParam = sanitizedPath !== '/login' ? `?redirect=${encodeURIComponent(sanitizedPath)}` : '';

        window.location.replace(`/login${redirectParam}`);
      },

      /**
       * Initialize auth cleanup on page load
       */
      initialize(): void {
        if (typeof window === 'undefined') return;

        // Perform health check on load
        const isHealthy = this.performHealthCheck();

        if (!isHealthy) {
          // If auth data was corrupted, redirect to login after a short delay
          setTimeout(() => {
            this.redirectToLogin('Corrupted auth data detected');
          }, 100);
        }

        // Listen for storage events from other tabs
        window.addEventListener('storage', (e) => {
          if (e.key === 'iptv_auth_token' && !e.newValue) {
            // Token was removed in another tab
            this.clearAllAuthData();
            this.redirectToLogin('Logged out from another tab');
          }
        });

        // Listen for unhandled promise rejections that might be auth-related
        window.addEventListener('unhandledrejection', (event) => {
          const error = event.reason;
          if (error?.response?.status === 401 ||
              error?.message?.includes('401') ||
              error?.message?.includes('Unauthorized')) {
            this.redirectToLogin('Authentication error');
          }
        });
      }
    };

    // Auto-initialize when module is loaded
    if (typeof window !== 'undefined') {
      // Use setTimeout to ensure DOM is ready
      setTimeout(() => {
        authCleanup.initialize();
      }, 0);
    }
    import { sanitizeRedirectPath } from './routes';