fix: presigned URL signatures, bucket consolidation, login & invite status
All checks were successful
Build and Push Docker Image / build (push) Successful in 9m44s

- MinIO: use separate public client for presigned URLs so AWS V4 signature
  matches the browser's Host header (fixes SignatureDoesNotMatch on all uploads)
- Consolidate applicant/partner uploads to mopc-files bucket (removes
  non-existent mopc-submissions and mopc-partners buckets)
- Auth: allow magic links for any non-SUSPENDED user (was ACTIVE-only,
  blocking first-time CSV-seeded applicants)
- Auth: accept invite tokens for any non-SUSPENDED user (was INVITED-only)
- Ensure all 14 invite token locations set status to INVITED

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-05 13:06:17 +01:00
parent 78334676d0
commit c6d0f90038
9 changed files with 50 additions and 60 deletions

View File

@@ -58,14 +58,16 @@ export const { handlers, auth, signIn, signOut } = NextAuth({
from: process.env.EMAIL_FROM || 'MOPC Platform <noreply@monaco-opc.com>',
maxAge: parseInt(process.env.MAGIC_LINK_EXPIRY || '900'), // 15 minutes
sendVerificationRequest: async ({ identifier: email, url }) => {
// Only send magic links to existing, ACTIVE users
// Send magic links to any existing, non-suspended user.
// This is the primary first-login path for applicants seeded from CSV
// (status NONE) who have no password yet.
const existingUser = await prisma.user.findUnique({
where: { email: email.toLowerCase().trim() },
select: { status: true },
})
if (!existingUser || existingUser.status !== 'ACTIVE') {
if (!existingUser || existingUser.status === 'SUSPENDED') {
// Silently skip — don't reveal whether the email exists (prevents enumeration)
console.log(`[auth] Magic link requested for non-active/unknown email: ${email}`)
console.log(`[auth] Magic link requested for suspended/unknown email: ${email}`)
return
}
await sendMagicLinkEmail(email, url)
@@ -96,7 +98,7 @@ export const { handlers, auth, signIn, signOut } = NextAuth({
},
})
if (!user || user.status !== 'INVITED') {
if (!user || user.status === 'SUSPENDED') {
return null
}