Files
pulse-signage/test/web-middleware.test.js
lzstealth 9c28eca3ef
Publish Docker Image / build-and-push-existing-registry (./build/Dockerfile, web, pulse-signage-web) (push) Successful in 1m47s
Publish Docker Image / build-and-push-existing-registry (./build/Dockerfile.player, player, pulse-signage-player) (push) Successful in 32s
Release v2.17.0: add read-only user previews and access fallbacks
2026-10-23 01:55:33 +01:00

177 lines
6.1 KiB
JavaScript

const test = require('node:test');
const assert = require('node:assert/strict');
const path = require('path');
const registerMiddleware = require('../src/web/middleware');
test('web middleware bypasses auth for internal player sync routes', () => {
const calls = [];
const app = {
middlewares: [],
use(...args) {
this.middlewares.push(args);
}
};
registerMiddleware(app, {
pool: {},
loadCurrentUser: async () => null,
requireAuth(req, _res, next) {
calls.push(req.path);
next();
},
MEDIA_DIR: path.join(process.cwd(), 'media'),
UPLOADS_DIR: path.join(process.cwd(), 'media', 'uploads-test'),
THUMBNAILS_DIR: path.join(process.cwd(), 'media', 'thumbnails-test'),
ASSET_DIR: path.join(process.cwd(), 'src', 'web', 'public')
});
const authGate = app.middlewares[app.middlewares.length - 1][0];
const nextCalls = [];
authGate({ path: '/api/internal/sync/player-media' }, {}, function () {
nextCalls.push('media');
});
authGate({ path: '/api/internal/sync/player-font' }, {}, function () {
nextCalls.push('font');
});
authGate({ path: '/dashboard' }, {}, function () {
nextCalls.push('dashboard');
});
assert.deepEqual(nextCalls, ['media', 'font', 'dashboard']);
assert.deepEqual(calls, ['/dashboard']);
});
test('view-as blocks writes but allows the stop-preview request', () => {
const app = {
middlewares: [],
use(...args) {
this.middlewares.push(args);
}
};
registerMiddleware(app, {
pool: {},
loadCurrentUser: async () => null,
requireAuth(req, _res, next) { next(); },
MEDIA_DIR: path.join(process.cwd(), 'media'),
UPLOADS_DIR: path.join(process.cwd(), 'media', 'uploads-test'),
THUMBNAILS_DIR: path.join(process.cwd(), 'media', 'thumbnails-test'),
ASSET_DIR: path.join(process.cwd(), 'src', 'web', 'public')
});
const authGate = app.middlewares[app.middlewares.length - 1][0];
const errors = [];
let stopAllowed = false;
['/slides/12', '/api/internal/sync/player-control'].forEach(function (requestPath) {
authGate({
method: 'POST',
path: requestPath,
currentUser: { id: 19, isViewingAs: true },
authenticatedUser: { id: 7 }
}, {}, function (error) {
errors.push(error);
});
});
authGate({
method: 'POST',
path: '/settings/view-as/stop',
currentUser: { id: 19, isViewingAs: true },
authenticatedUser: { id: 7 }
}, {}, function (error) {
stopAllowed = !error;
});
assert.equal(errors.length, 2);
assert.equal(errors[0].statusCode, 403);
assert.equal(stopAllowed, true);
});
test('view-as ignores the preview user password-change requirement and permits exit', () => {
const app = {
middlewares: [],
use(...args) { this.middlewares.push(args); }
};
registerMiddleware(app, {
pool: {},
loadCurrentUser: async () => null,
requireAuth(_req, _res, next) { next(); },
MEDIA_DIR: path.join(process.cwd(), 'media'),
UPLOADS_DIR: path.join(process.cwd(), 'media', 'uploads-test'),
THUMBNAILS_DIR: path.join(process.cwd(), 'media', 'thumbnails-test'),
ASSET_DIR: path.join(process.cwd(), 'src', 'web', 'public')
});
const authGate = app.middlewares[app.middlewares.length - 1][0];
let pageAllowed = false;
const response = { redirect(path) { this.redirectedTo = path; } };
authGate({
method: 'GET',
path: '/screens',
currentUser: { id: 19, isViewingAs: true, mustChangePassword: true },
authenticatedUser: { id: 7 }
}, response, function (error) { assert.ifError(error); pageAllowed = true; });
assert.equal(pageAllowed, true);
assert.equal(response.redirectedTo, undefined);
const adminMustChangeResponse = { redirect(path) { this.redirectedTo = path; } };
authGate({
method: 'GET',
path: '/screens',
currentUser: { id: 19, isViewingAs: true, mustChangePassword: false },
authenticatedUser: { id: 7, mustChangePassword: true }
}, adminMustChangeResponse, function (error) { assert.ifError(error); });
assert.equal(adminMustChangeResponse.redirectedTo, '/account/password');
let stopAllowed = false;
authGate({
method: 'POST',
path: '/settings/view-as/stop',
currentUser: { id: 19, isViewingAs: true, mustChangePassword: true },
authenticatedUser: { id: 7, mustChangePassword: true }
}, {}, function (error) { assert.ifError(error); stopAllowed = true; });
assert.equal(stopAllowed, true);
});
test('required-password gate blocks account details and allows only password page and logout', () => {
const app = {
middlewares: [],
use(...args) { this.middlewares.push(args); }
};
registerMiddleware(app, {
pool: {},
loadCurrentUser: async () => null,
requireAuth(_req, _res, next) { next(); },
MEDIA_DIR: path.join(process.cwd(), 'media'),
UPLOADS_DIR: path.join(process.cwd(), 'media', 'uploads-test'),
THUMBNAILS_DIR: path.join(process.cwd(), 'media', 'thumbnails-test'),
ASSET_DIR: path.join(process.cwd(), 'src', 'web', 'public')
});
const authGate = app.middlewares[app.middlewares.length - 1][0];
const requests = [
{ method: 'GET', path: '/account' },
{ method: 'POST', path: '/account/profile' },
{ method: 'GET', path: '/screens' }
];
requests.forEach(function (req) {
const response = { redirect(path) { this.redirectedTo = path; } };
Object.assign(req, { currentUser: { id: 5, mustChangePassword: true }, authenticatedUser: { id: 5, mustChangePassword: true } });
authGate(req, response, function (error) { assert.ifError(error); });
assert.equal(response.redirectedTo, '/account/password');
});
const passwordPageResponse = {};
authGate({
method: 'GET',
path: '/account/password',
currentUser: { id: 5, mustChangePassword: true },
authenticatedUser: { id: 5, mustChangePassword: true }
}, passwordPageResponse, function (error) { assert.ifError(error); });
const logoutResponse = {};
authGate({
method: 'GET',
path: '/logout',
currentUser: { id: 5, mustChangePassword: true },
authenticatedUser: { id: 5, mustChangePassword: true }
}, logoutResponse, function (error) { assert.ifError(error); });
});