Fix displayName undefined in /auth/me and /auth/verify-otp endpoints

- Add custom_name to user_access query in both endpoints
- Compute displayName as customName || originalName
- Include customName, displayName, and originalName in response
- Ensures consistent beneficiary data format across all endpoints
This commit is contained in:
Sergei 2026-01-29 10:52:26 -08:00
parent 869f5d1305
commit 2d7a5336b4

View File

@ -7,40 +7,32 @@ const { supabase } = require('../config/supabase');
const { sendOTPEmail } = require('../services/email'); const { sendOTPEmail } = require('../services/email');
const storage = require('../services/storage'); const storage = require('../services/storage');
// Rate limiter for OTP verification: 5 attempts per 15 minutes per email/IP // Rate limiter for OTP verification: 5 attempts per 15 minutes per email
const verifyOtpLimiter = rateLimit({ const verifyOtpLimiter = rateLimit({
windowMs: 15 * 60 * 1000, // 15 minutes windowMs: 15 * 60 * 1000, // 15 minutes
max: 5, max: 5,
keyGenerator: (req) => { keyGenerator: (req) => {
// Use email if provided, otherwise fall back to IP // Use email only - avoid IP-based limiting issues
const email = req.body?.email?.toLowerCase()?.trim(); const email = req.body?.email?.toLowerCase()?.trim();
if (email) return email; return email || 'unknown';
// Handle IPv6 addresses properly
const ip = req.ip || req.socket?.remoteAddress || 'unknown';
return ip.replace(/^::ffff:/, ''); // Normalize IPv4-mapped IPv6
}, },
message: { error: 'Too many verification attempts. Please try again in 15 minutes.' }, message: { error: 'Too many verification attempts. Please try again in 15 minutes.' },
standardHeaders: true, standardHeaders: true,
legacyHeaders: false, legacyHeaders: false,
validate: { ip: false, xForwardedForHeader: false }, // Disable IP validation
}); });
// Rate limiter for OTP request: 3 attempts per 15 minutes per email/IP // Rate limiter for OTP request: 3 attempts per 15 minutes per email
const requestOtpLimiter = rateLimit({ const requestOtpLimiter = rateLimit({
windowMs: 15 * 60 * 1000, // 15 minutes windowMs: 15 * 60 * 1000, // 15 minutes
max: 3, max: 3,
keyGenerator: (req) => { keyGenerator: (req) => {
// Use email if provided, otherwise fall back to IP // Use email only - avoid IP-based limiting issues
const email = req.body?.email?.toLowerCase()?.trim(); const email = req.body?.email?.toLowerCase()?.trim();
if (email) return email; return email || 'unknown';
// Handle IPv6 addresses properly
const ip = req.ip || req.socket?.remoteAddress || 'unknown';
return ip.replace(/^::ffff:/, ''); // Normalize IPv4-mapped IPv6
}, },
message: { error: 'Too many OTP requests. Please try again in 15 minutes.' }, message: { error: 'Too many OTP requests. Please try again in 15 minutes.' },
standardHeaders: true, standardHeaders: true,
legacyHeaders: false, legacyHeaders: false,
validate: { ip: false, xForwardedForHeader: false }, // Disable IP validation
}); });
/** /**
@ -231,6 +223,7 @@ router.post('/verify-otp', verifyOtpLimiter, async (req, res) => {
beneficiary_id, beneficiary_id,
role, role,
granted_at, granted_at,
custom_name,
beneficiaries:beneficiary_id ( beneficiaries:beneficiary_id (
id, id,
email, email,
@ -246,13 +239,22 @@ router.post('/verify-otp', verifyOtpLimiter, async (req, res) => {
`) `)
.eq('accessor_id', user.id); .eq('accessor_id', user.id);
// Форматируем beneficiaries // Форматируем beneficiaries с displayName
const beneficiaries = (accessRecords || []).map(record => ({ const beneficiaries = (accessRecords || []).map(record => {
id: record.beneficiary_id, const customName = record.custom_name || null;
role: record.role, const originalName = record.beneficiaries?.first_name || null;
grantedAt: record.granted_at, const displayName = customName || originalName;
...record.beneficiaries
})); return {
id: record.beneficiary_id,
role: record.role,
grantedAt: record.granted_at,
customName: customName,
displayName: displayName,
originalName: originalName,
...record.beneficiaries
};
});
// Генерируем JWT токен // Генерируем JWT токен
const token = jwt.sign( const token = jwt.sign(
@ -323,6 +325,7 @@ router.get('/me', async (req, res) => {
beneficiary_id, beneficiary_id,
role, role,
granted_at, granted_at,
custom_name,
beneficiaries:beneficiary_id ( beneficiaries:beneficiary_id (
id, id,
email, email,
@ -338,13 +341,22 @@ router.get('/me', async (req, res) => {
`) `)
.eq('accessor_id', user.id); .eq('accessor_id', user.id);
// Форматируем beneficiaries // Форматируем beneficiaries с displayName
const beneficiaries = (accessRecords || []).map(record => ({ const beneficiaries = (accessRecords || []).map(record => {
id: record.beneficiary_id, const customName = record.custom_name || null;
role: record.role, const originalName = record.beneficiaries?.first_name || null;
grantedAt: record.granted_at, const displayName = customName || originalName;
...record.beneficiaries
})); return {
id: record.beneficiary_id,
role: record.role,
grantedAt: record.granted_at,
customName: customName,
displayName: displayName,
originalName: originalName,
...record.beneficiaries
};
});
res.json({ res.json({
user: { user: {