diff --git a/spec/PagesRouter.spec.js b/spec/PagesRouter.spec.js index fc32e61e13..db2250f15a 100644 --- a/spec/PagesRouter.spec.js +++ b/spec/PagesRouter.spec.js @@ -225,9 +225,7 @@ describe('Pages Router', () => { expect(Config.get(Parse.applicationId).pages.forceRedirect).toBe( Definitions.PagesOptions.forceRedirect.default ); - expect(Config.get(Parse.applicationId).pages.pagesPath).toBe( - Definitions.PagesOptions.pagesPath.default - ); + expect(Config.get(Parse.applicationId).pages.pagesPath).toBeUndefined(); expect(Config.get(Parse.applicationId).pages.pagesEndpoint).toBe( Definitions.PagesOptions.pagesEndpoint.default ); @@ -1236,6 +1234,36 @@ describe('Pages Router', () => { }); }); + describe('pagesPath resolution', () => { + it('should serve pages when current working directory differs from module directory', async () => { + const originalCwd = process.cwd(); + const os = require('os'); + process.chdir(os.tmpdir()); + + try { + await reconfigureServer({ + appId: 'test', + appName: 'exampleAppname', + publicServerURL: 'http://localhost:8378/1', + pages: { enableRouter: true }, + }); + + // Request the password reset page with an invalid token; + // even with an invalid token, the server should serve the + // "invalid link" page (200), not a 404. A 404 indicates the + // HTML template files could not be found because pagesPath + // resolved to the wrong directory. + const response = await request({ + url: 'http://localhost:8378/1/apps/test/request_password_reset?token=invalidToken', + }).catch(e => e); + expect(response.status).toBe(200); + expect(response.text).toContain('Invalid password reset link'); + } finally { + process.chdir(originalCwd); + } + }); + }); + describe('XSS Protection', () => { beforeEach(async () => { await reconfigureServer({ diff --git a/src/Config.js b/src/Config.js index 54e3cc5ca4..9b8d31a58b 100644 --- a/src/Config.js +++ b/src/Config.js @@ -326,9 +326,7 @@ export class Config { } else if (!isBoolean(pages.forceRedirect)) { throw 'Parse Server option pages.forceRedirect must be a boolean.'; } - if (pages.pagesPath === undefined) { - pages.pagesPath = PagesOptions.pagesPath.default; - } else if (!isString(pages.pagesPath)) { + if (pages.pagesPath !== undefined && !isString(pages.pagesPath)) { throw 'Parse Server option pages.pagesPath must be a string.'; } if (pages.pagesEndpoint === undefined) { diff --git a/src/Options/Definitions.js b/src/Options/Definitions.js index 86104e5e15..59d70a3ae8 100644 --- a/src/Options/Definitions.js +++ b/src/Options/Definitions.js @@ -772,8 +772,7 @@ module.exports.PagesOptions = { pagesPath: { env: 'PARSE_SERVER_PAGES_PAGES_PATH', help: - "The path to the pages directory; this also defines where the static endpoint '/apps' points to. Default is the './public/' directory.", - default: './public', + "The path to the pages directory; this also defines where the static endpoint '/apps' points to. Default is the './public/' directory of the parse-server module.", }, placeholders: { env: 'PARSE_SERVER_PAGES_PLACEHOLDERS', diff --git a/src/Options/docs.js b/src/Options/docs.js index 0240d14b16..1f63cdda2e 100644 --- a/src/Options/docs.js +++ b/src/Options/docs.js @@ -142,7 +142,7 @@ * @property {String} localizationFallbackLocale The fallback locale for localization if no matching translation is provided for the given locale. This is only relevant when providing translation resources via JSON file. * @property {String} localizationJsonPath The path to the JSON file for localization; the translations will be used to fill template placeholders according to the locale. * @property {String} pagesEndpoint The API endpoint for the pages. Default is 'apps'. - * @property {String} pagesPath The path to the pages directory; this also defines where the static endpoint '/apps' points to. Default is the './public/' directory. + * @property {String} pagesPath The path to the pages directory; this also defines where the static endpoint '/apps' points to. Default is the './public/' directory of the parse-server module. * @property {Object} placeholders The placeholder keys and values which will be filled in pages; this can be a simple object or a callback function. */ diff --git a/src/Options/index.js b/src/Options/index.js index e190d376da..fd2b00e3c6 100644 --- a/src/Options/index.js +++ b/src/Options/index.js @@ -437,8 +437,7 @@ export interface PagesOptions { /* Is true if responses should always be redirects and never content, false if the response type should depend on the request type (GET request -> content response; POST request -> redirect response). :DEFAULT: false */ forceRedirect: ?boolean; - /* The path to the pages directory; this also defines where the static endpoint '/apps' points to. Default is the './public/' directory. - :DEFAULT: ./public */ + /* The path to the pages directory; this also defines where the static endpoint '/apps' points to. Default is the './public/' directory of the parse-server module. */ pagesPath: ?string; /* The API endpoint for the pages. Default is 'apps'. :DEFAULT: apps */