ChiragPatankar's picture
Upload 24 files
6980b1d verified
"use strict";
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