refactor tests
This commit is contained in:
@@ -40,6 +40,14 @@ function assertHttpError(expectedStatus, expectedMessage) {
|
||||
};
|
||||
}
|
||||
|
||||
function routeDeclaration(source, method, endpoint) {
|
||||
const marker = `api.${method}('${endpoint}'`;
|
||||
const start = source.indexOf(marker);
|
||||
assert.notEqual(start, -1, `API route missing: ${method.toUpperCase()} ${endpoint}`);
|
||||
const end = source.indexOf('\n', start);
|
||||
return source.slice(start, end === -1 ? source.length : end);
|
||||
}
|
||||
|
||||
test('nicht freigegebene Strecken bleiben schreibbar', () => {
|
||||
const db = fakeDatabase({ id: 7, activatedAt: null });
|
||||
assert.deepEqual(assertRouteWritable(db, 7), { id: 7, activatedAt: null });
|
||||
@@ -110,42 +118,49 @@ test('DELETE einer freigegebenen Strecke ist nur direkt lokal zulässig', () =>
|
||||
);
|
||||
});
|
||||
|
||||
test('alle vorhandenen Schreibpfade verwenden die zentrale Freigabeprüfung', async () => {
|
||||
test('alle mutierenden API-Pfade prüfen den Freigabestatus vor Upload oder Handler', async () => {
|
||||
const api = await fs.readFile(path.join(root, 'src/routes/api.js'), 'utf8');
|
||||
|
||||
const writablePatterns = [
|
||||
/api\.put\('\/routes\/:id',\s*requireWritableRoute\('id'\),\s*upload\.single\('gpx'\)/,
|
||||
/api\.post\('\/routes\/:id\/append',\s*requireWritableRoute\('id'\),\s*upload\.single\('gpx'\)/,
|
||||
/api\.post\('\/routes\/:id\/pois',\s*requireWritableRoute\('id'\),\s*upload\.none\(\)/,
|
||||
/api\.put\('\/routes\/:routeId\/pois\/:poiId',\s*requireWritableRoute\('routeId'\),\s*upload\.none\(\)/,
|
||||
/api\.post\('\/routes\/:routeId\/pois\/:poiId\/pictures',\s*requireWritableRoute\('routeId'\),\s*upload\.single\('picture'\)/,
|
||||
/api\.put\('\/routes\/:routeId\/pois\/:poiId\/pictures\/:pictureId',\s*requireWritableRoute\('routeId'\),\s*upload\.single\('picture'\)/,
|
||||
/api\.post\('\/routes\/:routeId\/pois\/:poiId\/audio',\s*requireWritableRoute\('routeId'\),\s*upload\.single\('audio'\)/,
|
||||
/api\.put\('\/routes\/:routeId\/pois\/:poiId\/audio',\s*requireWritableRoute\('routeId'\),\s*upload\.single\('audio'\)/,
|
||||
/api\.post\('\/routes\/:id\/restore',\s*requireWritableRoute\('id'\)/
|
||||
const writableRoutes = [
|
||||
['put', '/routes/:id', 'id'],
|
||||
['post', '/routes/:id/append', 'id'],
|
||||
['post', '/routes/:id/pois', 'id'],
|
||||
['put', '/routes/:routeId/pois/:poiId', 'routeId'],
|
||||
['post', '/routes/:routeId/pois/:poiId/pictures', 'routeId'],
|
||||
['put', '/routes/:routeId/pois/:poiId/pictures/:pictureId', 'routeId'],
|
||||
['post', '/routes/:routeId/pois/:poiId/audio', 'routeId'],
|
||||
['put', '/routes/:routeId/pois/:poiId/audio', 'routeId'],
|
||||
['post', '/routes/:id/restore', 'id']
|
||||
];
|
||||
|
||||
for (const pattern of writablePatterns) assert.match(api, pattern);
|
||||
for (const [method, endpoint, parameter] of writableRoutes) {
|
||||
const declaration = routeDeclaration(api, method, endpoint);
|
||||
const guard = `requireWritableRoute('${parameter}')`;
|
||||
assert.ok(declaration.includes(guard), `${method.toUpperCase()} ${endpoint} has no release-write guard`);
|
||||
|
||||
const uploadPosition = declaration.indexOf('upload.');
|
||||
if (uploadPosition >= 0) {
|
||||
assert.ok(
|
||||
declaration.indexOf(guard) < uploadPosition,
|
||||
`${method.toUpperCase()} ${endpoint} must check writability before processing uploads`
|
||||
);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
test('Route-, POI-, Bild- und Audio-DELETE verwenden die lokale Freigabeausnahme', async () => {
|
||||
test('Route-, Streckenpunkt-, Bild- und Audio-DELETE verwenden die lokale Freigabeausnahme', async () => {
|
||||
const api = await fs.readFile(path.join(root, 'src/routes/api.js'), 'utf8');
|
||||
|
||||
const deletePatterns = [
|
||||
/api\.delete\('\/routes\/:id',\s*requireRouteDeleteAllowed\('id'\)/,
|
||||
/api\.delete\('\/routes\/:routeId\/pois\/:poiId',\s*requireRouteDeleteAllowed\('routeId'\)/,
|
||||
/api\.delete\('\/routes\/:routeId\/pois\/:poiId\/pictures\/:pictureId',\s*requireRouteDeleteAllowed\('routeId'\)/,
|
||||
/api\.delete\('\/routes\/:routeId\/pois\/:poiId\/audio',\s*requireRouteDeleteAllowed\('routeId'\)/
|
||||
const deleteRoutes = [
|
||||
['delete', '/routes/:id', 'id'],
|
||||
['delete', '/routes/:routeId/pois/:poiId', 'routeId'],
|
||||
['delete', '/routes/:routeId/pois/:poiId/pictures/:pictureId', 'routeId'],
|
||||
['delete', '/routes/:routeId/pois/:poiId/audio', 'routeId']
|
||||
];
|
||||
|
||||
for (const pattern of deletePatterns) assert.match(api, pattern);
|
||||
});
|
||||
|
||||
|
||||
test('nginx kennzeichnet weitergeleitete Internet-Aufrufe für die Local-DELETE-Prüfung', async () => {
|
||||
const nginx = await fs.readFile(path.join(root, 'nginx/wegwichtel.conf'), 'utf8');
|
||||
|
||||
assert.match(nginx, /proxy_pass\s+http:\/\/127\.0\.0\.1:47145;/);
|
||||
assert.match(nginx, /proxy_set_header\s+X-Real-IP\s+\$remote_addr;/);
|
||||
assert.match(nginx, /proxy_set_header\s+X-Forwarded-For\s+\$proxy_add_x_forwarded_for;/);
|
||||
for (const [method, endpoint, parameter] of deleteRoutes) {
|
||||
const declaration = routeDeclaration(api, method, endpoint);
|
||||
assert.ok(
|
||||
declaration.includes(`requireRouteDeleteAllowed('${parameter}')`),
|
||||
`${method.toUpperCase()} ${endpoint} has no local-delete guard`
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user