138 lines
4.9 KiB
JavaScript
138 lines
4.9 KiB
JavaScript
const test = require('node:test');
|
|
const assert = require('node:assert/strict');
|
|
|
|
require('../src/common');
|
|
|
|
const registerAuthRoutes = require('../src/web/routes/auth');
|
|
const registerAccountRoutes = require('../src/web/routes/admin/account');
|
|
|
|
function createApp() {
|
|
const handlers = {};
|
|
return {
|
|
handlers: handlers,
|
|
get(path, ...routeHandlers) { handlers['GET ' + path] = routeHandlers; },
|
|
post(path, ...routeHandlers) { handlers['POST ' + path] = routeHandlers; }
|
|
};
|
|
}
|
|
|
|
function settingsQuery(sql) {
|
|
return String(sql).includes('SELECT id, setting_key, setting_value FROM o_app_settings');
|
|
}
|
|
|
|
test('forgot password requests a Better Auth OTP for a verified account', async () => {
|
|
let requestedEmail = '';
|
|
let renderedResetPage = null;
|
|
const app = createApp();
|
|
const pool = {
|
|
async query(sql) {
|
|
if (settingsQuery(sql)) return [[{ setting_key: 'email.smtp_enabled', setting_value: true }]];
|
|
if (String(sql).includes('SELECT id, email, email_verified FROM a_users')) {
|
|
return [[{ id: 9, email: 'person@example.test', email_verified: true }]];
|
|
}
|
|
return [[]];
|
|
}
|
|
};
|
|
registerAuthRoutes(app, {
|
|
pool: pool,
|
|
pages: {
|
|
renderResetPasswordPage(message, email) {
|
|
renderedResetPage = { message: message, email: email };
|
|
return 'reset-page';
|
|
}
|
|
},
|
|
betterAuth: {
|
|
api: {
|
|
async requestPasswordResetEmailOTP({ body }) { requestedEmail = body.email; }
|
|
}
|
|
},
|
|
parseCookies() { return {}; },
|
|
hashSessionToken(value) { return value; },
|
|
sessionCookieName: 'session'
|
|
});
|
|
|
|
const response = { send(value) { this.body = value; return this; } };
|
|
await app.handlers['POST /forgot-password'][0]({ body: { identity: 'person' } }, response, (error) => { throw error; });
|
|
|
|
assert.equal(requestedEmail, 'person@example.test');
|
|
assert.equal(response.body, 'reset-page');
|
|
assert.equal(renderedResetPage.email, '');
|
|
assert.match(renderedResetPage.message, /reset code/);
|
|
});
|
|
|
|
test('password reset verifies the OTP through Better Auth', async () => {
|
|
let resetBody = null;
|
|
const app = createApp();
|
|
const pool = { async query(sql) { return settingsQuery(sql) ? [[]] : [[]]; } };
|
|
registerAuthRoutes(app, {
|
|
pool: pool,
|
|
pages: {
|
|
renderResetPasswordPage(message, email) { return message + ':' + email; },
|
|
renderForgotPasswordPage(message) { return message; }
|
|
},
|
|
betterAuth: {
|
|
api: {
|
|
async resetPasswordEmailOTP({ body }) { resetBody = body; }
|
|
}
|
|
},
|
|
validatePasswordStrength() { return ''; },
|
|
parseCookies() { return {}; },
|
|
hashSessionToken(value) { return value; },
|
|
sessionCookieName: 'session'
|
|
});
|
|
|
|
const response = { send(value) { this.body = value; return this; } };
|
|
await app.handlers['POST /reset-password'][0]({
|
|
body: { email: 'person@example.test', otp: '123456', password: 'NewPassword!123', confirm_password: 'NewPassword!123' }
|
|
}, response, (error) => { throw error; });
|
|
|
|
assert.deepEqual(resetBody, { email: 'person@example.test', otp: '123456', password: 'NewPassword!123' });
|
|
assert.match(response.body, /Password updated/);
|
|
});
|
|
|
|
test('pending email change verifies through Better Auth and syncs the app email', async () => {
|
|
const calls = [];
|
|
const app = createApp();
|
|
const pool = {
|
|
async query(sql, params) {
|
|
calls.push([String(sql), params]);
|
|
const text = String(sql);
|
|
if (settingsQuery(text)) return [[{ setting_key: 'email.smtp_enabled', setting_value: true }]];
|
|
if (text.includes('SELECT email, email_verified, pending_email FROM a_users')) {
|
|
return [[{ email: 'old@example.test', pending_email: 'new@example.test' }]];
|
|
}
|
|
if (text.includes('SELECT id, created_at, modified_at FROM a_users')) {
|
|
return [[{ id: 7, created_at: new Date(), modified_at: new Date() }]];
|
|
}
|
|
return [{ affectedRows: 1, insertId: 1 }];
|
|
}
|
|
};
|
|
let verifiedBody = null;
|
|
registerAccountRoutes(app, {
|
|
pool: pool,
|
|
common: {},
|
|
pages: {},
|
|
betterAuth: {
|
|
api: {
|
|
async changeEmailEmailOTP({ body, headers }) {
|
|
verifiedBody = { body: body, headers: headers };
|
|
}
|
|
}
|
|
},
|
|
fromNodeHeaders(headers) { return { cookie: headers.cookie }; },
|
|
parseCookies() { return {}; },
|
|
sessionCookieName: 'session'
|
|
});
|
|
|
|
const response = { redirect(url) { this.redirectedTo = url; } };
|
|
await app.handlers['POST /account/email/verify'][0]({
|
|
body: { otp: '654321' },
|
|
headers: { cookie: 'session=token' },
|
|
currentUser: { id: 7 }
|
|
}, response, (error) => { throw error; });
|
|
|
|
assert.deepEqual(verifiedBody, { body: { newEmail: 'new@example.test', otp: '654321' }, headers: { cookie: 'session=token' } });
|
|
assert.ok(calls.some(([sql, params]) => sql.includes('UPDATE a_users SET email = ?, email_verified = 1, pending_email = NULL') && params[0] === 'new@example.test'));
|
|
assert.match(response.redirectedTo, /Email%20address%20verified/);
|
|
});
|
|
|