FileUpload options for Server Config (#7071)
* New: fileUpload options to restrict file uploads * review changes * update review * Update helper.js * added complete fileUpload values for tests * fixed config validation * allow file upload only for authenicated user by default * fixed inconsistent error messages * consolidated and extended tests * minor compacting * removed irregular whitespace * added changelog entry * always allow file upload with master key * fix lint * removed fit Co-authored-by: Manuel Trezza <trezza.m@gmail.com>
This commit is contained in:
@@ -6,7 +6,10 @@ import AppCache from './cache';
|
||||
import SchemaCache from './Controllers/SchemaCache';
|
||||
import DatabaseController from './Controllers/DatabaseController';
|
||||
import net from 'net';
|
||||
import { IdempotencyOptions } from './Options/Definitions';
|
||||
import {
|
||||
IdempotencyOptions,
|
||||
FileUploadOptions,
|
||||
} from './Options/Definitions';
|
||||
|
||||
function removeTrailingSlash(str) {
|
||||
if (!str) {
|
||||
@@ -71,6 +74,7 @@ export class Config {
|
||||
allowHeaders,
|
||||
idempotencyOptions,
|
||||
emailVerifyTokenReuseIfValid,
|
||||
fileUpload,
|
||||
}) {
|
||||
if (masterKey === readOnlyMasterKey) {
|
||||
throw new Error('masterKey and readOnlyMasterKey should be different');
|
||||
@@ -88,8 +92,8 @@ export class Config {
|
||||
}
|
||||
|
||||
this.validateAccountLockoutPolicy(accountLockout);
|
||||
|
||||
this.validatePasswordPolicy(passwordPolicy);
|
||||
this.validateFileUploadOptions(fileUpload);
|
||||
|
||||
if (typeof revokeSessionOnPasswordReset !== 'boolean') {
|
||||
throw 'revokeSessionOnPasswordReset must be a boolean value';
|
||||
@@ -245,6 +249,30 @@ export class Config {
|
||||
}
|
||||
}
|
||||
|
||||
static validateFileUploadOptions(fileUpload) {
|
||||
if (!fileUpload) {
|
||||
fileUpload = {};
|
||||
}
|
||||
if (typeof fileUpload !== 'object' || fileUpload instanceof Array) {
|
||||
throw 'fileUpload must be an object value.';
|
||||
}
|
||||
if (fileUpload.enableForAnonymousUser === undefined) {
|
||||
fileUpload.enableForAnonymousUser = FileUploadOptions.enableForAnonymousUser.default;
|
||||
} else if (typeof fileUpload.enableForAnonymousUser !== 'boolean') {
|
||||
throw 'fileUpload.enableForAnonymousUser must be a boolean value.';
|
||||
}
|
||||
if (fileUpload.enableForPublic === undefined) {
|
||||
fileUpload.enableForPublic = FileUploadOptions.enableForPublic.default;
|
||||
} else if (typeof fileUpload.enableForPublic !== 'boolean') {
|
||||
throw 'fileUpload.enableForPublic must be a boolean value.';
|
||||
}
|
||||
if (fileUpload.enableForAuthenticatedUser === undefined) {
|
||||
fileUpload.enableForAuthenticatedUser = FileUploadOptions.enableForAuthenticatedUser.default;
|
||||
} else if (typeof fileUpload.enableForAuthenticatedUser !== 'boolean') {
|
||||
throw 'fileUpload.enableForAuthenticatedUser must be a boolean value.';
|
||||
}
|
||||
}
|
||||
|
||||
static validateMasterKeyIps(masterKeyIps) {
|
||||
for (const ip of masterKeyIps) {
|
||||
if (!net.isIP(ip)) {
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -32,6 +32,7 @@
|
||||
* @property {Boolean} expireInactiveSessions Sets wether we should expire the inactive sessions, defaults to true
|
||||
* @property {String} fileKey Key for your files
|
||||
* @property {Adapter<FilesAdapter>} filesAdapter Adapter module for the files sub-system
|
||||
* @property {FileUploadOptions} fileUpload Options for file uploads
|
||||
* @property {String} graphQLPath Mount path for the GraphQL endpoint, defaults to /graphql
|
||||
* @property {String} graphQLSchema Full path to your GraphQL custom schema.graphql file
|
||||
* @property {String} host The host to serve ParseServer on, defaults to 0.0.0.0
|
||||
@@ -137,3 +138,10 @@
|
||||
* @property {Function} validatorCallback a callback function to be invoked to validate the password
|
||||
* @property {String} validatorPattern a RegExp object or a regex string representing the pattern to enforce
|
||||
*/
|
||||
|
||||
/**
|
||||
* @interface FileUploadOptions
|
||||
* @property {Boolean} enableForAnonymousUser Is true if file upload should be allowed for anonymous users.
|
||||
* @property {Boolean} enableForAuthenticatedUser Is true if file upload should be allowed for authenticated users.
|
||||
* @property {Boolean} enableForPublic Is true if file upload should be allowed for anyone, regardless of user authentication.
|
||||
*/
|
||||
|
||||
@@ -198,6 +198,9 @@ export interface ParseServerOptions {
|
||||
:ENV: PARSE_SERVER_EXPERIMENTAL_IDEMPOTENCY_OPTIONS
|
||||
:DEFAULT: false */
|
||||
idempotencyOptions: ?IdempotencyOptions;
|
||||
/* Options for file uploads
|
||||
:ENV: PARSE_SERVER_FILE_UPLOAD_OPTIONS */
|
||||
fileUpload: ?FileUploadOptions;
|
||||
/* Full path to your GraphQL custom schema.graphql file */
|
||||
graphQLSchema: ?string;
|
||||
/* Mounts the GraphQL endpoint
|
||||
@@ -315,3 +318,15 @@ export interface PasswordPolicyOptions {
|
||||
/* resend token if it's still valid */
|
||||
resetTokenReuseIfValid: ?boolean;
|
||||
}
|
||||
|
||||
export interface FileUploadOptions {
|
||||
/* Is true if file upload should be allowed for anonymous users.
|
||||
:DEFAULT: false */
|
||||
enableForAnonymousUser: ?boolean;
|
||||
/* Is true if file upload should be allowed for authenticated users.
|
||||
:DEFAULT: true */
|
||||
enableForAuthenticatedUser: ?boolean;
|
||||
/* Is true if file upload should be allowed for anyone, regardless of user authentication.
|
||||
:DEFAULT: false */
|
||||
enableForPublic: ?boolean;
|
||||
}
|
||||
|
||||
@@ -94,6 +94,27 @@ export class FilesRouter {
|
||||
|
||||
async createHandler(req, res, next) {
|
||||
const config = req.config;
|
||||
const user = req.auth.user;
|
||||
const isMaster = req.auth.isMaster;
|
||||
const isLinked = user && Parse.AnonymousUtils.isLinked(user);
|
||||
if (!isMaster && !config.fileUpload.enableForAnonymousUser && isLinked) {
|
||||
next(new Parse.Error(
|
||||
Parse.Error.FILE_SAVE_ERROR,
|
||||
'File upload by anonymous user is disabled.'
|
||||
));
|
||||
return;
|
||||
}
|
||||
if (!isMaster && !config.fileUpload.enableForAuthenticatedUser && !isLinked && user) {
|
||||
next(new Parse.Error(
|
||||
Parse.Error.FILE_SAVE_ERROR,
|
||||
'File upload by authenticated user is disabled.'
|
||||
));
|
||||
return;
|
||||
}
|
||||
if (!isMaster && !config.fileUpload.enableForPublic && !user) {
|
||||
next(new Parse.Error(Parse.Error.FILE_SAVE_ERROR, 'File upload by public is disabled.'));
|
||||
return;
|
||||
}
|
||||
const filesController = config.filesController;
|
||||
const { filename } = req.params;
|
||||
const contentType = req.get('Content-type');
|
||||
|
||||
Reference in New Issue
Block a user