fix: Default HTML pages for password reset, email verification not found (#10034)

This commit is contained in:
Manuel
2026-02-06 01:42:54 +00:00
committed by GitHub
parent 8cc71cf9e4
commit e29910764d
3 changed files with 67 additions and 10 deletions

View File

@@ -10,7 +10,7 @@
"files": [ "files": [
"bin/", "bin/",
"lib/", "lib/",
"public_html/", "public/",
"views/", "views/",
"LICENSE", "LICENSE",
"NOTICE", "NOTICE",

View File

@@ -1181,6 +1181,61 @@ describe('Pages Router', () => {
}); });
}); });
describe('async publicServerURL', () => {
it('resolves async publicServerURL for password reset page', async () => {
const emailAdapter = {
sendVerificationEmail: () => Promise.resolve(),
sendPasswordResetEmail: () => Promise.resolve(),
sendMail: () => {},
};
await reconfigureServer({
appId: 'test',
appName: 'exampleAppname',
verifyUserEmails: true,
emailAdapter,
publicServerURL: () => 'http://localhost:8378/1',
pages: { enableRouter: true },
});
const user = new Parse.User();
user.setUsername('asyncUrlUser');
user.setPassword('examplePassword');
user.set('email', 'async-url@example.com');
await user.signUp();
await Parse.User.requestPasswordReset('async-url@example.com');
const response = await request({
url: 'http://localhost:8378/1/apps/test/request_password_reset?token=invalidToken',
followRedirects: false,
}).catch(e => e);
expect(response.status).toBe(200);
expect(response.text).toContain('Invalid password reset link!');
});
it('resolves async publicServerURL for email verification page', async () => {
const emailAdapter = {
sendVerificationEmail: () => Promise.resolve(),
sendPasswordResetEmail: () => Promise.resolve(),
sendMail: () => {},
};
await reconfigureServer({
appId: 'test',
appName: 'exampleAppname',
verifyUserEmails: true,
emailAdapter,
publicServerURL: () => 'http://localhost:8378/1',
pages: { enableRouter: true },
});
const response = await request({
url: 'http://localhost:8378/1/apps/test/verify_email?token=invalidToken',
followRedirects: false,
}).catch(e => e);
expect(response.status).toBe(200);
expect(response.text).toContain('Invalid verification link!');
});
});
describe('XSS Protection', () => { describe('XSS Protection', () => {
beforeEach(async () => { beforeEach(async () => {
await reconfigureServer({ await reconfigureServer({

View File

@@ -624,12 +624,14 @@ export class PagesRouter extends PromiseRouter {
* @param {Boolean} failGracefully Is true if failing to set the config should * @param {Boolean} failGracefully Is true if failing to set the config should
* not result in an invalid request response. Default is `false`. * not result in an invalid request response. Default is `false`.
*/ */
setConfig(req, failGracefully = false) { async setConfig(req, failGracefully = false) {
req.config = Config.get(req.params.appId || req.query.appId); req.config = Config.get(req.params.appId || req.query.appId);
if (!req.config && !failGracefully) { if (!req.config && !failGracefully) {
this.invalidRequest(); this.invalidRequest();
} }
return Promise.resolve(); if (req.config) {
await req.config.loadKeys();
}
} }
mountPagesRoutes() { mountPagesRoutes() {
@@ -637,7 +639,7 @@ export class PagesRouter extends PromiseRouter {
'GET', 'GET',
`/${this.pagesEndpoint}/:appId/verify_email`, `/${this.pagesEndpoint}/:appId/verify_email`,
req => { req => {
this.setConfig(req); return this.setConfig(req);
}, },
req => { req => {
return this.verifyEmail(req); return this.verifyEmail(req);
@@ -648,7 +650,7 @@ export class PagesRouter extends PromiseRouter {
'POST', 'POST',
`/${this.pagesEndpoint}/:appId/resend_verification_email`, `/${this.pagesEndpoint}/:appId/resend_verification_email`,
req => { req => {
this.setConfig(req); return this.setConfig(req);
}, },
req => { req => {
return this.resendVerificationEmail(req); return this.resendVerificationEmail(req);
@@ -659,7 +661,7 @@ export class PagesRouter extends PromiseRouter {
'GET', 'GET',
`/${this.pagesEndpoint}/choose_password`, `/${this.pagesEndpoint}/choose_password`,
req => { req => {
this.setConfig(req); return this.setConfig(req);
}, },
req => { req => {
return this.passwordReset(req); return this.passwordReset(req);
@@ -670,7 +672,7 @@ export class PagesRouter extends PromiseRouter {
'POST', 'POST',
`/${this.pagesEndpoint}/:appId/request_password_reset`, `/${this.pagesEndpoint}/:appId/request_password_reset`,
req => { req => {
this.setConfig(req); return this.setConfig(req);
}, },
req => { req => {
return this.resetPassword(req); return this.resetPassword(req);
@@ -681,7 +683,7 @@ export class PagesRouter extends PromiseRouter {
'GET', 'GET',
`/${this.pagesEndpoint}/:appId/request_password_reset`, `/${this.pagesEndpoint}/:appId/request_password_reset`,
req => { req => {
this.setConfig(req); return this.setConfig(req);
}, },
req => { req => {
return this.requestResetPassword(req); return this.requestResetPassword(req);
@@ -695,7 +697,7 @@ export class PagesRouter extends PromiseRouter {
route.method, route.method,
`/${this.pagesEndpoint}/:appId/${route.path}`, `/${this.pagesEndpoint}/:appId/${route.path}`,
req => { req => {
this.setConfig(req); return this.setConfig(req);
}, },
async req => { async req => {
const { file, query = {} } = (await route.handler(req)) || {}; const { file, query = {} } = (await route.handler(req)) || {};
@@ -718,7 +720,7 @@ export class PagesRouter extends PromiseRouter {
'GET', 'GET',
`/${this.pagesEndpoint}/*resource`, `/${this.pagesEndpoint}/*resource`,
req => { req => {
this.setConfig(req, true); return this.setConfig(req, true);
}, },
req => { req => {
return this.staticRoute(req); return this.staticRoute(req);