Enhance utility functions and refactor authentication logic

- Added a new jsonToCacheKey function to generate a SHA-256 hash from a canonicalized JSON object for improved caching.
- Updated getModelByName to return the first model directly instead of an array.
- Refactored authentication logic to utilize listObjects for user and host retrieval, ensuring consistent handling of returned data.
- Improved logging for OTP verification to include the specific OTP used in the search.
This commit is contained in:
Tom Butcher 2025-09-05 23:30:06 +01:00
parent 8ccdc81de1
commit ab50a5261d
3 changed files with 20 additions and 16 deletions

View File

@ -4,11 +4,7 @@ import jwt from 'jsonwebtoken';
import log4js from 'log4js'; import log4js from 'log4js';
// Load configuration // Load configuration
import { loadConfig } from '../config.js'; import { loadConfig } from '../config.js';
import { import { editObject, getObject, listObjects } from '../database/database.js';
editObject,
getObject,
getObjectByFilter
} from '../database/database.js';
import { hostModel } from '../database/schemas/management/host.schema.js'; import { hostModel } from '../database/schemas/management/host.schema.js';
import { userModel } from '../database/schemas/management/user.schema.js'; import { userModel } from '../database/schemas/management/user.schema.js';
import { generateAuthCode } from '../utils.js'; import { generateAuthCode } from '../utils.js';
@ -82,16 +78,16 @@ export class KeycloakAuth {
roles: this.extractRoles(decodedToken) roles: this.extractRoles(decodedToken)
}; };
const user = await getObjectByFilter({ const user = await listObjects({
model: userModel, model: userModel,
filter: { username: decodedUser.username } filter: { username: decodedUser.username }
}); });
// Cache the verified token // Cache the verified token
const expiresAt = introspection.exp * 1000; // Convert to milliseconds const expiresAt = introspection.exp * 1000; // Convert to milliseconds
this.tokenCache.set(token, { expiresAt, user }); this.tokenCache.set(token, { expiresAt, user: user[0] });
return { valid: true, user }; return { valid: true, user: user[0] };
} catch (error) { } catch (error) {
logger.error('Token verification error:', error.message); logger.error('Token verification error:', error.message);
return { valid: false }; return { valid: false };
@ -167,13 +163,14 @@ export class CodeAuth {
async verifyOtp(otp) { async verifyOtp(otp) {
try { try {
const host = await getObjectByFilter({ const hosts = await listObjects({
model: hostModel, model: hostModel,
filter: { otp: otp }, filter: { otp: otp },
cached: false cached: false
}); });
const host = hosts[0];
if (host == undefined) { if (host == undefined) {
const error = 'No host found with OTP.'; const error = `No host found with OTP: ${otp}`;
logger.warn(error); logger.warn(error);
return { valid: false, error: error }; return { valid: false, error: error };
} }
@ -203,9 +200,10 @@ export class CodeAuth {
id: id, id: id,
updateData: { authCode: generateAuthCode() } updateData: { authCode: generateAuthCode() }
}); });
logger.info('Host found with OTP:', otp);
return { valid: true, host: authCodeHost }; return { valid: true, host: authCodeHost };
} catch (error) { } catch (error) {
logger.error('Code verification error:', error.message); logger.error('OTP verification error:', error.message);
return { valid: false, error: error.message }; return { valid: false, error: error.message };
} }
} }
@ -218,7 +216,6 @@ export function createAuthMiddleware(socketUser) {
// Allow the 'authenticate' event through without checks // Allow the 'authenticate' event through without checks
logger.trace('Event:', event);
if (event === 'authenticate') { if (event === 'authenticate') {
next(); next();
return; return;

View File

@ -1,6 +1,6 @@
import { ObjectId } from 'mongodb'; import { ObjectId } from 'mongodb';
import { auditLogModel } from './schemas/management/auditlog.schema.js'; import { auditLogModel } from './schemas/management/auditlog.schema.js';
import { etcdServer } from './etcd.js'; import { natsServer } from './nats.js';
function parseFilter(property, value) { function parseFilter(property, value) {
if (typeof value === 'string') { if (typeof value === 'string') {
@ -411,11 +411,11 @@ async function getAuditLogs(idOrIds) {
} }
async function distributeUpdate(value, id, type) { async function distributeUpdate(value, id, type) {
await etcdServer.setKey(`/${type}s/${id}/object`, value); await natsServer.publish(`${type}s.${id}.object`, value);
} }
async function distributeNew(id, type) { async function distributeNew(id, type) {
await etcdServer.setKey(`/${type}s/new`, id); await natsServer.publish(`${type}s.new`, id);
} }
function flatternObjectIds(object) { function flatternObjectIds(object) {

View File

@ -2,6 +2,7 @@ import { editObject } from './database/database.js';
import { hostModel } from './database/schemas/management/host.schema.js'; import { hostModel } from './database/schemas/management/host.schema.js';
import crypto from 'crypto'; import crypto from 'crypto';
import { nanoid } from 'nanoid'; import { nanoid } from 'nanoid';
import canonicalize from 'canonical-json';
import { loadConfig } from './config.js'; import { loadConfig } from './config.js';
import { userModel } from './database/schemas/management/user.schema.js'; import { userModel } from './database/schemas/management/user.schema.js';
@ -86,5 +87,11 @@ export function getChangedValues(oldObj, newObj, old = false) {
} }
export function getModelByName(modelName) { export function getModelByName(modelName) {
return modelList.filter(model => model.modelName == modelName); return modelList.filter(model => model.modelName == modelName)[0];
}
export function jsonToCacheKey(obj) {
const normalized = canonicalize(obj);
const hash = crypto.createHash('sha256').update(normalized).digest('hex');
return hash;
} }