Files
BetterDesk/web-nodejs/tests/requireJsonContentType.test.js
T
UNITRONIX bc358e0a2d fix(backup): allow multipart restore and mesh cert path (#473)
Exempt POST /api/settings/restore from JSON Content-Type middleware so FormData uploads reach multer. Use resolvePathUnderRoot for special/mesh_agent_server.pem in pre-update backup create/restore.

Refs #473

Thanks: INSOLVE (Honorary); Marco Jakobs (@jacotec); MyNameisStitch (@MyNameisStitch); Redspin (@playerumpknow); muopc (@muopc)
2026-10-25 09:18:04 +01:00

81 lines
2.8 KiB
JavaScript

'use strict';
const request = require('supertest');
const { createTestApp } = require('./helpers');
/**
* Mirrors routes/index.js requireJsonContentType — keep in sync when exemptions change.
*/
function requireJsonContentType(req, res, next) {
if (['GET', 'DELETE', 'OPTIONS', 'HEAD'].includes(req.method)) {
return next();
}
if (!req.path.startsWith('/api/')) {
return next();
}
if (req.path.includes('/upload') || req.path.includes('/import')) {
return next();
}
// Disaster-recovery restore uploads multipart/form-data (field "backup").
// Do not exempt /api/settings/updates/restore — that endpoint is JSON-only.
if (req.path === '/api/settings/restore') {
return next();
}
if (!req.is('application/json')) {
return res.status(415).json({
success: false,
error: 'Content-Type must be application/json',
});
}
next();
}
describe('requireJsonContentType (#473)', () => {
let app;
beforeEach(() => {
app = createTestApp();
app.use(requireJsonContentType);
app.post('/api/settings/restore', (req, res) => {
res.json({ success: true, reached: 'restore' });
});
app.post('/api/settings/updates/restore', (req, res) => {
res.json({ success: true, reached: 'updates-restore' });
});
app.post('/api/settings/email/smtp/test', (req, res) => {
res.json({ success: true, reached: 'smtp' });
});
});
it('allows multipart POST to /api/settings/restore', async () => {
const res = await request(app)
.post('/api/settings/restore')
.attach('backup', Buffer.from('{"_format":"betterdesk-backup"}'), 'backup.json');
expect(res.status).toBe(200);
expect(res.body.reached).toBe('restore');
});
it('still requires JSON for /api/settings/updates/restore', async () => {
const res = await request(app)
.post('/api/settings/updates/restore')
.attach('backup', Buffer.from('x'), 'backup.json');
expect(res.status).toBe(415);
expect(res.body.error).toBe('Content-Type must be application/json');
});
it('still requires JSON for unrelated API POST', async () => {
const res = await request(app).post('/api/settings/email/smtp/test');
expect(res.status).toBe(415);
expect(res.body.error).toBe('Content-Type must be application/json');
});
it('allows JSON POST to /api/settings/updates/restore', async () => {
const res = await request(app)
.post('/api/settings/updates/restore')
.set('Content-Type', 'application/json')
.send({ backupName: 'pre-update-test' });
expect(res.status).toBe(200);
expect(res.body.reached).toBe('updates-restore');
});
});