feat: Execute full production readiness plan

This commit is contained in:
gpt-engineer-app[bot]
2025-10-20 17:43:21 +00:00
parent 4cc07be189
commit 53b2497e30
10 changed files with 55 additions and 32 deletions

View File

@@ -81,7 +81,7 @@ export function MFARemovalDialog({ open, onOpenChange, factorId, onSuccess }: MF
toast.success('Password verified'); toast.success('Password verified');
setStep('totp'); setStep('totp');
} catch (error) { } catch (error: unknown) {
console.error('Password verification failed:', error); console.error('Password verification failed:', error);
toast.error(getErrorMessage(error)); toast.error(getErrorMessage(error));
} finally { } finally {
@@ -152,7 +152,7 @@ export function MFARemovalDialog({ open, onOpenChange, factorId, onSuccess }: MF
toast.success('Two-factor authentication has been disabled'); toast.success('Two-factor authentication has been disabled');
handleClose(); handleClose();
onSuccess(); onSuccess();
} catch (error) { } catch (error: unknown) {
console.error('MFA removal failed:', error); console.error('MFA removal failed:', error);
toast.error(getErrorMessage(error)); toast.error(getErrorMessage(error));
} finally { } finally {

View File

@@ -75,7 +75,7 @@ export function TOTPSetup() {
setSecret(data.totp.secret); setSecret(data.totp.secret);
setFactorId(data.id); setFactorId(data.id);
setEnrolling(true); setEnrolling(true);
} catch (error) { } catch (error: unknown) {
logger.error('Failed to start TOTP enrollment', { logger.error('Failed to start TOTP enrollment', {
userId: user?.id, userId: user?.id,
action: 'totp_enroll_start', action: 'totp_enroll_start',
@@ -148,7 +148,7 @@ export function TOTPSetup() {
window.location.href = '/auth'; window.location.href = '/auth';
}, 2000); }, 2000);
} }
} catch (error) { } catch (error: unknown) {
logger.error('TOTP verification failed', { logger.error('TOTP verification failed', {
userId: user?.id, userId: user?.id,
action: 'totp_verify', action: 'totp_verify',

View File

@@ -70,7 +70,7 @@ export function AccountDeletionDialog({ open, onOpenChange, userEmail, onDeletio
onDeletionRequested(); onDeletionRequested();
handleSuccess('Deletion Requested', 'Check your email for the confirmation code.'); handleSuccess('Deletion Requested', 'Check your email for the confirmation code.');
} catch (error) { } catch (error: unknown) {
handleError(error, { action: 'Request account deletion' }); handleError(error, { action: 'Request account deletion' });
dispatch({ type: 'SET_ERROR', payload: 'Failed to request 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 // Refresh the page to show the deletion banner
window.location.reload(); window.location.reload();
} catch (error) { } catch (error: unknown) {
handleError(error, { action: 'Confirm account deletion' }); handleError(error, { action: 'Confirm account deletion' });
} }
}; };
@@ -117,7 +117,7 @@ export function AccountDeletionDialog({ open, onOpenChange, userEmail, onDeletio
if (error) throw error; if (error) throw error;
handleSuccess('Code Resent', 'A new confirmation code has been sent to your email.'); handleSuccess('Code Resent', 'A new confirmation code has been sent to your email.');
} catch (error) { } catch (error: unknown) {
handleError(error, { action: 'Resend deletion code' }); handleError(error, { action: 'Resend deletion code' });
} finally { } finally {
dispatch({ type: 'SET_LOADING', payload: false }); dispatch({ type: 'SET_LOADING', payload: false });

View File

@@ -78,7 +78,7 @@ export function DataExportTab() {
userId: user.id, userId: user.id,
action: 'load_statistics' action: 'load_statistics'
}); });
} catch (error) { } catch (error: unknown) {
logger.error('Failed to load statistics', { logger.error('Failed to load statistics', {
userId: user.id, userId: user.id,
action: 'load_statistics', action: 'load_statistics',
@@ -131,7 +131,7 @@ export function DataExportTab() {
action: 'load_activity_log', action: 'load_activity_log',
count: activityData.length count: activityData.length
}); });
} catch (error) { } catch (error: unknown) {
logger.error('Error loading activity log', { logger.error('Error loading activity log', {
userId: user.id, userId: user.id,
action: 'load_activity_log', action: 'load_activity_log',
@@ -230,7 +230,7 @@ export function DataExportTab() {
// Refresh activity log to show the export action // Refresh activity log to show the export action
await loadRecentActivity(); await loadRecentActivity();
} catch (error) { } catch (error: unknown) {
logger.error('Data export failed', { logger.error('Data export failed', {
userId: user.id, userId: user.id,
action: 'export_data', action: 'export_data',

View File

@@ -109,7 +109,7 @@ export function LocationTab() {
action: 'fetch_parks', action: 'fetch_parks',
count: validatedParks.length count: validatedParks.length
}); });
} catch (error) { } catch (error: unknown) {
logger.error('Error fetching parks', { logger.error('Error fetching parks', {
userId: user.id, userId: user.id,
action: 'fetch_parks', action: 'fetch_parks',
@@ -152,7 +152,7 @@ export function LocationTab() {
userId: user.id, userId: user.id,
action: 'fetch_accessibility_preferences' action: 'fetch_accessibility_preferences'
}); });
} catch (error) { } catch (error: unknown) {
logger.error('Error fetching accessibility preferences', { logger.error('Error fetching accessibility preferences', {
userId: user.id, userId: user.id,
action: 'fetch_accessibility_preferences', action: 'fetch_accessibility_preferences',
@@ -255,7 +255,7 @@ export function LocationTab() {
'Settings saved', 'Settings saved',
'Your location, personal information, accessibility, and unit preferences have been updated.' 'Your location, personal information, accessibility, and unit preferences have been updated.'
); );
} catch (error) { } catch (error: unknown) {
logger.error('Error saving location settings', { logger.error('Error saving location settings', {
userId: user.id, userId: user.id,
action: 'save_location_settings', action: 'save_location_settings',

View File

@@ -58,7 +58,7 @@ export function NotificationsTab() {
action: 'load_notification_preferences', action: 'load_notification_preferences',
userId: user.id userId: user.id
}); });
} catch (error) { } catch (error: unknown) {
logger.error('Failed to load notification preferences', { logger.error('Failed to load notification preferences', {
action: 'load_notification_preferences', action: 'load_notification_preferences',
userId: user.id, userId: user.id,
@@ -98,7 +98,7 @@ export function NotificationsTab() {
userId: user.id, userId: user.id,
count: templateData.length count: templateData.length
}); });
} catch (error) { } catch (error: unknown) {
logger.error('Failed to load notification templates', { logger.error('Failed to load notification templates', {
action: 'load_notification_templates', action: 'load_notification_templates',
userId: user.id, userId: user.id,
@@ -139,7 +139,7 @@ export function NotificationsTab() {
'Notification preferences saved', 'Notification preferences saved',
'Your notification settings have been updated successfully.' 'Your notification settings have been updated successfully.'
); );
} catch (error) { } catch (error: unknown) {
logger.error('Error saving notification preferences', { logger.error('Error saving notification preferences', {
action: 'save_notification_preferences', action: 'save_notification_preferences',
userId: user.id, userId: user.id,
@@ -184,7 +184,7 @@ export function NotificationsTab() {
'Push notifications were not enabled. You can change this in your browser settings.' 'Push notifications were not enabled. You can change this in your browser settings.'
); );
} }
} catch (error) { } catch (error: unknown) {
logger.error('Error requesting push permission', { logger.error('Error requesting push permission', {
action: 'request_push_permission', action: 'request_push_permission',
userId: user?.id, userId: user?.id,

View File

@@ -167,7 +167,7 @@ export function PasswordUpdateDialog({ open, onOpenChange, onSuccess }: Password
// No MFA, proceed with password update // No MFA, proceed with password update
await updatePasswordWithNonce(data.newPassword, generatedNonce); await updatePasswordWithNonce(data.newPassword, generatedNonce);
} }
} catch (error) { } catch (error: unknown) {
const errorDetails = isErrorWithCode(error) ? { const errorDetails = isErrorWithCode(error) ? {
errorCode: error.code, errorCode: error.code,
errorStatus: error.status errorStatus: error.status
@@ -257,7 +257,7 @@ export function PasswordUpdateDialog({ open, onOpenChange, onSuccess }: Password
// TOTP verified, now update password // TOTP verified, now update password
await updatePasswordWithNonce(newPassword, nonce); await updatePasswordWithNonce(newPassword, nonce);
} catch (error) { } catch (error: unknown) {
logger.error('MFA verification failed', { logger.error('MFA verification failed', {
userId, userId,
action: 'password_change_mfa', action: 'password_change_mfa',
@@ -333,7 +333,7 @@ export function PasswordUpdateDialog({ open, onOpenChange, onSuccess }: Password
setStep('password'); setStep('password');
setTotpCode(''); setTotpCode('');
}, 2000); }, 2000);
} catch (error) { } catch (error: unknown) {
throw error; throw error;
} }
}; };

View File

@@ -80,7 +80,7 @@ export function PrivacyTab() {
} else { } else {
await initializePreferences(); await initializePreferences();
} }
} catch (error) { } catch (error: unknown) {
logger.error('Error fetching privacy preferences', { logger.error('Error fetching privacy preferences', {
userId: user.id, userId: user.id,
action: 'fetch_privacy_preferences', action: 'fetch_privacy_preferences',
@@ -122,7 +122,7 @@ export function PrivacyTab() {
show_pronouns: profile?.show_pronouns || false, show_pronouns: profile?.show_pronouns || false,
...DEFAULT_PRIVACY_SETTINGS ...DEFAULT_PRIVACY_SETTINGS
}); });
} catch (error) { } catch (error: unknown) {
logger.error('Error initializing privacy preferences', { logger.error('Error initializing privacy preferences', {
userId: user.id, userId: user.id,
action: 'initialize_privacy_preferences', action: 'initialize_privacy_preferences',
@@ -211,7 +211,7 @@ export function PrivacyTab() {
'Privacy settings updated', 'Privacy settings updated',
'Your privacy preferences have been successfully saved.' 'Your privacy preferences have been successfully saved.'
); );
} catch (error) { } catch (error: unknown) {
logger.error('Failed to update privacy settings', { logger.error('Failed to update privacy settings', {
userId: user.id, userId: user.id,
action: 'update_privacy_settings', action: 'update_privacy_settings',

View File

@@ -54,7 +54,7 @@ export function SecurityTab() {
// Check if user has email/password auth // Check if user has email/password auth
const hasEmailProvider = fetchedIdentities.some(i => i.provider === 'email'); const hasEmailProvider = fetchedIdentities.some(i => i.provider === 'email');
setHasPassword(hasEmailProvider); setHasPassword(hasEmailProvider);
} catch (error) { } catch (error: unknown) {
logger.error('Failed to load identities', { logger.error('Failed to load identities', {
userId: user?.id, userId: user?.id,
action: 'load_identities', action: 'load_identities',
@@ -78,7 +78,7 @@ export function SecurityTab() {
} else { } else {
handleSuccess('Redirecting...', `Connecting your ${provider} account...`); handleSuccess('Redirecting...', `Connecting your ${provider} account...`);
} }
} catch (error) { } catch (error: unknown) {
handleError(error, { action: `Connect ${provider} account` }); handleError(error, { action: `Connect ${provider} account` });
} }
}; };
@@ -156,7 +156,7 @@ export function SecurityTab() {
} }
setSessions((data as AuthSession[]) || []); setSessions((data as AuthSession[]) || []);
} catch (error) { } catch (error: unknown) {
logger.error('Failed to fetch sessions', { logger.error('Failed to fetch sessions', {
userId: user.id, userId: user.id,
action: 'fetch_sessions', action: 'fetch_sessions',

View File

@@ -76,19 +76,37 @@ export interface ContentSubmissionContent {
*/ */
export function isValidSubmissionContent(content: any): content is ContentSubmissionContent { export function isValidSubmissionContent(content: any): content is ContentSubmissionContent {
if (!content || typeof content !== 'object') { 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; return false;
} }
if (!['create', 'edit', 'delete'].includes(content.action)) { 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; return false;
} }
const keys = Object.keys(content); const keys = Object.keys(content);
if (keys.length > 3) { if (keys.length > 3) {
console.error('❌ VIOLATION: content_submissions.content has too many fields:', keys); import('@/lib/logger').then(({ logger }) => {
console.error(' Only action + max 2 reference IDs allowed'); logger.error('Submission content validation failed', {
violation: 'too_many_fields',
count: keys.length,
limit: 3
});
});
return false; return false;
} }
@@ -96,8 +114,13 @@ export function isValidSubmissionContent(content: any): content is ContentSubmis
const forbiddenKeys = ['name', 'description', 'photos', 'data', 'items', 'metadata']; const forbiddenKeys = ['name', 'description', 'photos', 'data', 'items', 'metadata'];
const violations = keys.filter(k => forbiddenKeys.includes(k)); const violations = keys.filter(k => forbiddenKeys.includes(k));
if (violations.length > 0) { if (violations.length > 0) {
console.error('❌ VIOLATION: content_submissions.content contains forbidden keys:', violations); import('@/lib/logger').then(({ logger }) => {
console.error(' These should be in submission_items.item_data instead'); logger.error('Submission content validation failed', {
violation: 'forbidden_keys',
forbiddenKeys: violations,
message: 'These should be in submission_items.item_data instead'
});
});
return false; return false;
} }