File size: 3,662 Bytes
ec15943
 
 
 
 
 
 
aa8f65d
ec15943
abdeed6
ec15943
aa8f65d
 
 
 
 
 
 
 
 
 
ec15943
abdeed6
ec15943
abdeed6
 
ec15943
 
 
 
 
 
 
 
 
 
abdeed6
 
 
 
 
 
 
 
ec15943
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
abdeed6
ec15943
abdeed6
ec15943
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
abdeed6
ec15943
 
abdeed6
ec15943
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
/**
 * Admin Auth Controller - Independent Admin Authentication
 */
const bcrypt = require('bcryptjs');
const jwt = require('jsonwebtoken');
const { getPool } = require('../db');

const ADMIN_JWT_SECRET = process.env.ADMIN_JWT_SECRET;
const JWT_EXPIRES_IN = '8h'; // Longer session for admins
const JWT_REFRESH_EXPIRES_IN = '30d';

// Security check: Ensure ADMIN_JWT_SECRET is configured
if (!ADMIN_JWT_SECRET) {
  console.error('⚠️  SECURITY WARNING: ADMIN_JWT_SECRET environment variable is not set!');
  if (process.env.NODE_ENV === 'production') {
    console.error('❌ FATAL: Cannot run in production without ADMIN_JWT_SECRET');
    process.exit(1);
  }
}


/**
 * Generate JWT tokens for Admin (matching UserService shape)
 */
function generateTokens(admin) {
  const accessToken = jwt.sign(
    { 
      id: admin.id, 
      username: admin.username, 
      email: admin.email, 
      role: 'admin',
      permissions: admin.permissions 
    },
    ADMIN_JWT_SECRET,
    { expiresIn: JWT_EXPIRES_IN }
  );

  const refreshToken = jwt.sign(
    { id: admin.id, type: 'refresh' },
    ADMIN_JWT_SECRET,
    { expiresIn: JWT_REFRESH_EXPIRES_IN }
  );

  return { accessToken, refreshToken };
}

/**
 * Register Admin
 */
async function register(req, res) {
  const { username, email, password, name } = req.body;
  const pool = getPool();
  
  if (!pool) return res.status(500).json({ error: 'Database not connected' });
  
  try {
    const existing = await pool.query('SELECT id FROM admins WHERE email = $1 OR username = $2', [email, username]);
    if (existing.rows.length > 0) {
      return res.status(400).json({ error: 'Admin already exists' });
    }
    
    const hashedPassword = await bcrypt.hash(password, 12);
    const result = await pool.query(
      'INSERT INTO admins (username, email, password_hash, name, permissions) VALUES ($1, $2, $3, $4, $5) RETURNING id, username, email, name, permissions',
      [username, email, hashedPassword, name, JSON.stringify(['all'])]
    );
    
    const admin = result.rows[0];
    const tokens = generateTokens(admin);
    
    res.status(201).json({ admin, tokens });
  } catch (error) {
    console.error('[Admin Register Error]', error.message);
    res.status(500).json({ error: 'Failed to register admin' });
  }
}

/**
 * Login Admin
 */
async function login(req, res) {
  const { email, password } = req.body;
  const pool = getPool();
  
  if (!pool) return res.status(500).json({ error: 'Database not connected' });
  
  try {
    const result = await pool.query('SELECT * FROM admins WHERE email = $1', [email]);
    if (result.rows.length === 0) {
      return res.status(401).json({ error: 'Invalid credentials' });
    }
    
    const admin = result.rows[0];
    const valid = await bcrypt.compare(password, admin.password_hash);
    if (!valid) {
      return res.status(401).json({ error: 'Invalid credentials' });
    }
    
    const tokens = generateTokens(admin);
    delete admin.password_hash;
    
    res.json({ admin, tokens });
  } catch (error) {
    console.error('[Admin Login Error]', error.message);
    res.status(500).json({ error: 'Login failed' });
  }
}

/**
 * Get current admin profile
 */
async function getMe(req, res) {
  const pool = getPool();
  try {
    const result = await pool.query('SELECT id, username, email, name, permissions FROM admins WHERE id = $1', [req.user.id]);
    if (result.rows.length === 0) return res.status(404).json({ error: 'Admin not found' });
    res.json({ admin: result.rows[0] });
  } catch (error) {
    res.status(500).json({ error: 'Failed to fetch profile' });
  }
}

module.exports = { register, login, getMe };