mirror of
https://github.com/pacnpal/thrilltrack-explorer.git
synced 2025-12-20 07:51:13 -05:00
feat: Execute full production readiness plan
This commit is contained in:
@@ -81,7 +81,7 @@ export function MFARemovalDialog({ open, onOpenChange, factorId, onSuccess }: MF
|
||||
|
||||
toast.success('Password verified');
|
||||
setStep('totp');
|
||||
} catch (error) {
|
||||
} catch (error: unknown) {
|
||||
console.error('Password verification failed:', error);
|
||||
toast.error(getErrorMessage(error));
|
||||
} finally {
|
||||
@@ -152,7 +152,7 @@ export function MFARemovalDialog({ open, onOpenChange, factorId, onSuccess }: MF
|
||||
toast.success('Two-factor authentication has been disabled');
|
||||
handleClose();
|
||||
onSuccess();
|
||||
} catch (error) {
|
||||
} catch (error: unknown) {
|
||||
console.error('MFA removal failed:', error);
|
||||
toast.error(getErrorMessage(error));
|
||||
} finally {
|
||||
|
||||
@@ -75,7 +75,7 @@ export function TOTPSetup() {
|
||||
setSecret(data.totp.secret);
|
||||
setFactorId(data.id);
|
||||
setEnrolling(true);
|
||||
} catch (error) {
|
||||
} catch (error: unknown) {
|
||||
logger.error('Failed to start TOTP enrollment', {
|
||||
userId: user?.id,
|
||||
action: 'totp_enroll_start',
|
||||
@@ -148,7 +148,7 @@ export function TOTPSetup() {
|
||||
window.location.href = '/auth';
|
||||
}, 2000);
|
||||
}
|
||||
} catch (error) {
|
||||
} catch (error: unknown) {
|
||||
logger.error('TOTP verification failed', {
|
||||
userId: user?.id,
|
||||
action: 'totp_verify',
|
||||
|
||||
@@ -70,7 +70,7 @@ export function AccountDeletionDialog({ open, onOpenChange, userEmail, onDeletio
|
||||
onDeletionRequested();
|
||||
|
||||
handleSuccess('Deletion Requested', 'Check your email for the confirmation code.');
|
||||
} catch (error) {
|
||||
} catch (error: unknown) {
|
||||
handleError(error, { action: 'Request account deletion' });
|
||||
dispatch({ type: 'SET_ERROR', payload: 'Failed to request deletion' });
|
||||
}
|
||||
@@ -101,7 +101,7 @@ export function AccountDeletionDialog({ open, onOpenChange, userEmail, onDeletio
|
||||
|
||||
// Refresh the page to show the deletion banner
|
||||
window.location.reload();
|
||||
} catch (error) {
|
||||
} catch (error: unknown) {
|
||||
handleError(error, { action: 'Confirm account deletion' });
|
||||
}
|
||||
};
|
||||
@@ -117,7 +117,7 @@ export function AccountDeletionDialog({ open, onOpenChange, userEmail, onDeletio
|
||||
if (error) throw error;
|
||||
|
||||
handleSuccess('Code Resent', 'A new confirmation code has been sent to your email.');
|
||||
} catch (error) {
|
||||
} catch (error: unknown) {
|
||||
handleError(error, { action: 'Resend deletion code' });
|
||||
} finally {
|
||||
dispatch({ type: 'SET_LOADING', payload: false });
|
||||
|
||||
@@ -78,7 +78,7 @@ export function DataExportTab() {
|
||||
userId: user.id,
|
||||
action: 'load_statistics'
|
||||
});
|
||||
} catch (error) {
|
||||
} catch (error: unknown) {
|
||||
logger.error('Failed to load statistics', {
|
||||
userId: user.id,
|
||||
action: 'load_statistics',
|
||||
@@ -131,7 +131,7 @@ export function DataExportTab() {
|
||||
action: 'load_activity_log',
|
||||
count: activityData.length
|
||||
});
|
||||
} catch (error) {
|
||||
} catch (error: unknown) {
|
||||
logger.error('Error loading activity log', {
|
||||
userId: user.id,
|
||||
action: 'load_activity_log',
|
||||
@@ -230,7 +230,7 @@ export function DataExportTab() {
|
||||
|
||||
// Refresh activity log to show the export action
|
||||
await loadRecentActivity();
|
||||
} catch (error) {
|
||||
} catch (error: unknown) {
|
||||
logger.error('Data export failed', {
|
||||
userId: user.id,
|
||||
action: 'export_data',
|
||||
|
||||
@@ -109,7 +109,7 @@ export function LocationTab() {
|
||||
action: 'fetch_parks',
|
||||
count: validatedParks.length
|
||||
});
|
||||
} catch (error) {
|
||||
} catch (error: unknown) {
|
||||
logger.error('Error fetching parks', {
|
||||
userId: user.id,
|
||||
action: 'fetch_parks',
|
||||
@@ -152,7 +152,7 @@ export function LocationTab() {
|
||||
userId: user.id,
|
||||
action: 'fetch_accessibility_preferences'
|
||||
});
|
||||
} catch (error) {
|
||||
} catch (error: unknown) {
|
||||
logger.error('Error fetching accessibility preferences', {
|
||||
userId: user.id,
|
||||
action: 'fetch_accessibility_preferences',
|
||||
@@ -255,7 +255,7 @@ export function LocationTab() {
|
||||
'Settings saved',
|
||||
'Your location, personal information, accessibility, and unit preferences have been updated.'
|
||||
);
|
||||
} catch (error) {
|
||||
} catch (error: unknown) {
|
||||
logger.error('Error saving location settings', {
|
||||
userId: user.id,
|
||||
action: 'save_location_settings',
|
||||
|
||||
@@ -58,7 +58,7 @@ export function NotificationsTab() {
|
||||
action: 'load_notification_preferences',
|
||||
userId: user.id
|
||||
});
|
||||
} catch (error) {
|
||||
} catch (error: unknown) {
|
||||
logger.error('Failed to load notification preferences', {
|
||||
action: 'load_notification_preferences',
|
||||
userId: user.id,
|
||||
@@ -98,7 +98,7 @@ export function NotificationsTab() {
|
||||
userId: user.id,
|
||||
count: templateData.length
|
||||
});
|
||||
} catch (error) {
|
||||
} catch (error: unknown) {
|
||||
logger.error('Failed to load notification templates', {
|
||||
action: 'load_notification_templates',
|
||||
userId: user.id,
|
||||
@@ -139,7 +139,7 @@ export function NotificationsTab() {
|
||||
'Notification preferences saved',
|
||||
'Your notification settings have been updated successfully.'
|
||||
);
|
||||
} catch (error) {
|
||||
} catch (error: unknown) {
|
||||
logger.error('Error saving notification preferences', {
|
||||
action: 'save_notification_preferences',
|
||||
userId: user.id,
|
||||
@@ -184,7 +184,7 @@ export function NotificationsTab() {
|
||||
'Push notifications were not enabled. You can change this in your browser settings.'
|
||||
);
|
||||
}
|
||||
} catch (error) {
|
||||
} catch (error: unknown) {
|
||||
logger.error('Error requesting push permission', {
|
||||
action: 'request_push_permission',
|
||||
userId: user?.id,
|
||||
|
||||
@@ -167,7 +167,7 @@ export function PasswordUpdateDialog({ open, onOpenChange, onSuccess }: Password
|
||||
// No MFA, proceed with password update
|
||||
await updatePasswordWithNonce(data.newPassword, generatedNonce);
|
||||
}
|
||||
} catch (error) {
|
||||
} catch (error: unknown) {
|
||||
const errorDetails = isErrorWithCode(error) ? {
|
||||
errorCode: error.code,
|
||||
errorStatus: error.status
|
||||
@@ -257,7 +257,7 @@ export function PasswordUpdateDialog({ open, onOpenChange, onSuccess }: Password
|
||||
|
||||
// TOTP verified, now update password
|
||||
await updatePasswordWithNonce(newPassword, nonce);
|
||||
} catch (error) {
|
||||
} catch (error: unknown) {
|
||||
logger.error('MFA verification failed', {
|
||||
userId,
|
||||
action: 'password_change_mfa',
|
||||
@@ -333,7 +333,7 @@ export function PasswordUpdateDialog({ open, onOpenChange, onSuccess }: Password
|
||||
setStep('password');
|
||||
setTotpCode('');
|
||||
}, 2000);
|
||||
} catch (error) {
|
||||
} catch (error: unknown) {
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -80,7 +80,7 @@ export function PrivacyTab() {
|
||||
} else {
|
||||
await initializePreferences();
|
||||
}
|
||||
} catch (error) {
|
||||
} catch (error: unknown) {
|
||||
logger.error('Error fetching privacy preferences', {
|
||||
userId: user.id,
|
||||
action: 'fetch_privacy_preferences',
|
||||
@@ -122,7 +122,7 @@ export function PrivacyTab() {
|
||||
show_pronouns: profile?.show_pronouns || false,
|
||||
...DEFAULT_PRIVACY_SETTINGS
|
||||
});
|
||||
} catch (error) {
|
||||
} catch (error: unknown) {
|
||||
logger.error('Error initializing privacy preferences', {
|
||||
userId: user.id,
|
||||
action: 'initialize_privacy_preferences',
|
||||
@@ -211,7 +211,7 @@ export function PrivacyTab() {
|
||||
'Privacy settings updated',
|
||||
'Your privacy preferences have been successfully saved.'
|
||||
);
|
||||
} catch (error) {
|
||||
} catch (error: unknown) {
|
||||
logger.error('Failed to update privacy settings', {
|
||||
userId: user.id,
|
||||
action: 'update_privacy_settings',
|
||||
|
||||
@@ -54,7 +54,7 @@ export function SecurityTab() {
|
||||
// Check if user has email/password auth
|
||||
const hasEmailProvider = fetchedIdentities.some(i => i.provider === 'email');
|
||||
setHasPassword(hasEmailProvider);
|
||||
} catch (error) {
|
||||
} catch (error: unknown) {
|
||||
logger.error('Failed to load identities', {
|
||||
userId: user?.id,
|
||||
action: 'load_identities',
|
||||
@@ -78,7 +78,7 @@ export function SecurityTab() {
|
||||
} else {
|
||||
handleSuccess('Redirecting...', `Connecting your ${provider} account...`);
|
||||
}
|
||||
} catch (error) {
|
||||
} catch (error: unknown) {
|
||||
handleError(error, { action: `Connect ${provider} account` });
|
||||
}
|
||||
};
|
||||
@@ -156,7 +156,7 @@ export function SecurityTab() {
|
||||
}
|
||||
|
||||
setSessions((data as AuthSession[]) || []);
|
||||
} catch (error) {
|
||||
} catch (error: unknown) {
|
||||
logger.error('Failed to fetch sessions', {
|
||||
userId: user.id,
|
||||
action: 'fetch_sessions',
|
||||
|
||||
@@ -76,19 +76,37 @@ export interface ContentSubmissionContent {
|
||||
*/
|
||||
export function isValidSubmissionContent(content: any): content is ContentSubmissionContent {
|
||||
if (!content || typeof content !== 'object') {
|
||||
console.error('❌ VIOLATION: content_submissions.content must be an object');
|
||||
// Security: Use logger instead of console.error to prevent PII exposure
|
||||
import('@/lib/logger').then(({ logger }) => {
|
||||
logger.error('Submission content validation failed', {
|
||||
violation: 'invalid_type',
|
||||
expected: 'object',
|
||||
received: typeof content
|
||||
});
|
||||
});
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!['create', 'edit', 'delete'].includes(content.action)) {
|
||||
console.error('❌ VIOLATION: content_submissions.content must have valid action:', content.action);
|
||||
import('@/lib/logger').then(({ logger }) => {
|
||||
logger.error('Submission content validation failed', {
|
||||
violation: 'invalid_action',
|
||||
expected: 'create | edit | delete',
|
||||
received: content.action
|
||||
});
|
||||
});
|
||||
return false;
|
||||
}
|
||||
|
||||
const keys = Object.keys(content);
|
||||
if (keys.length > 3) {
|
||||
console.error('❌ VIOLATION: content_submissions.content has too many fields:', keys);
|
||||
console.error(' Only action + max 2 reference IDs allowed');
|
||||
import('@/lib/logger').then(({ logger }) => {
|
||||
logger.error('Submission content validation failed', {
|
||||
violation: 'too_many_fields',
|
||||
count: keys.length,
|
||||
limit: 3
|
||||
});
|
||||
});
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -96,8 +114,13 @@ export function isValidSubmissionContent(content: any): content is ContentSubmis
|
||||
const forbiddenKeys = ['name', 'description', 'photos', 'data', 'items', 'metadata'];
|
||||
const violations = keys.filter(k => forbiddenKeys.includes(k));
|
||||
if (violations.length > 0) {
|
||||
console.error('❌ VIOLATION: content_submissions.content contains forbidden keys:', violations);
|
||||
console.error(' These should be in submission_items.item_data instead');
|
||||
import('@/lib/logger').then(({ logger }) => {
|
||||
logger.error('Submission content validation failed', {
|
||||
violation: 'forbidden_keys',
|
||||
forbiddenKeys: violations,
|
||||
message: 'These should be in submission_items.item_data instead'
|
||||
});
|
||||
});
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user