Skip to content

feat: add allowHeaders to Options #6044

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Sep 12, 2019
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 20 additions & 3 deletions src/Config.js
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ export class Config {
masterKeyIps,
masterKey,
readOnlyMasterKey,
allowHeaders,
}) {
if (masterKey === readOnlyMasterKey) {
throw new Error('masterKey and readOnlyMasterKey should be different');
Expand Down Expand Up @@ -110,6 +111,8 @@ export class Config {
this.validateMasterKeyIps(masterKeyIps);

this.validateMaxLimit(maxLimit);

this.validateAllowHeaders(allowHeaders);
}

static validateAccountLockoutPolicy(accountLockout) {
Expand Down Expand Up @@ -254,6 +257,22 @@ export class Config {
}
}

static validateAllowHeaders(allowHeaders) {
if (![null, undefined].includes(allowHeaders)) {
if (Array.isArray(allowHeaders)) {
allowHeaders.forEach(header => {
if (typeof header !== 'string') {
throw 'Allow headers must only contain strings';
} else if (!header.trim().length) {
throw 'Allow headers must not contain empty strings';
}
});
} else {
throw 'Allow headers must be an array';
}
}
}

generateEmailVerifyTokenExpiresAt() {
if (!this.verifyUserEmails || !this.emailVerifyTokenValidityDuration) {
return undefined;
Expand Down Expand Up @@ -328,9 +347,7 @@ export class Config {
}

get requestResetPasswordURL() {
return `${this.publicServerURL}/apps/${
this.applicationId
}/request_password_reset`;
return `${this.publicServerURL}/apps/${this.applicationId}/request_password_reset`;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure what happened here - maybe the pre-commit ran a formatter through it!

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah it’s prettier

}

get passwordResetSuccessURL() {
Expand Down
2 changes: 2 additions & 0 deletions src/Options/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ export interface ParseServerOptions {
masterKeyIps: ?(string[]);
/* Sets the app name */
appName: ?string;
/* Add headers to Access-Control-Allow-Headers */
allowHeaders: ?(string[]);
/* Adapter module for the analytics */
analyticsAdapter: ?Adapter<AnalyticsAdapter>;
/* Adapter module for the files sub-system */
Expand Down
23 changes: 16 additions & 7 deletions src/middlewares.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,20 @@ import Config from './Config';
import ClientSDK from './ClientSDK';
import defaultLogger from './logger';

const getMountForRequest = function(req) {
const mountPathLength = req.originalUrl.length - req.url.length;
const mountPath = req.originalUrl.slice(0, mountPathLength);
return req.protocol + '://' + req.get('host') + mountPath;
};

// Checks that the request is authorized for this app and checks user
// auth too.
// The bodyparser should run before this middleware.
// Adds info to the request:
// req.config - the Config for this app
// req.auth - the Auth for this request
export function handleParseHeaders(req, res, next) {
var mountPathLength = req.originalUrl.length - req.url.length;
var mountPath = req.originalUrl.slice(0, mountPathLength);
var mount = req.protocol + '://' + req.get('host') + mountPath;
var mount = getMountForRequest(req);

var info = {
appId: req.get('X-Parse-Application-Id'),
Expand Down Expand Up @@ -280,12 +284,17 @@ function decodeBase64(str) {
}

export function allowCrossDomain(req, res, next) {
const config = Config.get(
req.get('X-Parse-Application-Id', getMountForRequest(req))
Copy link
Contributor Author

@omairvaiyani omairvaiyani Sep 12, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm making an assumption here that Config.get will gracefully handle empty parameters and return an undefined config. If not, I'll need to add some checks to ensure we have an appId and mount before looking for the config.

);
let allowHeaders =
'X-Parse-Master-Key, X-Parse-REST-API-Key, X-Parse-Javascript-Key, X-Parse-Application-Id, X-Parse-Client-Version, X-Parse-Session-Token, X-Requested-With, X-Parse-Revocable-Session, Content-Type, Pragma, Cache-Control';
if (config && config.allowHeaders) {
allowHeaders += `, ${config.allowHeaders.join(', ')}`;
}
res.header('Access-Control-Allow-Origin', '*');
res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE,OPTIONS');
res.header(
'Access-Control-Allow-Headers',
'X-Parse-Master-Key, X-Parse-REST-API-Key, X-Parse-Javascript-Key, X-Parse-Application-Id, X-Parse-Client-Version, X-Parse-Session-Token, X-Requested-With, X-Parse-Revocable-Session, Content-Type, Pragma, Cache-Control'
);
res.header('Access-Control-Allow-Headers', allowHeaders);
res.header(
'Access-Control-Expose-Headers',
'X-Parse-Job-Status-Id, X-Parse-Push-Status-Id'
Expand Down