Spaces:
Sleeping
Sleeping
; | |
var __importDefault = (this && this.__importDefault) || function (mod) { | |
return (mod && mod.__esModule) ? mod : { "default": mod }; | |
}; | |
Object.defineProperty(exports, "__esModule", { value: true }); | |
const express_1 = __importDefault(require("express")); | |
const bcryptjs_1 = __importDefault(require("bcryptjs")); | |
const jsonwebtoken_1 = __importDefault(require("jsonwebtoken")); | |
const uuid_1 = require("uuid"); | |
const google_auth_library_1 = require("google-auth-library"); | |
const database_1 = require("../db/database"); | |
const auth_1 = require("../middleware/auth"); | |
const router = express_1.default.Router(); | |
const client = new google_auth_library_1.OAuth2Client(process.env.GOOGLE_CLIENT_ID); | |
// Sign up with email/password | |
router.post('/signup', async (req, res) => { | |
try { | |
const { email, password, name } = req.body; | |
// Validation | |
if (!email || !password || !name) { | |
return res.status(400).json({ error: 'Email, password, and name are required' }); | |
} | |
if (password.length < 6) { | |
return res.status(400).json({ error: 'Password must be at least 6 characters' }); | |
} | |
// Check if user already exists | |
const existingUser = await database_1.database.get('SELECT id FROM users WHERE email = ?', [email]); | |
if (existingUser) { | |
return res.status(400).json({ error: 'User already exists' }); | |
} | |
// Hash password | |
const saltRounds = 10; | |
const passwordHash = await bcryptjs_1.default.hash(password, saltRounds); | |
// Generate verification token | |
const verificationToken = (0, uuid_1.v4)(); | |
// Create user | |
const result = await database_1.database.run('INSERT INTO users (email, name, password_hash, verification_token) VALUES (?, ?, ?, ?)', [email, name, passwordHash, verificationToken]); | |
// Create default tenant for user | |
const tenantResult = await database_1.database.run('INSERT INTO tenants (name, subdomain) VALUES (?, ?)', [`${name}'s Workspace`, `tenant-${result.lastID}`]); | |
// Link user to tenant | |
await database_1.database.run('INSERT INTO user_tenants (user_id, tenant_id, role) VALUES (?, ?, ?)', [result.lastID, tenantResult.lastID, 'owner']); | |
// Generate JWT token | |
const token = jsonwebtoken_1.default.sign({ userId: result.lastID, tenantId: tenantResult.lastID }, process.env.JWT_SECRET, { expiresIn: '7d' }); | |
// Get user data | |
const user = await database_1.database.get('SELECT id, email, name, avatar, created_at FROM users WHERE id = ?', [result.lastID]); | |
res.status(201).json({ | |
message: 'User created successfully', | |
token, | |
user, | |
tenant: { id: tenantResult.lastID, name: `${name}'s Workspace` } | |
}); | |
} | |
catch (error) { | |
console.error('Signup error:', error); | |
res.status(500).json({ error: 'Internal server error' }); | |
} | |
}); | |
// Sign in with email/password | |
router.post('/signin', async (req, res) => { | |
try { | |
const { email, password } = req.body; | |
if (!email || !password) { | |
return res.status(400).json({ error: 'Email and password are required' }); | |
} | |
// Get user | |
const user = await database_1.database.get('SELECT * FROM users WHERE email = ?', [email]); | |
if (!user || !user.password_hash) { | |
return res.status(401).json({ error: 'Invalid credentials' }); | |
} | |
// Check password | |
const isValidPassword = await bcryptjs_1.default.compare(password, user.password_hash); | |
if (!isValidPassword) { | |
return res.status(401).json({ error: 'Invalid credentials' }); | |
} | |
// Get user's tenant | |
const userTenant = await database_1.database.get(`SELECT t.id, t.name, t.subdomain, t.plan | |
FROM tenants t | |
JOIN user_tenants ut ON t.id = ut.tenant_id | |
WHERE ut.user_id = ? AND ut.role = 'owner'`, [user.id]); | |
// Generate JWT token | |
const token = jsonwebtoken_1.default.sign({ userId: user.id, tenantId: userTenant?.id }, process.env.JWT_SECRET, { expiresIn: '7d' }); | |
// Remove sensitive data | |
const { password_hash, verification_token, ...safeUser } = user; | |
res.json({ | |
message: 'Signed in successfully', | |
token, | |
user: safeUser, | |
tenant: userTenant | |
}); | |
} | |
catch (error) { | |
console.error('Signin error:', error); | |
res.status(500).json({ error: 'Internal server error' }); | |
} | |
}); | |
// Google OAuth | |
router.post('/google', async (req, res) => { | |
try { | |
const { credential } = req.body; | |
if (!credential) { | |
return res.status(400).json({ error: 'Google credential is required' }); | |
} | |
// Verify Google token | |
const ticket = await client.verifyIdToken({ | |
idToken: credential, | |
audience: process.env.GOOGLE_CLIENT_ID, | |
}); | |
const payload = ticket.getPayload(); | |
if (!payload) { | |
return res.status(400).json({ error: 'Invalid Google token' }); | |
} | |
const { sub: googleId, email, name, picture } = payload; | |
// Check if user exists | |
let user = await database_1.database.get('SELECT * FROM users WHERE google_id = ? OR email = ?', [googleId, email]); | |
if (user) { | |
// Update Google ID if needed | |
if (!user.google_id) { | |
await database_1.database.run('UPDATE users SET google_id = ?, avatar = ? WHERE id = ?', [googleId, picture, user.id]); | |
user.google_id = googleId; | |
user.avatar = picture; | |
} | |
} | |
else { | |
// Create new user | |
const result = await database_1.database.run('INSERT INTO users (email, name, google_id, avatar, email_verified) VALUES (?, ?, ?, ?, ?)', [email, name, googleId, picture, true]); | |
// Create default tenant | |
const tenantResult = await database_1.database.run('INSERT INTO tenants (name, subdomain) VALUES (?, ?)', [`${name}'s Workspace`, `tenant-${result.lastID}`]); | |
// Link user to tenant | |
await database_1.database.run('INSERT INTO user_tenants (user_id, tenant_id, role) VALUES (?, ?, ?)', [result.lastID, tenantResult.lastID, 'owner']); | |
user = { | |
id: result.lastID, | |
email, | |
name, | |
google_id: googleId, | |
avatar: picture, | |
email_verified: true | |
}; | |
} | |
// Get user's tenant | |
const userTenant = await database_1.database.get(`SELECT t.id, t.name, t.subdomain, t.plan | |
FROM tenants t | |
JOIN user_tenants ut ON t.id = ut.tenant_id | |
WHERE ut.user_id = ? AND ut.role = 'owner'`, [user.id]); | |
// Generate JWT token | |
const token = jsonwebtoken_1.default.sign({ userId: user.id, tenantId: userTenant?.id }, process.env.JWT_SECRET, { expiresIn: '7d' }); | |
// Remove sensitive data | |
const { password_hash, verification_token, ...safeUser } = user; | |
res.json({ | |
message: 'Google authentication successful', | |
token, | |
user: safeUser, | |
tenant: userTenant | |
}); | |
} | |
catch (error) { | |
console.error('Google auth error:', error); | |
res.status(500).json({ error: 'Google authentication failed' }); | |
} | |
}); | |
// Get current user | |
router.get('/me', auth_1.authenticateToken, async (req, res) => { | |
try { | |
const { userId, tenantId } = req.user; | |
// Get user data | |
const user = await database_1.database.get('SELECT id, email, name, avatar, email_verified, created_at FROM users WHERE id = ?', [userId]); | |
if (!user) { | |
return res.status(404).json({ error: 'User not found' }); | |
} | |
// Get tenant data | |
const tenant = await database_1.database.get('SELECT id, name, subdomain, plan, settings FROM tenants WHERE id = ?', [tenantId]); | |
res.json({ | |
user, | |
tenant | |
}); | |
} | |
catch (error) { | |
console.error('Get user error:', error); | |
res.status(500).json({ error: 'Internal server error' }); | |
} | |
}); | |
// Update user profile | |
router.put('/profile', auth_1.authenticateToken, async (req, res) => { | |
try { | |
const { userId } = req.user; | |
const { name, avatar } = req.body; | |
const updates = []; | |
const params = []; | |
if (name) { | |
updates.push('name = ?'); | |
params.push(name); | |
} | |
if (avatar) { | |
updates.push('avatar = ?'); | |
params.push(avatar); | |
} | |
if (updates.length === 0) { | |
return res.status(400).json({ error: 'No valid fields to update' }); | |
} | |
updates.push('updated_at = CURRENT_TIMESTAMP'); | |
params.push(userId); | |
await database_1.database.run(`UPDATE users SET ${updates.join(', ')} WHERE id = ?`, params); | |
// Get updated user | |
const user = await database_1.database.get('SELECT id, email, name, avatar, email_verified, created_at FROM users WHERE id = ?', [userId]); | |
res.json({ | |
message: 'Profile updated successfully', | |
user | |
}); | |
} | |
catch (error) { | |
console.error('Update profile error:', error); | |
res.status(500).json({ error: 'Internal server error' }); | |
} | |
}); | |
// Logout (client-side token removal, but we can blacklist if needed) | |
router.post('/logout', auth_1.authenticateToken, (req, res) => { | |
res.json({ message: 'Logged out successfully' }); | |
}); | |
exports.default = router; | |
//# sourceMappingURL=auth.js.map |