Release v2.5.6
This commit is contained in:
@@ -0,0 +1,128 @@
|
||||
const test = require('node:test');
|
||||
const assert = require('node:assert/strict');
|
||||
|
||||
const registerAuthRoutes = require('../src/web/routes/auth');
|
||||
const renderLoginPage = require('../src/web/routes/auth/login');
|
||||
const { createSessionService, normalizeReturnToPath } = require('../src/web/lib/auth/session');
|
||||
|
||||
test('login page preserves the return target in a hidden field', () => {
|
||||
const html = renderLoginPage('', '/slides/6/edit');
|
||||
|
||||
assert.match(html, /name="returnTo"/);
|
||||
assert.match(html, /value="\/slides\/6\/edit"/);
|
||||
});
|
||||
|
||||
test('requireAuth preserves the original request path when redirecting to login', () => {
|
||||
const sessionService = createSessionService({
|
||||
sessionCookieName: 'pulse_session',
|
||||
sessionMaxAgeMs: 60 * 60 * 1000,
|
||||
hashSessionToken: (value) => value,
|
||||
createSessionToken: () => 'token'
|
||||
});
|
||||
|
||||
const req = {
|
||||
originalUrl: '/slides/6/edit?tab=content'
|
||||
};
|
||||
const res = {
|
||||
headers: {},
|
||||
getHeader(name) {
|
||||
return this.headers[name];
|
||||
},
|
||||
setHeader(name, value) {
|
||||
this.headers[name] = value;
|
||||
},
|
||||
redirect(url) {
|
||||
this.redirectedTo = url;
|
||||
}
|
||||
};
|
||||
|
||||
sessionService.requireAuth(req, res, () => {});
|
||||
|
||||
assert.equal(res.redirectedTo, '/login?returnTo=%2Fslides%2F6%2Fedit%3Ftab%3Dcontent');
|
||||
});
|
||||
|
||||
test('normalizeReturnToPath keeps same-origin absolute urls and strips the origin', () => {
|
||||
assert.equal(
|
||||
normalizeReturnToPath('https://signage.example.com/slides/6/edit?tab=content', 'https://signage.example.com'),
|
||||
'/slides/6/edit?tab=content'
|
||||
);
|
||||
assert.equal(
|
||||
normalizeReturnToPath('https://evil.example.com/slides/6/edit', 'https://signage.example.com'),
|
||||
''
|
||||
);
|
||||
});
|
||||
|
||||
test('successful login returns to the requested link instead of the dashboard', async () => {
|
||||
const handlers = {};
|
||||
const app = {
|
||||
get(path, ...routeHandlers) {
|
||||
handlers['GET ' + path] = routeHandlers;
|
||||
},
|
||||
post(path, ...routeHandlers) {
|
||||
handlers['POST ' + path] = routeHandlers;
|
||||
}
|
||||
};
|
||||
|
||||
registerAuthRoutes(app, {
|
||||
pool: {
|
||||
async query(sql) {
|
||||
if (sql.includes('FROM a_users WHERE username = ? LIMIT 1')) {
|
||||
return [[{ id: 7, name: 'Demo User', username: 'demo', password_hash: 'hash', password_salt: 'salt', password_iterations: 1 }]];
|
||||
}
|
||||
return [[]];
|
||||
}
|
||||
},
|
||||
pages: {
|
||||
renderLoginPage(message, returnTo) {
|
||||
return { message, returnTo };
|
||||
}
|
||||
},
|
||||
createUserSession: async () => 'session-token',
|
||||
setSessionCookie(res, token) {
|
||||
res.sessionToken = token;
|
||||
},
|
||||
clearSessionCookie() {},
|
||||
parseCookies() {
|
||||
return {};
|
||||
},
|
||||
consumeAuthMessageCookie() {
|
||||
return '';
|
||||
},
|
||||
setAuthMessageCookie() {},
|
||||
hashSessionToken(value) {
|
||||
return value;
|
||||
},
|
||||
verifyPassword() {
|
||||
return true;
|
||||
},
|
||||
sessionCookieName: 'pulse_session'
|
||||
});
|
||||
|
||||
const req = {
|
||||
body: {
|
||||
username: 'demo',
|
||||
password: 'secret',
|
||||
returnTo: '/slides/6/edit?tab=content'
|
||||
},
|
||||
query: {
|
||||
returnTo: '/slides/6/edit?tab=content'
|
||||
}
|
||||
};
|
||||
const res = {
|
||||
redirect(url) {
|
||||
this.redirectedTo = url;
|
||||
},
|
||||
status() {
|
||||
return this;
|
||||
},
|
||||
send(value) {
|
||||
this.sentValue = value;
|
||||
return this;
|
||||
}
|
||||
};
|
||||
|
||||
await handlers['POST /login'][0](req, res, () => {});
|
||||
|
||||
assert.equal(res.sessionToken, 'session-token');
|
||||
assert.equal(res.redirectedTo, '/slides/6/edit?tab=content');
|
||||
});
|
||||
Reference in New Issue
Block a user