Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 6 additions & 4 deletions src/modules/services.ts
Original file line number Diff line number Diff line change
Expand Up @@ -212,10 +212,12 @@ const services: Services = {
parameters.portOverride = portOverride;

// Load config if exists, otherwise use empty config
const confPath = `${parameters.projectDir}/var/conf.json`;
try {
config = JSON.parse(fs.readFileSync(`${parameters.projectDir}/var/conf.json`, 'utf8'));
} catch {
config = JSON.parse(fs.readFileSync(confPath, 'utf8'));
} catch (err) {
config = {};
console.warn(`[boot] Config file not loaded from "${confPath}": ${err}. Starting with empty config.`);
}

this.getDatabase();
Expand Down Expand Up @@ -439,7 +441,7 @@ const services: Services = {
return nodemailer.createTransport({
host: config.notify?.mail?.server,
port: config.notify?.mail?.port,
secure: config.notify?.mail?.port == 465,
secure: config.notify?.mail?.port === 465,
auth: {
user: config.notify?.mail?.username,
pass: config.notify?.mail?.password
Expand All @@ -452,7 +454,7 @@ const services: Services = {
const { token } = config.notify?.telegram || {};

if (!token) {
console.log('Telegram: No api token given');
this.getLogger().info('Telegram: No api token given');
return;
}

Expand Down
28 changes: 23 additions & 5 deletions src/modules/strategy/v2/strategy_registry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,22 +49,40 @@ export class StrategyRegistry {

// ============== File Resolution ==============

/**
* Validate that a strategy name contains only safe characters.
* Rejects names with path traversal sequences or special characters.
*/
private isSafeStrategyName(name: string): boolean {
return /^[a-zA-Z0-9_-]+$/.test(name);
}

/**
* Validate that a resolved file path is within the allowed strategies directory.
* Prevents path traversal attacks.
*/
private isPathWithinStrategiesDir(filePath: string): boolean {
const strategiesDir = path.resolve(process.cwd(), 'var/strategies');
const resolved = path.resolve(filePath);
return resolved.startsWith(strategiesDir + path.sep) || resolved === strategiesDir;
}

/**
* Resolve strategy name/path to a file path
*/
private resolveFilePath(strategy: string): string | null {
// Direct file path
if (fs.existsSync(strategy)) {
return strategy;
// Reject unsafe strategy names (path traversal, special chars)
if (!this.isSafeStrategyName(strategy)) {
return null;
}
// var/strategies/{name}/{name}.ts
const varPath = path.join('var/strategies', strategy, `${strategy}.ts`);
if (fs.existsSync(varPath)) {
if (fs.existsSync(varPath) && this.isPathWithinStrategiesDir(varPath)) {
return varPath;
}
// var/strategies/{name}.ts
const flatPath = path.join('var/strategies', `${strategy}.ts`);
if (fs.existsSync(flatPath)) {
if (fs.existsSync(flatPath) && this.isPathWithinStrategiesDir(flatPath)) {
return flatPath;
}
return null;
Expand Down
7 changes: 5 additions & 2 deletions src/strategy/bot_runner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,11 @@ export class BotRunner {
const delay = nextBoundary - now + 8_000;

setTimeout(() => {
this.onTick();
setInterval(() => this.onTick(), oneMinuteMs);
this.onTick().catch(err => this.logger.error(`BotRunner: unhandled tick error: ${err}`));
setInterval(
() => this.onTick().catch(err => this.logger.error(`BotRunner: unhandled tick error: ${err}`)),
oneMinuteMs
);
}, delay);

this.logger.info(`BotRunner: first tick in ${(delay / 1000).toFixed(1)}s`);
Expand Down