mirror of
https://github.com/DeNNiiInc/dbgate.git
synced 2026-04-17 23:45:59 +00:00
auditlog dummy methods
This commit is contained in:
@@ -1,286 +1,7 @@
|
||||
// *** This file is part of DbGate Premium ***
|
||||
// only in DbGate Premium
|
||||
|
||||
const { getLogger, extractErrorLogData } = require('dbgate-tools');
|
||||
const { storageSqlCommandFmt, storageSelectFmt } = require('../controllers/storageDb');
|
||||
const logger = getLogger('auditLog');
|
||||
const _ = require('lodash');
|
||||
|
||||
let auditLogQueue = [];
|
||||
let isProcessing = false;
|
||||
let isPlanned = false;
|
||||
|
||||
function nullableSum(a, b) {
|
||||
const res = (a || 0) + (b || 0);
|
||||
return res == 0 ? null : res;
|
||||
}
|
||||
|
||||
async function processAuditLogQueue() {
|
||||
do {
|
||||
isProcessing = true;
|
||||
const elements = [...auditLogQueue];
|
||||
auditLogQueue = [];
|
||||
|
||||
while (elements.length > 0) {
|
||||
const element = elements.shift();
|
||||
if (!element) continue;
|
||||
if (element.sessionId && element.sessionGroup && element.sessionParam) {
|
||||
const existingRows = await storageSelectFmt(
|
||||
'^select ~id, ~sumint_1, ~sumint_2 from ~audit_log where ~session_id = %v and ~session_group = %v and ~session_param = %v',
|
||||
element.sessionId,
|
||||
element.sessionGroup,
|
||||
element.sessionParam
|
||||
);
|
||||
if (existingRows && existingRows.length > 0) {
|
||||
const existing = existingRows[0];
|
||||
await storageSqlCommandFmt(
|
||||
'^update ~audit_log set ~sumint_1 = %v, ~sumint_2 = %v, ~modified = %v where ~id = %v',
|
||||
nullableSum(element.sumint1, existing.sumint_1),
|
||||
nullableSum(element.sumint2, existing.sumint_2),
|
||||
element.created,
|
||||
existing.id
|
||||
);
|
||||
// only update existing session
|
||||
continue;
|
||||
}
|
||||
}
|
||||
try {
|
||||
let connectionData = null;
|
||||
if (element.conid) {
|
||||
const connections = await storageSelectFmt('^select * from ~connections where ~conid = %v', element.conid);
|
||||
if (connections[0])
|
||||
connectionData = _.pick(connections[0], [
|
||||
'displayName',
|
||||
'engine',
|
||||
'displayName',
|
||||
'databaseUrl',
|
||||
'singleDatabase',
|
||||
'server',
|
||||
'databaseFile',
|
||||
'useSshTunnel',
|
||||
'sshHost',
|
||||
'defaultDatabase',
|
||||
]);
|
||||
}
|
||||
|
||||
const detailText = _.isPlainObject(element.detail) ? JSON.stringify(element.detail) : element.detail || null;
|
||||
const connectionDataText = connectionData ? JSON.stringify(connectionData) : null;
|
||||
await storageSqlCommandFmt(
|
||||
`^insert ^into ~audit_log (
|
||||
~user_id, ~user_login, ~created, ~category, ~component, ~event, ~detail, ~detail_full_length, ~action, ~severity,
|
||||
~conid, ~database, ~schema_name, ~pure_name, ~sumint_1, ~sumint_2, ~session_id, ~session_group, ~session_param, ~connection_data, ~message)
|
||||
values (%v, %v, %v, %v, %v, %v, %v, %v, %v, %v, %v, %v, %v, %v, %v, %v, %v, %v, %v, %v, %v)`,
|
||||
element.userId || null,
|
||||
element.login || null,
|
||||
element.created,
|
||||
element.category || null,
|
||||
element.component || null,
|
||||
element.event || null,
|
||||
detailText?.slice(0, 1000) || null,
|
||||
detailText?.length || null,
|
||||
element.action || null,
|
||||
element.severity || 'info',
|
||||
element.conid || null,
|
||||
element.database || null,
|
||||
element.schemaName || null,
|
||||
element.pureName || null,
|
||||
element.sumint1 || null,
|
||||
element.sumint2 || null,
|
||||
element.sessionId || null,
|
||||
element.sessionGroup || null,
|
||||
element.sessionParam || null,
|
||||
connectionDataText?.slice(0, 1000) || null,
|
||||
element.message || null
|
||||
);
|
||||
} catch (err) {
|
||||
logger.error(extractErrorLogData(err), 'Error processing audit log entry');
|
||||
}
|
||||
}
|
||||
|
||||
isProcessing = false;
|
||||
} while (auditLogQueue.length > 0);
|
||||
isPlanned = false;
|
||||
}
|
||||
|
||||
async function sendToAuditLog(
|
||||
req,
|
||||
{
|
||||
category,
|
||||
component,
|
||||
event,
|
||||
detail = null,
|
||||
action,
|
||||
severity = 'info',
|
||||
conid = null,
|
||||
database = null,
|
||||
schemaName = null,
|
||||
pureName = null,
|
||||
sumint1 = null,
|
||||
sumint2 = null,
|
||||
sessionGroup = null,
|
||||
sessionParam = null,
|
||||
message = null,
|
||||
}
|
||||
) {
|
||||
if (!process.env.STORAGE_DATABASE) {
|
||||
return;
|
||||
}
|
||||
const config = require('../controllers/config');
|
||||
const settings = await config.getCachedSettings();
|
||||
if (settings?.['storage.useAuditLog'] != 'true') {
|
||||
return;
|
||||
}
|
||||
|
||||
const { login, userId } = req?.user || {};
|
||||
const sessionId = req?.headers?.['x-api-session-id'];
|
||||
|
||||
auditLogQueue.push({
|
||||
userId,
|
||||
login,
|
||||
created: new Date().getTime(),
|
||||
category,
|
||||
component,
|
||||
event,
|
||||
detail,
|
||||
action,
|
||||
severity,
|
||||
conid,
|
||||
database,
|
||||
schemaName,
|
||||
pureName,
|
||||
sumint1,
|
||||
sumint2,
|
||||
sessionId,
|
||||
sessionGroup,
|
||||
sessionParam,
|
||||
message,
|
||||
});
|
||||
if (!isProcessing && !isPlanned) {
|
||||
setTimeout(() => {
|
||||
isPlanned = true;
|
||||
processAuditLogQueue();
|
||||
}, 0);
|
||||
}
|
||||
}
|
||||
|
||||
function maskLogFields(script) {
|
||||
return _.cloneDeepWith(script, (value, key) => {
|
||||
if (_.isString(key) && key.toLowerCase().includes('password')) {
|
||||
return '****';
|
||||
}
|
||||
if (key == 'query') {
|
||||
return '****';
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function extractConnectionId(connection) {
|
||||
if (
|
||||
connection?.server == process.env.STORAGE_SERVER &&
|
||||
connection?.database == process.env.STORAGE_DATABASE &&
|
||||
connection?.port == process.env.STORAGE_PORT
|
||||
) {
|
||||
return '__storage';
|
||||
}
|
||||
if (connection?.conid) {
|
||||
return connection.conid;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function analyseJsonRunnerScript(script) {
|
||||
const [assignSource, assignTarget, copyStream] = _.isArray(script?.commands) ? script?.commands : [];
|
||||
if (assignSource?.type != 'assign') {
|
||||
return null;
|
||||
}
|
||||
if (assignTarget?.type != 'assign') {
|
||||
return null;
|
||||
}
|
||||
if (copyStream?.type != 'copyStream') {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (assignTarget?.functionName == 'tableWriter') {
|
||||
const pureName = assignTarget?.props?.pureName;
|
||||
const schemaName = assignTarget?.props?.schemaName;
|
||||
const connection = assignTarget?.props?.connection;
|
||||
if (pureName && connection) {
|
||||
return {
|
||||
category: 'import',
|
||||
component: 'RunnersController',
|
||||
event: 'import.table',
|
||||
action: 'import',
|
||||
severity: 'info',
|
||||
message: `Importing table ${pureName}`,
|
||||
pureName: pureName,
|
||||
conid: extractConnectionId(connection),
|
||||
database: connection?.database,
|
||||
schemaName: schemaName,
|
||||
detail: maskLogFields(script),
|
||||
};
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
if (assignSource?.functionName == 'tableReader') {
|
||||
const pureName = assignSource?.props?.pureName;
|
||||
const schemaName = assignSource?.props?.schemaName;
|
||||
const connection = assignSource?.props?.connection;
|
||||
if (pureName && connection) {
|
||||
return {
|
||||
category: 'export',
|
||||
component: 'RunnersController',
|
||||
event: 'export.table',
|
||||
action: 'export',
|
||||
severity: 'info',
|
||||
message: `Exporting table ${pureName}`,
|
||||
pureName: pureName,
|
||||
conid: extractConnectionId(connection),
|
||||
database: connection?.database,
|
||||
schemaName: schemaName,
|
||||
detail: maskLogFields(script),
|
||||
};
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
if (assignSource?.functionName == 'queryReader') {
|
||||
const connection = assignSource?.props?.connection;
|
||||
if (connection) {
|
||||
return {
|
||||
category: 'export',
|
||||
component: 'RunnersController',
|
||||
event: 'export.query',
|
||||
action: 'export',
|
||||
severity: 'info',
|
||||
message: 'Exporting query',
|
||||
conid: extractConnectionId(connection),
|
||||
database: connection?.database,
|
||||
detail: maskLogFields(script),
|
||||
};
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
function logJsonRunnerScript(req, script) {
|
||||
const analysed = analyseJsonRunnerScript(script);
|
||||
|
||||
if (analysed) {
|
||||
sendToAuditLog(req, analysed);
|
||||
} else {
|
||||
sendToAuditLog(req, {
|
||||
category: 'shell',
|
||||
component: 'RunnersController',
|
||||
event: 'script.run.json',
|
||||
action: 'script',
|
||||
severity: 'info',
|
||||
detail: maskLogFields(script),
|
||||
message: 'Running JSON script',
|
||||
});
|
||||
}
|
||||
}
|
||||
async function sendToAuditLog(req, props) {}
|
||||
async function logJsonRunnerScript(req, script) {}
|
||||
|
||||
module.exports = {
|
||||
sendToAuditLog,
|
||||
|
||||
Reference in New Issue
Block a user