🔧 API Format Fix: - Convert register.ts to register.js using req/res pattern - Convert login.ts to login.js using req/res pattern - Convert setup-auth.ts to setup-auth.js using req/res pattern - Use CommonJS require() instead of ES6 imports - Use traditional Vercel function signature that works ✅ Working Format: - export default async function handler(req, res) - req.body for request data (auto-parsed by Vercel) - res.status().json() for responses - CommonJS modules with require() This should resolve all timeout issues and make authentication work properly.
158 lines
No EOL
4.3 KiB
JavaScript
158 lines
No EOL
4.3 KiB
JavaScript
const { Pool } = require('pg');
|
|
const bcrypt = require('bcryptjs');
|
|
const jwt = require('jsonwebtoken');
|
|
|
|
const pool = new Pool({
|
|
connectionString: process.env.DATABASE_URL,
|
|
ssl: process.env.NODE_ENV === 'production' ? { rejectUnauthorized: false } : false,
|
|
});
|
|
|
|
export default async function handler(req, res) {
|
|
if (req.method !== 'POST') {
|
|
return res.status(405).json({ error: 'Method not allowed' });
|
|
}
|
|
|
|
// Check environment variables
|
|
if (!process.env.DATABASE_URL) {
|
|
return res.status(500).json({
|
|
error: 'Database configuration missing',
|
|
details: 'DATABASE_URL environment variable not set'
|
|
});
|
|
}
|
|
|
|
if (!process.env.JWT_SECRET) {
|
|
console.warn('JWT_SECRET not set, using fallback');
|
|
}
|
|
|
|
const client = await pool.connect();
|
|
|
|
try {
|
|
const { username, email, password, firstName, lastName } = req.body;
|
|
|
|
// Validate input
|
|
if (!username || !email || !password) {
|
|
return res.status(400).json({
|
|
error: 'Username, email, and password are required'
|
|
});
|
|
}
|
|
|
|
if (password.length < 6) {
|
|
return res.status(400).json({
|
|
error: 'Password must be at least 6 characters long'
|
|
});
|
|
}
|
|
|
|
// Check if users table exists
|
|
const tableCheck = await client.query(`
|
|
SELECT EXISTS (
|
|
SELECT FROM information_schema.tables
|
|
WHERE table_schema = 'public'
|
|
AND table_name = 'users'
|
|
);
|
|
`);
|
|
|
|
if (!tableCheck.rows[0].exists) {
|
|
return res.status(500).json({
|
|
error: 'Database not initialized',
|
|
details: 'Please run the setup-auth endpoint first'
|
|
});
|
|
}
|
|
|
|
// Check if user already exists
|
|
const existingUser = await client.query(
|
|
'SELECT id FROM users WHERE username = $1 OR email = $2',
|
|
[username, email]
|
|
);
|
|
|
|
if (existingUser.rows.length > 0) {
|
|
return res.status(409).json({
|
|
error: 'Username or email already exists'
|
|
});
|
|
}
|
|
|
|
// Hash password
|
|
const saltRounds = 12;
|
|
const passwordHash = await bcrypt.hash(password, saltRounds);
|
|
|
|
// Create user
|
|
const userResult = await client.query(`
|
|
INSERT INTO users (username, email, password_hash, first_name, last_name)
|
|
VALUES ($1, $2, $3, $4, $5)
|
|
RETURNING id, username, email, first_name, last_name, created_at
|
|
`, [username, email, passwordHash, firstName || null, lastName || null]);
|
|
|
|
const user = userResult.rows[0];
|
|
|
|
// Assign default 'user' role
|
|
const roleResult = await client.query(
|
|
'SELECT id FROM roles WHERE name = $1',
|
|
['user']
|
|
);
|
|
|
|
if (roleResult.rows.length > 0) {
|
|
await client.query(
|
|
'INSERT INTO user_roles (user_id, role_id) VALUES ($1, $2)',
|
|
[user.id, roleResult.rows[0].id]
|
|
);
|
|
}
|
|
|
|
// Generate JWT token
|
|
const jwtSecret = process.env.JWT_SECRET || 'fallback-secret-change-in-production';
|
|
const token = jwt.sign(
|
|
{
|
|
userId: user.id,
|
|
username: user.username,
|
|
email: user.email
|
|
},
|
|
jwtSecret,
|
|
{ expiresIn: '7d' }
|
|
);
|
|
|
|
// Store session
|
|
const tokenHash = await bcrypt.hash(token, 10);
|
|
const expiresAt = new Date(Date.now() + 7 * 24 * 60 * 60 * 1000); // 7 days
|
|
|
|
await client.query(`
|
|
INSERT INTO user_sessions (user_id, token_hash, expires_at, user_agent, ip_address)
|
|
VALUES ($1, $2, $3, $4, $5)
|
|
`, [
|
|
user.id,
|
|
tokenHash,
|
|
expiresAt,
|
|
req.headers['user-agent'] || null,
|
|
req.headers['x-forwarded-for'] || req.headers['x-real-ip'] || null
|
|
]);
|
|
|
|
// Get user roles for response
|
|
const userRoles = await client.query(`
|
|
SELECT r.name, r.description
|
|
FROM roles r
|
|
JOIN user_roles ur ON r.id = ur.role_id
|
|
WHERE ur.user_id = $1
|
|
`, [user.id]);
|
|
|
|
res.status(201).json({
|
|
success: true,
|
|
message: 'User registered successfully',
|
|
user: {
|
|
id: user.id,
|
|
username: user.username,
|
|
email: user.email,
|
|
firstName: user.first_name,
|
|
lastName: user.last_name,
|
|
roles: userRoles.rows.map(r => r.name),
|
|
createdAt: user.created_at
|
|
},
|
|
token
|
|
});
|
|
|
|
} catch (error) {
|
|
console.error('Registration error:', error);
|
|
res.status(500).json({
|
|
error: 'Registration failed',
|
|
details: process.env.NODE_ENV === 'development' ? error.message : undefined
|
|
});
|
|
} finally {
|
|
client.release();
|
|
}
|
|
}
|