mirror of
https://github.com/pacnpal/thrilltrack-explorer.git
synced 2025-12-30 06:47:05 -05:00
Compare commits
2 Commits
a5fed1e26a
...
82b85e3284
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
82b85e3284 | ||
|
|
466c549e4a |
@@ -115,6 +115,21 @@ export function TOTPSetup() {
|
||||
|
||||
if (verifyError) throw verifyError;
|
||||
|
||||
// Log MFA enrollment to audit trail
|
||||
try {
|
||||
const { logAdminAction } = await import('@/lib/adminActionAuditHelpers');
|
||||
await logAdminAction(
|
||||
'mfa_enabled',
|
||||
{
|
||||
factor_id: factorId,
|
||||
factor_type: 'totp',
|
||||
friendly_name: 'Authenticator App',
|
||||
}
|
||||
);
|
||||
} catch (auditError) {
|
||||
// Non-critical - don't fail enrollment if audit logging fails
|
||||
}
|
||||
|
||||
// Check if user signed in via OAuth and trigger step-up flow
|
||||
const authMethod = getAuthMethod();
|
||||
const isOAuthUser = authMethod === 'oauth';
|
||||
|
||||
@@ -311,6 +311,19 @@ export function useModerationQueueManager(config: ModerationQueueManagerConfig):
|
||||
|
||||
if (error) throw error;
|
||||
|
||||
// Log manual submission deletion
|
||||
const { logAdminAction } = await import('@/lib/adminActionAuditHelpers');
|
||||
await logAdminAction(
|
||||
'submission_force_deleted',
|
||||
{
|
||||
submission_id: item.id,
|
||||
submission_type: item.content?.action || 'unknown',
|
||||
entity_type: item.content?.entity_type,
|
||||
reason: 'Manual deletion by moderator',
|
||||
},
|
||||
item.user_id
|
||||
);
|
||||
|
||||
toast({
|
||||
title: "Submission deleted",
|
||||
description: "The submission has been permanently deleted",
|
||||
@@ -336,7 +349,7 @@ export function useModerationQueueManager(config: ModerationQueueManagerConfig):
|
||||
setActionLoading(null);
|
||||
}
|
||||
},
|
||||
[actionLoading, toast],
|
||||
[actionLoading, toast, queue],
|
||||
);
|
||||
|
||||
/**
|
||||
|
||||
@@ -257,6 +257,21 @@ export async function addPasswordToAccount(): Promise<IdentityOperationResult> {
|
||||
method: 'reset_password_flow',
|
||||
timestamp: new Date().toISOString()
|
||||
});
|
||||
|
||||
// Log to admin audit trail for security tracking
|
||||
try {
|
||||
const { logAdminAction } = await import('@/lib/adminActionAuditHelpers');
|
||||
await logAdminAction(
|
||||
'password_setup_initiated',
|
||||
{
|
||||
method: 'reset_password_email',
|
||||
email: userEmail,
|
||||
has_oauth: true, // If they're adding password, they must have OAuth
|
||||
}
|
||||
);
|
||||
} catch (auditError) {
|
||||
// Non-critical - don't fail operation if audit logging fails
|
||||
}
|
||||
|
||||
return {
|
||||
success: true,
|
||||
|
||||
@@ -65,16 +65,47 @@ export default function AdminBlog() {
|
||||
};
|
||||
|
||||
if (editingPost) {
|
||||
const oldStatus = editingPost.status;
|
||||
const { error } = await supabase
|
||||
.from('blog_posts')
|
||||
.update(postData)
|
||||
.eq('id', editingPost.id);
|
||||
if (error) throw error;
|
||||
|
||||
// Log blog post update
|
||||
const { logAdminAction } = await import('@/lib/adminActionAuditHelpers');
|
||||
const statusChanged = oldStatus !== postData.status;
|
||||
await logAdminAction(
|
||||
statusChanged && postData.status === 'published' ? 'blog_post_published' : 'blog_post_updated',
|
||||
{
|
||||
post_id: editingPost.id,
|
||||
title: postData.title,
|
||||
slug: postData.slug,
|
||||
old_status: oldStatus,
|
||||
new_status: postData.status,
|
||||
status_changed: statusChanged,
|
||||
}
|
||||
);
|
||||
} else {
|
||||
const { error } = await supabase
|
||||
const { data: newPost, error } = await supabase
|
||||
.from('blog_posts')
|
||||
.insert(postData);
|
||||
.insert(postData)
|
||||
.select('id')
|
||||
.single();
|
||||
if (error) throw error;
|
||||
|
||||
// Log blog post creation
|
||||
const { logAdminAction } = await import('@/lib/adminActionAuditHelpers');
|
||||
await logAdminAction(
|
||||
'blog_post_created',
|
||||
{
|
||||
post_id: newPost.id,
|
||||
title: postData.title,
|
||||
slug: postData.slug,
|
||||
status: postData.status,
|
||||
is_draft: isDraft,
|
||||
}
|
||||
);
|
||||
}
|
||||
},
|
||||
onSuccess: (_, { isDraft }) => {
|
||||
@@ -89,12 +120,31 @@ export default function AdminBlog() {
|
||||
});
|
||||
|
||||
const deleteMutation = useMutation({
|
||||
mutationFn: async (id: string) => {
|
||||
mutationFn: async (postId: string) => {
|
||||
// Get post details before deletion for audit log
|
||||
const { data: post } = await supabase
|
||||
.from('blog_posts')
|
||||
.select('title, slug, status')
|
||||
.eq('id', postId)
|
||||
.single();
|
||||
|
||||
const { error } = await supabase
|
||||
.from('blog_posts')
|
||||
.delete()
|
||||
.eq('id', id);
|
||||
.eq('id', postId);
|
||||
if (error) throw error;
|
||||
|
||||
// Log blog post deletion
|
||||
const { logAdminAction } = await import('@/lib/adminActionAuditHelpers');
|
||||
await logAdminAction(
|
||||
'blog_post_deleted',
|
||||
{
|
||||
post_id: postId,
|
||||
title: post?.title,
|
||||
slug: post?.slug,
|
||||
status: post?.status,
|
||||
}
|
||||
);
|
||||
},
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({ queryKey: ['admin-blog-posts'] });
|
||||
|
||||
@@ -76,6 +76,17 @@ export default createEdgeFunction(
|
||||
throw profileError;
|
||||
}
|
||||
|
||||
// Log to system activity log
|
||||
await supabaseClient.rpc('log_system_activity', {
|
||||
_user_id: context.userId,
|
||||
_action: 'account_deletion_cancelled',
|
||||
_details: {
|
||||
request_id: deletionRequest.id,
|
||||
cancellation_reason: cancellation_reason || 'User cancelled',
|
||||
account_reactivated: true,
|
||||
}
|
||||
});
|
||||
|
||||
// Send cancellation email
|
||||
const forwardEmailKey = Deno.env.get('FORWARDEMAIL_API_KEY');
|
||||
const fromEmail = Deno.env.get('FROM_EMAIL_ADDRESS') || 'noreply@thrillwiki.com';
|
||||
|
||||
@@ -89,6 +89,17 @@ export default createEdgeFunction(
|
||||
throw updateError;
|
||||
}
|
||||
|
||||
// Log to system activity log
|
||||
await supabaseClient.rpc('log_system_activity', {
|
||||
_user_id: context.userId,
|
||||
_action: 'account_deletion_confirmed',
|
||||
_details: {
|
||||
request_id: deletionRequest.id,
|
||||
scheduled_deletion_at: deletionRequest.scheduled_deletion_at,
|
||||
account_deactivated: true,
|
||||
}
|
||||
});
|
||||
|
||||
// Send confirmation email
|
||||
const forwardEmailKey = Deno.env.get('FORWARDEMAIL_API_KEY');
|
||||
const fromEmail = Deno.env.get('FROM_EMAIL_ADDRESS') || 'noreply@thrillwiki.com';
|
||||
|
||||
@@ -82,6 +82,16 @@ const handler = createEdgeFunction(
|
||||
const forwardEmailKey = Deno.env.get('FORWARDEMAIL_API_KEY');
|
||||
const fromEmail = Deno.env.get('FROM_EMAIL_ADDRESS') || 'noreply@thrillwiki.com';
|
||||
|
||||
// Log to system activity log
|
||||
await supabaseClient.rpc('log_system_activity', {
|
||||
_user_id: context.userId,
|
||||
_action: 'account_deletion_requested',
|
||||
_details: {
|
||||
request_id: deletionRequest.id,
|
||||
scheduled_deletion_at: scheduledDeletionAt.toISOString(),
|
||||
}
|
||||
});
|
||||
|
||||
if (forwardEmailKey && userEmail) {
|
||||
try {
|
||||
await fetch('https://api.forwardemail.net/v1/emails', {
|
||||
|
||||
Reference in New Issue
Block a user