Wegwichtel/test/upload-detection-tools.test.js
Florian Zumpe 95026aac6e
Some checks failed
Sonarqube Scanner / Build and analyze (push) Failing after 22s
fixed sonarqube scan issues
2026-06-17 15:12:46 +02:00

107 lines
4.7 KiB
JavaScript

import assert from 'node:assert/strict';
import fs from 'node:fs/promises';
import path from 'node:path';
import { spawn, spawnSync } from 'node:child_process';
import http from 'node:http';
import test from 'node:test';
const root = path.resolve(import.meta.dirname, '..');
const read = relative => fs.readFile(path.join(root, relative), 'utf8');
test('upload MIME types are detected from content and not trusted request metadata', async () => {
const upload = await read('src/middleware/upload.js');
const media = await read('src/services/media-service.js');
const pkg = JSON.parse(await read('package.json'));
assert.equal(pkg.dependencies['file-type'], '22.0.1');
assert.equal(pkg.dependencies['@file-type/av'], '0.2.0');
assert.match(upload, /fileTypeFromFile/);
assert.match(upload, /customDetectors:\s*\[detectAv\]/);
assert.match(upload, /detectGpx/);
assert.doesNotMatch(upload, /allowed\.has\(file\.mimetype\)/);
assert.doesNotMatch(upload, /contentType ist erforderlich/);
assert.match(media, /file\.detectedExtension/);
});
test('Python API tools are syntax-valid and contain reusable 401 authentication handling', async () => {
const toolsDir = path.join(root, 'tools/python');
const names = (await fs.readdir(toolsDir)).filter(name => name.endsWith('.py'));
const expected = [
'append_route.py', 'common.py', 'create_audio.py', 'create_picture.py', 'create_poi.py',
'create_route.py', 'delete_audio.py', 'delete_picture.py', 'delete_poi.py', 'delete_route.py',
'restore_route.py', 'update_audio.py', 'update_picture.py', 'update_poi.py', 'update_route.py'
];
assert.deepEqual(
names.toSorted((left, right) => left.localeCompare(right)),
expected.toSorted((left, right) => left.localeCompare(right))
);
const compile = spawnSync('python3', ['-m', 'py_compile', ...names.map(name => path.join(toolsDir, name))], {
cwd: root,
encoding: 'utf8'
});
assert.equal(compile.status, 0, compile.stderr);
await fs.rm(path.join(toolsDir, '__pycache__'), { recursive: true, force: true });
const common = await read('tools/python/common.py');
const sonar = await read('sonar-project.properties');
const requirements = await read('requirements-dev.txt');
const pkg = JSON.parse(await read('package.json'));
assert.match(common, /class ApiClient/);
assert.match(common, /error\.code != 401/);
assert.match(common, /MAX_AUTH_ATTEMPTS/);
assert.match(common, /self\.prompt_credentials\(\)/);
assert.match(common, /getpass\.getpass/);
assert.match(common, /os\.getenv\(API_USER_ENV/);
assert.match(common, /os\.getenv\(API_PASSWORD_ENV/);
assert.match(common, /def encode_multipart/);
assert.match(common, /traceback\.print_exception/);
assert.doesNotMatch(common, /Content-Type:.*application\/octet-stream/);
assert.match(pkg.scripts['test:coverage'], /test:coverage:python/);
assert.match(pkg.scripts['test:coverage:python'], /coverage\/python\/coverage\.xml/);
assert.match(sonar, /sonar\.python\.coverage\.reportPaths=coverage\/python\/coverage\.xml/);
assert.match(requirements, /^coverage==/m);
});
test('Python client retries an intentionally simulated reverse-proxy 401 with trimmed environment credentials', async t => {
const apiUser = 'local-test-user';
const apiPassword = 'local-test-password';
const expectedAuthorization = `Basic ${Buffer.from(`${apiUser}:${apiPassword}`).toString('base64')}`;
const receivedAuthorization = [];
const server = http.createServer((req, res) => {
receivedAuthorization.push(req.headers.authorization || null);
if (req.headers.authorization !== expectedAuthorization) {
res.writeHead(401, { 'Content-Type': 'application/json', 'WWW-Authenticate': 'Basic realm="test"' });
res.end(JSON.stringify({ message: 'Zugangsdaten erforderlich.' }));
return;
}
res.writeHead(200, { 'Content-Type': 'application/json' });
res.end(JSON.stringify({ ok: true }));
});
await new Promise(resolve => server.listen(0, '127.0.0.1', resolve));
t.after(() => server.close());
const { port } = server.address();
const script = `
from common import ApiClient
result = ApiClient('http://127.0.0.1:${port}').request('GET', '/protected')
assert result == {'ok': True}
`;
const child = spawn('python3', ['-c', script], {
env: {
...process.env,
API_USER: ` ${apiUser} `,
API_PASSWORD: ` ${apiPassword} `,
PYTHONPATH: path.join(root, 'tools/python')
},
stdio: ['ignore', 'pipe', 'pipe']
});
const stderr = [];
child.stderr.on('data', chunk => stderr.push(chunk.toString()));
const status = await new Promise(resolve => child.once('exit', resolve));
assert.equal(status, 0, stderr.join(''));
assert.deepEqual(receivedAuthorization, [null, expectedAuthorization]);
});