import {query,UUID2hex,HEX2uuid} from '@commtool/sql-query'
import { Buffer } from 'node:buffer';
import { errorLoggerRead, errorLoggerUpdate } from './requestLogger.js';
export const checkAdmin=async (req,res,next, error)=>
{
try {
if(await isAdmin(req.session))
{
req.session.admin=true
next()
return
}
else
{
req.session.admin=false
res.status(200).json({success:false,message:'your are not authorized for this operation'})
}
}
catch(e)
{
errorLoggerUpdate(e)
next()
}
}
export const checkBaseAdmin=async (req,res,next)=>
{
try {
if(await isBaseAdmin(req.session))
{
req.session.baseAdmin=true
next()
return
}
else
{
req.session.baseAdmin=false
res.status(401).json({success:false,message:'your base user is not authorized for this operation'})
}
}
catch(e)
{
errorLoggerUpdate(e)
return false
}
}
/**
* Check if user is admin for an organization
* MIGRATION: Checks both Keycloak orgRoles (new) AND database admin list (legacy)
* Once bot sync is complete, database check can be removed
*
* @param {Buffer|string} user - User UID
* @param {Buffer|string} orga - Organization UID (Buffer or hex string)
* @param {Object} [session] - Optional session object to check Keycloak orgRoles
* @returns {Promise<boolean|null>} true if admin, false if not admin, null if no admin list defined
*/
export const isAdminOrga = async (user, orga, session = null) => {
try {
// NEW: Check Keycloak organization roles first (faster, no DB query)
// orgRoles is already filtered by sessionEnhancer to only include roles for current organization
if (session?.roles) {
return session.roles[HEX2uuid(orga).replace(/^UUID-/, '')].includes('db-admin');
}
return false;
}
catch(e) {
errorLoggerUpdate(e);
return false;
}
}
/**
* Check if user is admin for current organization
* MIGRATION: Checks Keycloak orgRoles first, then falls back to database
*
* @param {Object} session - Express session object
* @returns {Promise<boolean>} true if user has admin rights
*/
export const isAdmin = async (session) => {
try {
// Bot user has admin rights
if( session?.authUser?.groups.includes('app-bot') || session?.authUser?.groups.includes('employees') )
return true;
if(isEmployee(session))
{
session.admin= true;
return true;
}
if(session.superadmin)
return true;
if(!session || !session.root || !session.authUser)
return false;
// Return cached result if available
if(session && session.admin !== undefined && session.admin !== null)
return session.admin;
// NEW: Check Keycloak organization roles
if(session.authUser?.orgRolesArray?.includes('db-admin')) {
console.log('[isAdmin] ✅ User has org-admin role from Keycloak');
session.admin = true;
return true;
}
return session.admin;
}
catch(e) {
errorLoggerUpdate(e);
return false;
}
}
/**
* Check if the base user (real user, not impersonated) has admin rights
* MIGRATION: Checks Keycloak orgRoles first, then falls back to database
*
* @param {Object} session - Express session object
* @returns {Promise<boolean>} true if base user has admin rights
*/
export const isBaseAdmin = async (session) => {
try {
if(!session || !session.root || !session.authUser )
return false;
if(session?.authUser?.groups.includes('app-bot') || session?.authUser?.groups.includes('employees'))
return true;
// Return cached result if available
if(session && session.baseAdmin !== undefined)
return session.baseAdmin;
// NEW: Check Keycloak organization roles
if(session.authUser?.orgRolesArray?.includes('db-admin')) {
console.log('[isBaseAdmin] ✅ Base user has org-admin role from Keycloak');
session.baseAdmin = true;
return true;
}
}
catch(e) {
errorLoggerUpdate(e);
return false;
}
}
export const isObjectAdmin=async (req,check)=>
{
try {
// checks if the user can administrate an object
if(!Buffer.isBuffer(check))
check=UUID2hex(check)
if(await isAdmin(req.session))
return true
if(!check)
return false
const result=await query(`SELECT Visible.UID FROM Visible
WHERE Type IN('changeable','admin') AND UID=? AND UIDUser=?
`,[check,UUID2hex(req.session.user)])
if(result.length===1)
return true
else
return false
}
catch(e)
{
errorLoggerUpdate(e)
return false
}
}
export const checkObjectAdmin= async (req,res,next, error)=>
{
try {
if(await isAdmin(req.session))
{
next()
return
}
// find all params which are UID's and check if we have changeable rights for them
const UIDs=Object.values(req.params)
.filter(value=>(typeof value==='string' && value.match(/^UUID\-[0-9A-Fa-f]{8}-[0-9A-Fa-f]{4}-[1-5][0-9A-Fa-f]{3}-[89ABab][0-9A-Fa-f]{3}-[0-9A-Fa-f]{12}$/) ))
.map(value=>UUID2hex(value))
const results= await query(`SELECT UID FROM Visible WHERE Type IN('changeable','admin') AND UID IN(?) AND UIDUser=?`,
[UIDs,UUID2hex(req.session.user)])
if(UIDs.length===0 || results.length===UIDs.length)
{
next()
return
}
else
res.status(200).json({success:false,message: 'user has no change authorisation for one this objects'})
}
catch(e)
{
errorLoggerUpdate(e)
next()
}
}
export const isListAdmin=async (req,check)=>
{
try {
// checks if the user can administrate a list
check=UUID2hex(check)
if(await isAdmin(req.session))
return true
const result=await query(`SELECT Visible.UID FROM Visible
WHERE Type ='admin' AND UID=? AND UIDUser=?
`,[check,UUID2hex(req.session.user)])
if(result.length===1)
return true
else
return false
}
catch(e)
{
errorLoggerUpdate(e)
return false
}
}
export const isVisible=async (UID,user,root=null,session=null)=>
{
try {
if(user && user!=='undefined' && UID)
{
const visible= await query(`SELECT UID FROM Visible WHERE UID=? AND UIDUser=?`,[UID,user])
return visible.length===1
}
if(root && session)
{
const admin=await isAdminOrga(UUID2hex(session.user),UUID2hex(session.root),session)
return admin
}
return false
}
catch(e)
{
errorLoggerRead(e)
return false
}
}
export const isChangeable=async (UID,user,root=null,session=null)=>
{
try {
if(user && user!=='undefined' && UID)
{
const visible= await query(`SELECT UID FROM Visible WHERE UID=? AND UIDUser=? AND Type IN ('changeable','admin')`,[UID,user])
return visible.length===1
}
if(root && session)
{
const admin=await isAdmin(session)
return admin
}
return false
}
catch(e)
{
errorLoggerUpdate(e)
return false
}
}
export const isObjectVisible=async (req,check)=>
{
try {
// checks if the user can see an object
if(!Buffer.isBuffer(check))
check=UUID2hex(check)
if(!check)
return false
if(await isAdmin(req.session))
return true
if(!check)
return false
const result=await query(`SELECT UID FROM Visible WHERE UID=? AND UIDUser=?
`,[check,UUID2hex(req.session.user)])
if(result.length===1)
return true
else
return false
}
catch(e)
{
errorLoggerRead(e)
return false
}
}
export const checkVisible=async (req,res,next,error)=>
{
try {
if(await isAdmin(req.session) || !req.params)
{
next()
return
}
// find all params which are UID's and check if we have visible rights for them
const UIDs=Object.values(req.params)
.filter(value=>(typeof value==='string' && value.match(/^UUID\-[0-9A-Fa-f]{8}-[0-9A-Fa-f]{4}-[1-5][0-9A-Fa-f]{3}-[89ABab][0-9A-Fa-f]{3}-[0-9A-Fa-f]{12}$/) ))
.map(value=>UUID2hex(value))
if(UIDs.length===0)
{
res.status(404).send('no valid UUIDs supplied')
return
}
const results= await query(`SELECT UID FROM Visible WHERE UID IN(?) AND UIDUser=?`,
[UIDs,UUID2hex(req.session.user)])
if(UIDs.length===0 || results.length===UIDs.length)
{
next()
return
}
else
{
res.status(200).json({success:false, message:'user not allowed to view one of the UUIDs'})
}
}
catch(e)
{
errorLoggerRead(e)
next()
}
}
export const isEmployee = (session) => {
try {
if(!session || !session.authUser)
{
console.log('no session, root or authUser')
return false
}
if(session.authUser?.isBotAuth)
return true
// Check Keycloak groups for employee access
if(session.authUser?.groups?.includes('employees') ||
session.authUser?.groups?.includes('administrators'))
return true
return false
}
catch(e) {
errorLoggerUpdate(e)
return false
}
}
export const checkEmployee = async (req, res, next) => {
try {
if(await isEmployee(req.session)) {
req.session.employee = true
next()
return
}
else {
req.session.employee = false
res.status(200).json({success: false, message: 'Employee rights required for this operation'})
}
}
catch(e) {
errorLoggerUpdate(e)
next()
}
}