Refactor authentication and routing code to use consistent naming conventions for database fields.

Do NOT update the schema like that again for the love of god.
This commit is contained in:
AdamT20054
2025-09-21 06:59:39 +01:00
parent 584e5ed52b
commit fd76a9efd2
8 changed files with 208 additions and 208 deletions

View File

@@ -28,13 +28,13 @@ router.get('/admin/users', authenticateToken, requireViewUsers, async (req, res)
username: true, username: true,
email: true, email: true,
role: true, role: true,
isActive: true, is_active: true,
lastLogin: true, last_login: true,
createdAt: true, created_at: true,
updatedAt: true updated_at: true
}, },
orderBy: { orderBy: {
createdAt: 'desc' created_at: 'desc'
} }
}) })
@@ -91,7 +91,7 @@ router.post('/admin/users', authenticateToken, requireManageUsers, [
data: { data: {
username, username,
email, email,
passwordHash, password_hash: passwordHash,
role role
}, },
select: { select: {
@@ -99,8 +99,8 @@ router.post('/admin/users', authenticateToken, requireManageUsers, [
username: true, username: true,
email: true, email: true,
role: true, role: true,
isActive: true, is_active: true,
createdAt: true created_at: true
} }
}); });
@@ -144,7 +144,7 @@ router.put('/admin/users/:userId', authenticateToken, requireManageUsers, [
if (username) updateData.username = username; if (username) updateData.username = username;
if (email) updateData.email = email; if (email) updateData.email = email;
if (role) updateData.role = role; if (role) updateData.role = role;
if (typeof isActive === 'boolean') updateData.isActive = isActive; if (typeof isActive === 'boolean') updateData.is_active = isActive;
// Check if user exists // Check if user exists
const existingUser = await prisma.users.findUnique({ const existingUser = await prisma.users.findUnique({
@@ -181,7 +181,7 @@ router.put('/admin/users/:userId', authenticateToken, requireManageUsers, [
const adminCount = await prisma.users.count({ const adminCount = await prisma.users.count({
where: { where: {
role: 'admin', role: 'admin',
isActive: true is_active: true
} }
}); });
@@ -199,10 +199,10 @@ router.put('/admin/users/:userId', authenticateToken, requireManageUsers, [
username: true, username: true,
email: true, email: true,
role: true, role: true,
isActive: true, is_active: true,
lastLogin: true, last_login: true,
createdAt: true, created_at: true,
updatedAt: true updated_at: true
} }
}); });
@@ -240,7 +240,7 @@ router.delete('/admin/users/:userId', authenticateToken, requireManageUsers, asy
const adminCount = await prisma.users.count({ const adminCount = await prisma.users.count({
where: { where: {
role: 'admin', role: 'admin',
isActive: true is_active: true
} }
}); });
@@ -304,7 +304,7 @@ router.post('/admin/users/:userId/reset-password', authenticateToken, requireMan
// Update user password // Update user password
await prisma.users.update({ await prisma.users.update({
where: { id: userId }, where: { id: userId },
data: { passwordHash } data: { password_hash: passwordHash }
}); });
// Log the password reset action (you might want to add an audit log table) // Log the password reset action (you might want to add an audit log table)
@@ -519,7 +519,7 @@ router.post('/verify-tfa', [
const speakeasy = require('speakeasy'); const speakeasy = require('speakeasy');
// Check if it's a backup code // Check if it's a backup code
const backupCodes = user.tfaBackupCodes ? JSON.parse(user.tfaBackupCodes) : []; const backupCodes = user.tfa_backup_codes ? JSON.parse(user.tfa_backup_codes) : [];
const isBackupCode = backupCodes.includes(token); const isBackupCode = backupCodes.includes(token);
let verified = false; let verified = false;
@@ -527,17 +527,17 @@ router.post('/verify-tfa', [
if (isBackupCode) { if (isBackupCode) {
// Remove the used backup code // Remove the used backup code
const updatedBackupCodes = backupCodes.filter(code => code !== token); const updatedBackupCodes = backupCodes.filter(code => code !== token);
await prisma.user.update({ await prisma.users.update({
where: { id: user.id }, where: { id: user.id },
data: { data: {
tfaBackupCodes: JSON.stringify(updatedBackupCodes) tfa_backup_codes: JSON.stringify(updatedBackupCodes)
} }
}); });
verified = true; verified = true;
} else { } else {
// Verify TOTP token // Verify TOTP token
verified = speakeasy.totp.verify({ verified = speakeasy.totp.verify({
secret: user.tfaSecret, secret: user.tfa_secret,
encoding: 'base32', encoding: 'base32',
token: token, token: token,
window: 2 window: 2
@@ -549,9 +549,9 @@ router.post('/verify-tfa', [
} }
// Update last login // Update last login
await prisma.user.update({ await prisma.users.update({
where: { id: user.id }, where: { id: user.id },
data: { lastLogin: new Date() } data: { last_login: new Date() }
}); });
// Generate token // Generate token
@@ -604,7 +604,7 @@ router.put('/profile', authenticateToken, [
// Check if username/email already exists (excluding current user) // Check if username/email already exists (excluding current user)
if (username || email) { if (username || email) {
const existingUser = await prisma.user.findFirst({ const existingUser = await prisma.users.findFirst({
where: { where: {
AND: [ AND: [
{ id: { not: req.user.id } }, { id: { not: req.user.id } },
@@ -623,7 +623,7 @@ router.put('/profile', authenticateToken, [
} }
} }
const updatedUser = await prisma.user.update({ const updatedUser = await prisma.users.update({
where: { id: req.user.id }, where: { id: req.user.id },
data: updateData, data: updateData,
select: { select: {
@@ -631,9 +631,9 @@ router.put('/profile', authenticateToken, [
username: true, username: true,
email: true, email: true,
role: true, role: true,
isActive: true, is_active: true,
lastLogin: true, last_login: true,
updatedAt: true updated_at: true
} }
}); });
@@ -661,12 +661,12 @@ router.put('/change-password', authenticateToken, [
const { currentPassword, newPassword } = req.body; const { currentPassword, newPassword } = req.body;
// Get user with password hash // Get user with password hash
const user = await prisma.user.findUnique({ const user = await prisma.users.findUnique({
where: { id: req.user.id } where: { id: req.user.id }
}); });
// Verify current password // Verify current password
const isValidPassword = await bcrypt.compare(currentPassword, user.passwordHash); const isValidPassword = await bcrypt.compare(currentPassword, user.password_hash);
if (!isValidPassword) { if (!isValidPassword) {
return res.status(401).json({ error: 'Current password is incorrect' }); return res.status(401).json({ error: 'Current password is incorrect' });
} }
@@ -675,9 +675,9 @@ router.put('/change-password', authenticateToken, [
const newPasswordHash = await bcrypt.hash(newPassword, 12); const newPasswordHash = await bcrypt.hash(newPassword, 12);
// Update password // Update password
await prisma.user.update({ await prisma.users.update({
where: { id: req.user.id }, where: { id: req.user.id },
data: { passwordHash: newPasswordHash } data: { password_hash: newPasswordHash }
}); });
res.json({ res.json({

View File

@@ -162,16 +162,16 @@ router.get('/hosts', authenticateToken, requireViewHosts, async (req, res) => {
// Show all hosts regardless of status // Show all hosts regardless of status
select: { select: {
id: true, id: true,
friendlyName: true, friendly_name: true,
hostname: true, hostname: true,
ip: true, ip: true,
osType: true, os_type: true,
osVersion: true, os_version: true,
lastUpdate: true, last_update: true,
status: true, status: true,
agentVersion: true, agent_version: true,
autoUpdate: true, auto_update: true,
hostGroup: { host_groups: {
select: { select: {
id: true, id: true,
name: true, name: true,
@@ -180,15 +180,15 @@ router.get('/hosts', authenticateToken, requireViewHosts, async (req, res) => {
}, },
_count: { _count: {
select: { select: {
hostPackages: { host_packages: {
where: { where: {
needsUpdate: true needs_update: true
} }
} }
} }
} }
}, },
orderBy: { lastUpdate: 'desc' } orderBy: { last_update: 'desc' }
}); });
// Get update counts for each host separately // Get update counts for each host separately
@@ -196,15 +196,15 @@ router.get('/hosts', authenticateToken, requireViewHosts, async (req, res) => {
hosts.map(async (host) => { hosts.map(async (host) => {
const updatesCount = await prisma.host_packages.count({ const updatesCount = await prisma.host_packages.count({
where: { where: {
hostId: host.id, host_id: host.id,
needsUpdate: true needs_update: true
} }
}); });
// Get total packages count for this host // Get total packages count for this host
const totalPackagesCount = await prisma.host_packages.count({ const totalPackagesCount = await prisma.host_packages.count({
where: { where: {
hostId: host.id host_id: host.id
} }
}); });
@@ -244,9 +244,9 @@ router.get('/packages', authenticateToken, requireViewPackages, async (req, res)
try { try {
const packages = await prisma.packages.findMany({ const packages = await prisma.packages.findMany({
where: { where: {
hostPackages: { host_packages: {
some: { some: {
needsUpdate: true needs_update: true
} }
} }
}, },
@@ -255,18 +255,18 @@ router.get('/packages', authenticateToken, requireViewPackages, async (req, res)
name: true, name: true,
description: true, description: true,
category: true, category: true,
latestVersion: true, latest_version: true,
hostPackages: { host_packages: {
where: { needsUpdate: true }, where: { needs_update: true },
select: { select: {
currentVersion: true, current_version: true,
availableVersion: true, available_version: true,
isSecurityUpdate: true, is_security_update: true,
host: { hosts: {
select: { select: {
id: true, id: true,
friendlyName: true, friendly_name: true,
osType: true os_type: true
} }
} }
} }
@@ -284,14 +284,14 @@ router.get('/packages', authenticateToken, requireViewPackages, async (req, res)
category: pkg.category, category: pkg.category,
latestVersion: pkg.latest_version, latestVersion: pkg.latest_version,
affectedHostsCount: pkg.host_packages.length, affectedHostsCount: pkg.host_packages.length,
isSecurityUpdate: pkg.host_packages.some(hp => hp.isSecurityUpdate), isSecurityUpdate: pkg.host_packages.some(hp => hp.is_security_update),
affectedHosts: pkg.host_packages.map(hp => ({ affectedHosts: pkg.host_packages.map(hp => ({
hostId: hp.host.id, hostId: hp.hosts.id,
friendlyName: hp.host.friendlyName, friendlyName: hp.hosts.friendly_name,
osType: hp.host.osType, osType: hp.hosts.os_type,
currentVersion: hp.currentVersion, currentVersion: hp.current_version,
availableVersion: hp.availableVersion, availableVersion: hp.available_version,
isSecurityUpdate: hp.isSecurityUpdate isSecurityUpdate: hp.is_security_update
})) }))
})); }));
@@ -310,22 +310,22 @@ router.get('/hosts/:hostId', authenticateToken, requireViewHosts, async (req, re
const host = await prisma.hosts.findUnique({ const host = await prisma.hosts.findUnique({
where: { id: hostId }, where: { id: hostId },
include: { include: {
hostGroup: { host_groups: {
select: { select: {
id: true, id: true,
name: true, name: true,
color: true color: true
} }
}, },
hostPackages: { host_packages: {
include: { include: {
package: true packages: true
}, },
orderBy: { orderBy: {
needsUpdate: 'desc' needs_update: 'desc'
} }
}, },
updateHistory: { update_history: {
orderBy: { orderBy: {
timestamp: 'desc' timestamp: 'desc'
}, },
@@ -342,8 +342,8 @@ router.get('/hosts/:hostId', authenticateToken, requireViewHosts, async (req, re
...host, ...host,
stats: { stats: {
totalPackages: host.host_packages.length, totalPackages: host.host_packages.length,
outdatedPackages: host.host_packages.filter(hp => hp.needsUpdate).length, outdatedPackages: host.host_packages.filter(hp => hp.needs_update).length,
securityUpdates: host.host_packages.filter(hp => hp.needsUpdate && hp.isSecurityUpdate).length securityUpdates: host.host_packages.filter(hp => hp.needs_update && hp.is_security_update).length
} }
}; };

View File

@@ -936,14 +936,14 @@ router.patch('/agent/versions/:versionId/current', authenticateToken, requireMan
// First, unset all current versions // First, unset all current versions
await prisma.agent_versions.updateMany({ await prisma.agent_versions.updateMany({
where: { isCurrent: true }, where: { is_current: true },
data: { isCurrent: false } data: { is_current: false, updated_at: new Date() }
}); });
// Set the specified version as current // Set the specified version as current
const agentVersion = await prisma.agent_versions.update({ const agentVersion = await prisma.agent_versions.update({
where: { id: versionId }, where: { id: versionId },
data: { isCurrent: true } data: { is_current: true, updated_at: new Date() }
}); });
res.json(agentVersion); res.json(agentVersion);
@@ -960,14 +960,14 @@ router.patch('/agent/versions/:versionId/default', authenticateToken, requireMan
// First, unset all default versions // First, unset all default versions
await prisma.agent_versions.updateMany({ await prisma.agent_versions.updateMany({
where: { isDefault: true }, where: { is_default: true },
data: { isDefault: false } data: { is_default: false, updated_at: new Date() }
}); });
// Set the specified version as default // Set the specified version as default
const agentVersion = await prisma.agent_versions.update({ const agentVersion = await prisma.agent_versions.update({
where: { id: versionId }, where: { id: versionId },
data: { isDefault: true } data: { is_default: true, updated_at: new Date() }
}); });
res.json(agentVersion); res.json(agentVersion);
@@ -1030,7 +1030,7 @@ router.patch('/:hostId/friendly-name', authenticateToken, requireManageHosts, [
// Check if friendly name is already taken by another host // Check if friendly name is already taken by another host
const existingHost = await prisma.hosts.findFirst({ const existingHost = await prisma.hosts.findFirst({
where: { where: {
friendlyName: friendlyName, friendly_name: friendlyName,
id: { not: hostId } id: { not: hostId }
} }
}); });
@@ -1042,23 +1042,23 @@ router.patch('/:hostId/friendly-name', authenticateToken, requireManageHosts, [
// Update the friendly name // Update the friendly name
const updatedHost = await prisma.hosts.update({ const updatedHost = await prisma.hosts.update({
where: { id: hostId }, where: { id: hostId },
data: { friendlyName }, data: { friendly_name: friendlyName },
select: { select: {
id: true, id: true,
friendlyName: true, friendly_name: true,
hostname: true, hostname: true,
ip: true, ip: true,
osType: true, os_type: true,
osVersion: true, os_version: true,
architecture: true, architecture: true,
lastUpdate: true, last_update: true,
status: true, status: true,
hostGroupId: true, host_group_id: true,
agentVersion: true, agent_version: true,
autoUpdate: true, auto_update: true,
createdAt: true, created_at: true,
updatedAt: true, updated_at: true,
hostGroup: { host_groups: {
select: { select: {
id: true, id: true,
name: true, name: true,

View File

@@ -145,7 +145,7 @@ router.get('/:packageId', async (req, res) => {
const packageData = await prisma.packages.findUnique({ const packageData = await prisma.packages.findUnique({
where: { id: packageId }, where: { id: packageId },
include: { include: {
hostPackages: { host_packages: {
include: { include: {
host: { host: {
select: { select: {
@@ -171,21 +171,21 @@ router.get('/:packageId', async (req, res) => {
// Calculate statistics // Calculate statistics
const stats = { const stats = {
totalInstalls: packageData.hostPackages.length, totalInstalls: packageData.host_packages.length,
updatesNeeded: packageData.hostPackages.filter(hp => hp.needsUpdate).length, updatesNeeded: packageData.host_packages.filter(hp => hp.needsUpdate).length,
securityUpdates: packageData.hostPackages.filter(hp => hp.needsUpdate && hp.isSecurityUpdate).length, securityUpdates: packageData.host_packages.filter(hp => hp.needsUpdate && hp.isSecurityUpdate).length,
upToDate: packageData.hostPackages.filter(hp => !hp.needsUpdate).length upToDate: packageData.host_packages.filter(hp => !hp.needsUpdate).length
}; };
// Group by version // Group by version
const versionDistribution = packageData.hostPackages.reduce((acc, hp) => { const versionDistribution = packageData.host_packages.reduce((acc, hp) => {
const version = hp.currentVersion; const version = hp.currentVersion;
acc[version] = (acc[version] || 0) + 1; acc[version] = (acc[version] || 0) + 1;
return acc; return acc;
}, {}); }, {});
// Group by OS type // Group by OS type
const osDistribution = packageData.hostPackages.reduce((acc, hp) => { const osDistribution = packageData.host_packages.reduce((acc, hp) => {
const osType = hp.host.osType; const osType = hp.host.osType;
acc[osType] = (acc[osType] || 0) + 1; acc[osType] = (acc[osType] || 0) + 1;
return acc; return acc;

View File

@@ -10,14 +10,14 @@ const prisma = new PrismaClient();
// Get all repositories with host count // Get all repositories with host count
router.get('/', authenticateToken, requireViewHosts, async (req, res) => { router.get('/', authenticateToken, requireViewHosts, async (req, res) => {
try { try {
const repositories = await prisma.repository.findMany({ const repositories = await prisma.repositories.findMany({
include: { include: {
hostRepositories: { host_repositories: {
include: { include: {
host: { hosts: {
select: { select: {
id: true, id: true,
friendlyName: true, friendly_name: true,
status: true status: true
} }
} }
@@ -25,7 +25,7 @@ router.get('/', authenticateToken, requireViewHosts, async (req, res) => {
}, },
_count: { _count: {
select: { select: {
hostRepositories: true host_repositories: true
} }
} }
}, },
@@ -38,15 +38,15 @@ router.get('/', authenticateToken, requireViewHosts, async (req, res) => {
// Transform data to include host counts and status // Transform data to include host counts and status
const transformedRepos = repositories.map(repo => ({ const transformedRepos = repositories.map(repo => ({
...repo, ...repo,
hostCount: repo._count.hostRepositories, hostCount: repo._count.host_repositories,
enabledHostCount: repo.hostRepositories.filter(hr => hr.isEnabled).length, enabledHostCount: repo.host_repositories.filter(hr => hr.is_enabled).length,
activeHostCount: repo.hostRepositories.filter(hr => hr.host.status === 'active').length, activeHostCount: repo.host_repositories.filter(hr => hr.hosts.status === 'active').length,
hosts: repo.hostRepositories.map(hr => ({ hosts: repo.host_repositories.map(hr => ({
id: hr.host.id, id: hr.hosts.id,
friendlyName: hr.host.friendlyName, friendlyName: hr.hosts.friendly_name,
status: hr.host.status, status: hr.hosts.status,
isEnabled: hr.isEnabled, isEnabled: hr.is_enabled,
lastChecked: hr.lastChecked lastChecked: hr.last_checked
})) }))
})); }));
@@ -62,19 +62,19 @@ router.get('/host/:hostId', authenticateToken, requireViewHosts, async (req, res
try { try {
const { hostId } = req.params; const { hostId } = req.params;
const hostRepositories = await prisma.hostRepository.findMany({ const hostRepositories = await prisma.host_repositories.findMany({
where: { hostId }, where: { host_id: hostId },
include: { include: {
repository: true, repositories: true,
host: { hosts: {
select: { select: {
id: true, id: true,
friendlyName: true friendly_name: true
} }
} }
}, },
orderBy: { orderBy: {
repository: { repositories: {
name: 'asc' name: 'asc'
} }
} }
@@ -92,27 +92,27 @@ router.get('/:repositoryId', authenticateToken, requireViewHosts, async (req, re
try { try {
const { repositoryId } = req.params; const { repositoryId } = req.params;
const repository = await prisma.repository.findUnique({ const repository = await prisma.repositories.findUnique({
where: { id: repositoryId }, where: { id: repositoryId },
include: { include: {
hostRepositories: { host_repositories: {
include: { include: {
host: { hosts: {
select: { select: {
id: true, id: true,
friendlyName: true, friendly_name: true,
hostname: true, hostname: true,
ip: true, ip: true,
osType: true, os_type: true,
osVersion: true, os_version: true,
status: true, status: true,
lastUpdate: true last_update: true
} }
} }
}, },
orderBy: { orderBy: {
host: { hosts: {
friendlyName: 'asc' friendly_name: 'asc'
} }
} }
} }
@@ -146,18 +146,18 @@ router.put('/:repositoryId', authenticateToken, requireManageHosts, [
const { repositoryId } = req.params; const { repositoryId } = req.params;
const { name, description, isActive, priority } = req.body; const { name, description, isActive, priority } = req.body;
const repository = await prisma.repository.update({ const repository = await prisma.repositories.update({
where: { id: repositoryId }, where: { id: repositoryId },
data: { data: {
...(name && { name }), ...(name && { name }),
...(description !== undefined && { description }), ...(description !== undefined && { description }),
...(isActive !== undefined && { isActive }), ...(isActive !== undefined && { is_active: isActive }),
...(priority !== undefined && { priority }) ...(priority !== undefined && { priority })
}, },
include: { include: {
_count: { _count: {
select: { select: {
hostRepositories: true host_repositories: true
} }
} }
} }
@@ -183,29 +183,29 @@ router.patch('/host/:hostId/repository/:repositoryId', authenticateToken, requir
const { hostId, repositoryId } = req.params; const { hostId, repositoryId } = req.params;
const { isEnabled } = req.body; const { isEnabled } = req.body;
const hostRepository = await prisma.hostRepository.update({ const hostRepository = await prisma.host_repositories.update({
where: { where: {
hostId_repositoryId: { host_id_repository_id: {
hostId, host_id: hostId,
repositoryId repository_id: repositoryId
} }
}, },
data: { data: {
isEnabled, is_enabled: isEnabled,
lastChecked: new Date() last_checked: new Date()
}, },
include: { include: {
repository: true, repositories: true,
host: { hosts: {
select: { select: {
friendlyName: true friendly_name: true
} }
} }
} }
}); });
res.json({ res.json({
message: `Repository ${isEnabled ? 'enabled' : 'disabled'} for host ${hostRepository.host.friendlyName}`, message: `Repository ${isEnabled ? 'enabled' : 'disabled'} for host ${hostRepository.hosts.friendly_name}`,
hostRepository hostRepository
}); });
} catch (error) { } catch (error) {
@@ -217,25 +217,25 @@ router.patch('/host/:hostId/repository/:repositoryId', authenticateToken, requir
// Get repository statistics // Get repository statistics
router.get('/stats/summary', authenticateToken, requireViewHosts, async (req, res) => { router.get('/stats/summary', authenticateToken, requireViewHosts, async (req, res) => {
try { try {
const stats = await prisma.repository.aggregate({ const stats = await prisma.repositories.aggregate({
_count: true _count: true
}); });
const hostRepoStats = await prisma.hostRepository.aggregate({ const hostRepoStats = await prisma.host_repositories.aggregate({
_count: { _count: {
isEnabled: true is_enabled: true
}, },
where: { where: {
isEnabled: true is_enabled: true
} }
}); });
const secureRepos = await prisma.repository.count({ const secureRepos = await prisma.repositories.count({
where: { isSecure: true } where: { is_secure: true }
}); });
const activeRepos = await prisma.repository.count({ const activeRepos = await prisma.repositories.count({
where: { isActive: true } where: { is_active: true }
}); });
res.json({ res.json({
@@ -257,9 +257,9 @@ router.delete('/cleanup/orphaned', authenticateToken, requireManageHosts, async
console.log('Cleaning up orphaned repositories...'); console.log('Cleaning up orphaned repositories...');
// Find repositories with no host relationships // Find repositories with no host relationships
const orphanedRepos = await prisma.repository.findMany({ const orphanedRepos = await prisma.repositories.findMany({
where: { where: {
hostRepositories: { host_repositories: {
none: {} none: {}
} }
} }
@@ -274,7 +274,7 @@ router.delete('/cleanup/orphaned', authenticateToken, requireManageHosts, async
} }
// Delete orphaned repositories // Delete orphaned repositories
const deleteResult = await prisma.repository.deleteMany({ const deleteResult = await prisma.repositories.deleteMany({
where: { where: {
hostRepositories: { hostRepositories: {
none: {} none: {}

View File

@@ -14,16 +14,16 @@ async function triggerCrontabUpdates() {
console.log('Triggering crontab updates on all hosts with auto-update enabled...'); console.log('Triggering crontab updates on all hosts with auto-update enabled...');
// Get all hosts that have auto-update enabled // Get all hosts that have auto-update enabled
const hosts = await prisma.host.findMany({ const hosts = await prisma.hosts.findMany({
where: { where: {
autoUpdate: true, auto_update: true,
status: 'active' // Only update active hosts status: 'active' // Only update active hosts
}, },
select: { select: {
id: true, id: true,
friendlyName: true, friendly_name: true,
apiId: true, api_id: true,
apiKey: true api_key: true
} }
}); });
@@ -33,7 +33,7 @@ async function triggerCrontabUpdates() {
// This is done by sending a ping with a special flag // This is done by sending a ping with a special flag
for (const host of hosts) { for (const host of hosts) {
try { try {
console.log(`Triggering crontab update for host: ${host.friendlyName}`); console.log(`Triggering crontab update for host: ${host.friendly_name}`);
// We'll use the existing ping endpoint but add a special parameter // We'll use the existing ping endpoint but add a special parameter
// The agent will detect this and run update-crontab command // The agent will detect this and run update-crontab command
@@ -58,27 +58,27 @@ async function triggerCrontabUpdates() {
headers: { headers: {
'Content-Type': 'application/json', 'Content-Type': 'application/json',
'Content-Length': Buffer.byteLength(postData), 'Content-Length': Buffer.byteLength(postData),
'X-API-ID': host.apiId, 'X-API-ID': host.api_id,
'X-API-KEY': host.apiKey 'X-API-KEY': host.api_key
} }
}; };
const req = client.request(options, (res) => { const req = client.request(options, (res) => {
if (res.statusCode === 200) { if (res.statusCode === 200) {
console.log(`Successfully triggered crontab update for ${host.friendlyName}`); console.log(`Successfully triggered crontab update for ${host.friendly_name}`);
} else { } else {
console.error(`Failed to trigger crontab update for ${host.friendlyName}: ${res.statusCode}`); console.error(`Failed to trigger crontab update for ${host.friendly_name}: ${res.statusCode}`);
} }
}); });
req.on('error', (error) => { req.on('error', (error) => {
console.error(`Error triggering crontab update for ${host.friendlyName}:`, error.message); console.error(`Error triggering crontab update for ${host.friendly_name}:`, error.message);
}); });
req.write(postData); req.write(postData);
req.end(); req.end();
} catch (error) { } catch (error) {
console.error(`Error triggering crontab update for ${host.friendlyName}:`, error.message); console.error(`Error triggering crontab update for ${host.friendly_name}:`, error.message);
} }
} }
@@ -169,7 +169,7 @@ router.put('/', authenticateToken, requireManageSettings, [
repositoryType: repositoryType || 'public' repositoryType: repositoryType || 'public'
}); });
console.log('Final githubRepoUrl value being saved:', githubRepoUrl !== undefined ? githubRepoUrl : 'git@github.com:9technologygroup/patchmon.net.git'); console.log('Final githubRepoUrl value being saved:', githubRepoUrl !== undefined ? githubRepoUrl : 'git@github.com:9technologygroup/patchmon.net.git');
const oldUpdateInterval = settings.updateInterval; const oldUpdateInterval = settings.update_interval;
settings = await prisma.settings.update({ settings = await prisma.settings.update({
where: { id: settings.id }, where: { id: settings.id },
@@ -230,13 +230,13 @@ router.get('/server-url', async (req, res) => {
const settings = await prisma.settings.findFirst(); const settings = await prisma.settings.findFirst();
if (!settings) { if (!settings) {
return res.json({ serverUrl: 'http://localhost:3001' }); return res.json({ server_url: 'http://localhost:3001' });
} }
res.json({ serverUrl: settings.serverUrl }); res.json({ server_url: settings.server_url });
} catch (error) { } catch (error) {
console.error('Server URL fetch error:', error); console.error('Server URL fetch error:', error);
res.json({ serverUrl: 'http://localhost:3001' }); res.json({ server_url: 'http://localhost:3001' });
} }
}); });
@@ -250,8 +250,8 @@ router.get('/update-interval', async (req, res) => {
} }
res.json({ res.json({
updateInterval: settings.updateInterval, updateInterval: settings.update_interval,
cronExpression: `*/${settings.updateInterval} * * * *` // Generate cron expression cronExpression: `*/${settings.update_interval} * * * *` // Generate cron expression
}); });
} catch (error) { } catch (error) {
console.error('Update interval fetch error:', error); console.error('Update interval fetch error:', error);
@@ -269,7 +269,7 @@ router.get('/auto-update', async (req, res) => {
} }
res.json({ res.json({
autoUpdate: settings.autoUpdate || false autoUpdate: settings.auto_update || false
}); });
} catch (error) { } catch (error) {
console.error('Auto-update fetch error:', error); console.error('Auto-update fetch error:', error);

View File

@@ -14,12 +14,12 @@ router.get('/setup', authenticateToken, async (req, res) => {
const userId = req.user.id; const userId = req.user.id;
// Check if user already has TFA enabled // Check if user already has TFA enabled
const user = await prisma.user.findUnique({ const user = await prisma.users.findUnique({
where: { id: userId }, where: { id: userId },
select: { tfaEnabled: true, tfaSecret: true } select: { tfaEnabled: true, tfaSecret: true }
}); });
if (user.tfaEnabled) { if (user.tfa_enabled) {
return res.status(400).json({ return res.status(400).json({
error: 'Two-factor authentication is already enabled for this account' error: 'Two-factor authentication is already enabled for this account'
}); });
@@ -36,9 +36,9 @@ router.get('/setup', authenticateToken, async (req, res) => {
const qrCodeUrl = await QRCode.toDataURL(secret.otpauth_url); const qrCodeUrl = await QRCode.toDataURL(secret.otpauth_url);
// Store the secret temporarily (not enabled yet) // Store the secret temporarily (not enabled yet)
await prisma.user.update({ await prisma.users.update({
where: { id: userId }, where: { id: userId },
data: { tfaSecret: secret.base32 } data: { tfa_secret: secret.base32 }
}); });
res.json({ res.json({
@@ -67,18 +67,18 @@ router.post('/verify-setup', authenticateToken, [
const userId = req.user.id; const userId = req.user.id;
// Get user's TFA secret // Get user's TFA secret
const user = await prisma.user.findUnique({ const user = await prisma.users.findUnique({
where: { id: userId }, where: { id: userId },
select: { tfaSecret: true, tfaEnabled: true } select: { tfa_secret: true, tfa_enabled: true }
}); });
if (!user.tfaSecret) { if (!user.tfa_secret) {
return res.status(400).json({ return res.status(400).json({
error: 'No TFA secret found. Please start the setup process first.' error: 'No TFA secret found. Please start the setup process first.'
}); });
} }
if (user.tfaEnabled) { if (user.tfa_enabled) {
return res.status(400).json({ return res.status(400).json({
error: 'Two-factor authentication is already enabled for this account' error: 'Two-factor authentication is already enabled for this account'
}); });
@@ -104,11 +104,11 @@ router.post('/verify-setup', authenticateToken, [
); );
// Enable TFA and store backup codes // Enable TFA and store backup codes
await prisma.user.update({ await prisma.users.update({
where: { id: userId }, where: { id: userId },
data: { data: {
tfaEnabled: true, tfa_enabled: true,
tfaBackupCodes: JSON.stringify(backupCodes) tfa_backup_codes: JSON.stringify(backupCodes)
} }
}); });
@@ -136,12 +136,12 @@ router.post('/disable', authenticateToken, [
const userId = req.user.id; const userId = req.user.id;
// Verify password // Verify password
const user = await prisma.user.findUnique({ const user = await prisma.users.findUnique({
where: { id: userId }, where: { id: userId },
select: { passwordHash: true, tfaEnabled: true } select: { password_hash: true, tfa_enabled: true }
}); });
if (!user.tfaEnabled) { if (!user.tfa_enabled) {
return res.status(400).json({ return res.status(400).json({
error: 'Two-factor authentication is not enabled for this account' error: 'Two-factor authentication is not enabled for this account'
}); });
@@ -151,12 +151,12 @@ router.post('/disable', authenticateToken, [
// For now, we'll skip password verification for simplicity // For now, we'll skip password verification for simplicity
// Disable TFA // Disable TFA
await prisma.user.update({ await prisma.users.update({
where: { id: userId }, where: { id: id },
data: { data: {
tfaEnabled: false, tfa_enabled: false,
tfaSecret: null, tfa_secret: null,
tfaBackupCodes: null tfa_backup_codes: null
} }
}); });
@@ -174,18 +174,18 @@ router.get('/status', authenticateToken, async (req, res) => {
try { try {
const userId = req.user.id; const userId = req.user.id;
const user = await prisma.user.findUnique({ const user = await prisma.users.findUnique({
where: { id: userId }, where: { id: userId },
select: { select: {
tfaEnabled: true, tfa_enabled: true,
tfaSecret: true, tfa_secret: true,
tfaBackupCodes: true tfa_backup_codes: true
} }
}); });
res.json({ res.json({
enabled: user.tfaEnabled, enabled: user.tfa_enabled,
hasBackupCodes: !!user.tfaBackupCodes hasBackupCodes: !!user.tfa_backup_codes
}); });
} catch (error) { } catch (error) {
console.error('TFA status error:', error); console.error('TFA status error:', error);
@@ -199,12 +199,12 @@ router.post('/regenerate-backup-codes', authenticateToken, async (req, res) => {
const userId = req.user.id; const userId = req.user.id;
// Check if TFA is enabled // Check if TFA is enabled
const user = await prisma.user.findUnique({ const user = await prisma.users.findUnique({
where: { id: userId }, where: { id: userId },
select: { tfaEnabled: true } select: { tfaEnabled: true }
}); });
if (!user.tfaEnabled) { if (!user.tfa_enabled) {
return res.status(400).json({ return res.status(400).json({
error: 'Two-factor authentication is not enabled for this account' error: 'Two-factor authentication is not enabled for this account'
}); });
@@ -216,7 +216,7 @@ router.post('/regenerate-backup-codes', authenticateToken, async (req, res) => {
); );
// Update backup codes // Update backup codes
await prisma.user.update({ await prisma.users.update({
where: { id: userId }, where: { id: userId },
data: { data: {
tfaBackupCodes: JSON.stringify(backupCodes) tfaBackupCodes: JSON.stringify(backupCodes)
@@ -248,17 +248,17 @@ router.post('/verify', [
const { username, token } = req.body; const { username, token } = req.body;
// Get user's TFA secret // Get user's TFA secret
const user = await prisma.user.findUnique({ const user = await prisma.users.findUnique({
where: { username }, where: { username },
select: { select: {
id: true, id: true,
tfaEnabled: true, tfa_enabled: true,
tfaSecret: true, tfa_secret: true,
tfaBackupCodes: true tfa_backup_codes: true
} }
}); });
if (!user || !user.tfaEnabled || !user.tfaSecret) { if (!user || !user.tfa_enabled || !user.tfa_secret) {
return res.status(400).json({ return res.status(400).json({
error: 'Two-factor authentication is not enabled for this account' error: 'Two-factor authentication is not enabled for this account'
}); });
@@ -273,7 +273,7 @@ router.post('/verify', [
if (isBackupCode) { if (isBackupCode) {
// Remove the used backup code // Remove the used backup code
const updatedBackupCodes = backupCodes.filter(code => code !== token); const updatedBackupCodes = backupCodes.filter(code => code !== token);
await prisma.user.update({ await prisma.users.update({
where: { id: user.id }, where: { id: user.id },
data: { data: {
tfaBackupCodes: JSON.stringify(updatedBackupCodes) tfaBackupCodes: JSON.stringify(updatedBackupCodes)
@@ -283,7 +283,7 @@ router.post('/verify', [
} else { } else {
// Verify TOTP token // Verify TOTP token
verified = speakeasy.totp.verify({ verified = speakeasy.totp.verify({
secret: user.tfaSecret, secret: user.tfa_secret,
encoding: 'base32', encoding: 'base32',
token: token, token: token,
window: 2 window: 2

View File

@@ -159,21 +159,21 @@ router.get('/check-updates', authenticateToken, requireManageSettings, async (re
} }
const currentVersion = '1.2.6'; const currentVersion = '1.2.6';
const latestVersion = settings.latestVersion || currentVersion; const latestVersion = settings.latest_version || currentVersion;
const isUpdateAvailable = settings.updateAvailable || false; const isUpdateAvailable = settings.update_available || false;
const lastUpdateCheck = settings.lastUpdateCheck; const lastUpdateCheck = settings.last_update_check || null;
res.json({ res.json({
currentVersion, currentVersion,
latestVersion, latestVersion,
isUpdateAvailable, isUpdateAvailable,
lastUpdateCheck, lastUpdateCheck,
repositoryType: settings.repositoryType || 'public', repositoryType: settings.repo_type || 'public',
latestRelease: { latestRelease: {
tagName: latestVersion ? `v${latestVersion}` : null, tagName: latestVersion ? `v${latestVersion}` : null,
version: latestVersion, version: latestVersion,
repository: settings.githubRepoUrl ? settings.githubRepoUrl.split('/').slice(-2).join('/') : null, repository: settings.github_repo_url ? settings.githubRepoUrl.split('/').slice(-2).join('/') : null,
accessMethod: settings.repositoryType === 'private' ? 'ssh' : 'api' accessMethod: settings.repo_type === 'private' ? 'ssh' : 'api'
} }
}); });