mirror of
https://github.com/Ride-The-Lightning/RTL.git
synced 2026-08-13 12:33:07 +02:00
63 lines
2.5 KiB
JavaScript
63 lines
2.5 KiB
JavaScript
|
|
import assert from 'node:assert/strict';
|
||
|
|
import { mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs';
|
||
|
|
import { tmpdir } from 'node:os';
|
||
|
|
import { join } from 'node:path';
|
||
|
|
import test from 'node:test';
|
||
|
|
|
||
|
|
import { getChannels } from '../../backend/controllers/eclair/channels.js';
|
||
|
|
|
||
|
|
// Eclair authenticates with HTTP basic auth, so the request options carry the node's
|
||
|
|
// lnApiPassword in the authorization header. A DEBUG log of the whole options object
|
||
|
|
// therefore writes a recoverable credential into the node log file.
|
||
|
|
const buildRequest = (logFile) => ({
|
||
|
|
session: {
|
||
|
|
selectedNode: {
|
||
|
|
index: 1,
|
||
|
|
lnNode: 'eclair-node',
|
||
|
|
lnImplementation: 'ECL',
|
||
|
|
authentication: {
|
||
|
|
options: {
|
||
|
|
url: '',
|
||
|
|
rejectUnauthorized: false,
|
||
|
|
json: true,
|
||
|
|
headers: { authorization: 'Basic ' + Buffer.from(':super-secret-password').toString('base64') }
|
||
|
|
}
|
||
|
|
},
|
||
|
|
settings: { lnServerUrl: 'http://127.0.0.1:1/', logLevel: 'DEBUG', logFile: logFile }
|
||
|
|
}
|
||
|
|
},
|
||
|
|
query: {}
|
||
|
|
});
|
||
|
|
|
||
|
|
const waitForLog = async (logFile) => {
|
||
|
|
// logger.log appends asynchronously; give it a few turns to flush.
|
||
|
|
for (let i = 0; i < 40; i++) {
|
||
|
|
const contents = readFileSync(logFile, 'utf-8');
|
||
|
|
if (contents.includes('Channels =>')) { return contents; }
|
||
|
|
await new Promise((resolve) => setTimeout(resolve, 25));
|
||
|
|
}
|
||
|
|
return readFileSync(logFile, 'utf-8');
|
||
|
|
};
|
||
|
|
|
||
|
|
test('getChannels does not write the eclair auth header to the node log at DEBUG level', async () => {
|
||
|
|
const tempDir = mkdtempSync(join(tmpdir(), 'ecl-channels-'));
|
||
|
|
const logFile = join(tempDir, 'RTL-Node-1.log');
|
||
|
|
writeFileSync(logFile, '');
|
||
|
|
const req = buildRequest(logFile);
|
||
|
|
const res = { status: () => ({ json: () => { } }) };
|
||
|
|
|
||
|
|
try {
|
||
|
|
getChannels(req, res, () => { });
|
||
|
|
const contents = await waitForLog(logFile);
|
||
|
|
|
||
|
|
assert.ok(contents.includes('Channels =>'), 'expected the controller to have logged at DEBUG level');
|
||
|
|
assert.ok(!contents.includes('authorization'), 'auth header key must not reach the node log');
|
||
|
|
assert.ok(!contents.includes('super-secret-password'), 'lnApiPassword must not reach the node log');
|
||
|
|
assert.ok(!contents.includes(Buffer.from(':super-secret-password').toString('base64')), 'encoded credential must not reach the node log');
|
||
|
|
// The diagnostic value of the log — where the call went — is still there.
|
||
|
|
assert.ok(contents.includes('/channels'), 'request url should still be logged for diagnostics');
|
||
|
|
} finally {
|
||
|
|
rmSync(tempDir, { force: true, recursive: true });
|
||
|
|
}
|
||
|
|
});
|