Skip to content

Commit

Permalink
feat(core): added monitor folder content checksum reporting
Browse files Browse the repository at this point in the history
  • Loading branch information
tabarra committed Oct 18, 2024
1 parent 61aacd6 commit 8cbc767
Show file tree
Hide file tree
Showing 6 changed files with 120 additions and 3 deletions.
108 changes: 108 additions & 0 deletions core/checksumMonitorFolder.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
//FIXME: after refactor, move to the correct path
import bytes from 'bytes';
import fs from 'node:fs/promises';
import path from 'node:path';
import { createHash } from 'node:crypto';
import { txEnv } from './globalData';

//Hash test
const hashFile = async (filePath: string) => {
const rawFile = await fs.readFile(filePath, 'utf8')
const normalized = rawFile.normalize('NFKC')
.replace(/\r\n/g, '\n')
.replace(/^\uFEFF/, '');
return createHash('sha1').update(normalized).digest('hex');
}

// Limits
const MAX_FILES = 300;
const MAX_TOTAL_SIZE = bytes('50MB');
const MAX_FILE_SIZE = bytes('20MB');
const MAX_DEPTH = 10;
const MAX_EXECUTION_TIME = 30 * 1000;
const IGNORED_FOLDERS = [
'db',
'cache',
'dist',
'.reports',
'license_report',
'tmp_core_tsc',
'node_modules',
'txData',
];


type ContentFileType = {
path: string;
size: number;
hash: string;
}

export default async function checksumMonitorFolder() {
const rootPath = txEnv.txAdminResourcePath;
const allFiles: ContentFileType[] = [];
let totalFiles = 0;
let totalSize = 0;

try {
const tsStart = Date.now();
const scanDir = async (dir: string, depth: number = 0) => {
if (depth > MAX_DEPTH) {
throw new Error('MAX_DEPTH');
}

let filesFound = 0;
const entries = await fs.readdir(dir, { withFileTypes: true });
for (const entry of entries) {
if (totalFiles >= MAX_FILES) {
throw new Error('MAX_FILES');
} else if (totalSize >= MAX_TOTAL_SIZE) {
throw new Error('MAX_TOTAL_SIZE');
} else if (Date.now() - tsStart > MAX_EXECUTION_TIME) {
throw new Error('MAX_EXECUTION_TIME');
}

const entryPath = path.join(dir, entry.name);
let relativeEntryPath = path.relative(rootPath, entryPath);
relativeEntryPath = './' + relativeEntryPath.split(path.sep).join(path.posix.sep);

if (entry.isDirectory()) {
if (IGNORED_FOLDERS.includes(entry.name)) {
continue;
}
await scanDir(entryPath, depth + 1);
} else if (entry.isFile()) {
const stats = await fs.stat(entryPath);
if (stats.size > MAX_FILE_SIZE) {
throw new Error('MAX_SIZE');
}

allFiles.push({
path: relativeEntryPath,
size: stats.size,
hash: await hashFile(entryPath),
});
filesFound++;
totalFiles++;
totalSize += stats.size;
}
}
return filesFound;
};
await scanDir(rootPath);
allFiles.sort((a, b) => a.path.localeCompare(b.path));
return {
totalFiles,
totalSize,
allFiles,
};
} catch (error) {
//At least saving the progress
return {
error: (error as any).message,
totalFiles,
totalSize,
allFiles,
};
}
}
2 changes: 1 addition & 1 deletion core/updateChangelog.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
//FIXME: after efactor, move to the correct path (maybe drop the 'update' prefix?)
//FIXME: after refactor, move to the correct path (maybe drop the 'update' prefix?)
const modulename = 'UpdateChecker';
import semver, { ReleaseType } from 'semver';
import { z } from "zod";
Expand Down
1 change: 1 addition & 0 deletions core/updateRollout.test.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
//FIXME: after refactor, move to the correct path
import { it, expect, suite } from 'vitest';
import { getUpdateRolloutDelay } from './updateRollout';

Expand Down
2 changes: 1 addition & 1 deletion core/updateRollout.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
//FIXME: after efactor, move to the correct path
//FIXME: after refactor, move to the correct path
import type { ReleaseType } from 'semver';

type RolloutStrategyType = {
Expand Down
8 changes: 8 additions & 0 deletions core/webroutes/diagnostics/sendReport.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { getServerDataConfigs, getServerDataContent, ServerDataContentType, Serv
import MemCache from '@extras/MemCache';
import consoleFactory, { getLogBuffer } from '@extras/console';
import { AuthedCtx } from '@core/components/WebServer/ctxTypes';
import checksumMonitorFolder from '@core/checksumMonitorFolder';
const console = consoleFactory(modulename);

//Consts & Helpers
Expand Down Expand Up @@ -111,6 +112,12 @@ export default async function SendDiagnosticsReport(ctx: AuthedCtx) {
perfSvMain = ctx.txAdmin.statsManager.svRuntime.getServerPerfSummary();
} catch (error) { }

//Monitor integrity check
let monitorContent = undefined;
try {
monitorContent = await checksumMonitorFolder();
} catch (error) { }

//Prepare report object
const reportData = {
$schemaVersion: 2,
Expand All @@ -128,6 +135,7 @@ export default async function SendDiagnosticsReport(ctx: AuthedCtx) {
adminList,
serverDataContent,
cfgFiles,
monitorContent,
};

// //Preparing request
Expand Down
2 changes: 1 addition & 1 deletion web/main/diagnostics.ejs
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,7 @@
<li>Player database statistics</li>
<li>txAdmin settings (no bot token)</li>
<li>List of admins (no passwords/hashes)</li>
<li>List of files/folders in server data folder</li>
<li>List of files/folders in server data and monitor folders</li>
<li>Config files in server data folder</li>
</ul>
</li>
Expand Down

0 comments on commit 8cbc767

Please sign in to comment.