From c469f6291e44ab87e5a3682f4778a118751a005b Mon Sep 17 00:00:00 2001 From: Manuel Trezza Date: Thu, 23 Apr 2020 01:27:53 +0200 Subject: [PATCH 01/19] enabled direct access by default --- src/Options/index.js | 4 ---- src/ParseServer.js | 14 +++++--------- 2 files changed, 5 insertions(+), 13 deletions(-) diff --git a/src/Options/index.js b/src/Options/index.js index 3aa5b7fc6b..859b3975a1 100644 --- a/src/Options/index.js +++ b/src/Options/index.js @@ -155,10 +155,6 @@ export interface ParseServerOptions { /* Sets the maximum size for the in memory cache, defaults to 10000 :DEFAULT: 10000 */ cacheMaxSize: ?number; - /* Replace HTTP Interface when using JS SDK in current node runtime, defaults to false. Caution, this is an experimental feature that may not be appropriate for production. - :ENV: PARSE_SERVER_ENABLE_EXPERIMENTAL_DIRECT_ACCESS - :DEFAULT: false */ - directAccess: ?boolean; /* Use a single schema cache shared across requests. Reduces number of queries made to _SCHEMA, defaults to false, i.e. unique schema cache per request. :DEFAULT: false */ enableSingleSchemaCache: ?boolean; diff --git a/src/ParseServer.js b/src/ParseServer.js index 1fd279b4c7..ad6f3d77be 100644 --- a/src/ParseServer.js +++ b/src/ParseServer.js @@ -140,7 +140,7 @@ class ParseServer { * @static * Create an express app for the parse server * @param {Object} options let you specify the maxUploadSize when creating the express app */ - static app({ maxUploadSize = '20mb', appId, directAccess }) { + static app({ maxUploadSize = '20mb', appId }) { // This app serves the Parse API directly. // It's the equivalent of https://api.parse.com/1 in the hosted Parse API. var api = express(); @@ -196,14 +196,10 @@ class ParseServer { ParseServer.verifyServerUrl(); }); } - if ( - process.env.PARSE_SERVER_ENABLE_EXPERIMENTAL_DIRECT_ACCESS === '1' || - directAccess - ) { - Parse.CoreManager.setRESTController( - ParseServerRESTController(appId, appRouter) - ); - } + // Set direct access REST controller + Parse.CoreManager.setRESTController( + ParseServerRESTController(appId, appRouter) + ); return api; } From a4b886252bceb3f66c0f0da497702dbe0daf70e8 Mon Sep 17 00:00:00 2001 From: Manuel Trezza Date: Thu, 23 Apr 2020 01:28:21 +0200 Subject: [PATCH 02/19] removed obsolete direct access option test case --- spec/index.spec.js | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/spec/index.spec.js b/spec/index.spec.js index 8d02e37213..cf2fce5439 100644 --- a/spec/index.spec.js +++ b/spec/index.spec.js @@ -508,16 +508,6 @@ describe('server', () => { .catch(done.fail); }); - it('should allow direct access', async () => { - const RESTController = Parse.CoreManager.getRESTController(); - const spy = spyOn(Parse.CoreManager, 'setRESTController').and.callThrough(); - await reconfigureServer({ - directAccess: true, - }); - expect(spy).toHaveBeenCalledTimes(1); - Parse.CoreManager.setRESTController(RESTController); - }); - it('should load a middleware from string', done => { reconfigureServer({ middleware: 'spec/support/CustomMiddleware', From e8cbbcfbb72c8e7c860f8ebdc71642cf393e50f4 Mon Sep 17 00:00:00 2001 From: Diamond Lewis Date: Fri, 8 Jan 2021 13:19:37 -0600 Subject: [PATCH 03/19] quick fix test --- src/ParseServerRESTController.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ParseServerRESTController.js b/src/ParseServerRESTController.js index c678f99ea3..091b303e51 100644 --- a/src/ParseServerRESTController.js +++ b/src/ParseServerRESTController.js @@ -12,7 +12,7 @@ function getSessionToken(options) { } function getAuth(options = {}, config) { - const installationId = options.installationId || 'cloud'; + const installationId = options.installationId || (process.env.TESTING ? 'directAccess' : 'cloud'); if (options.useMasterKey) { return Promise.resolve(new Auth.Auth({ config, isMaster: true, installationId })); } From 6a6ee89513b9a9ad78a0a932fc78fca4effd84da Mon Sep 17 00:00:00 2001 From: Diamond Lewis Date: Fri, 8 Jan 2021 17:12:21 -0600 Subject: [PATCH 04/19] Set RESTController during tests --- spec/helper.js | 4 ++++ src/ParseServer.js | 3 ++- src/ParseServerRESTController.js | 5 +++-- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/spec/helper.js b/spec/helper.js index 5c598277f5..728575f3f6 100644 --- a/spec/helper.js +++ b/spec/helper.js @@ -30,6 +30,7 @@ const PostgresStorageAdapter = require('../lib/Adapters/Storage/Postgres/Postgre .default; const MongoStorageAdapter = require('../lib/Adapters/Storage/Mongo/MongoStorageAdapter').default; const RedisCacheAdapter = require('../lib/Adapters/Cache/RedisCacheAdapter').default; +const RESTController = require('parse/lib/node/RESTController'); const mongoURI = 'mongodb://localhost:27017/parseServerMongoAdapterTestDatabase'; const postgresURI = 'postgres://localhost:5432/parse_server_postgres_adapter_test_database'; @@ -164,6 +165,7 @@ const reconfigureServer = changedConfiguration => { // Set up a Parse client to talk to our test API server const Parse = require('parse/node'); Parse.serverURL = 'http://localhost:' + port + '/1'; +Parse.CoreManager.setRESTController(RESTController); beforeEach(done => { try { @@ -187,6 +189,8 @@ beforeEach(done => { .then(() => { Parse.initialize('test', 'test', 'test'); Parse.serverURL = 'http://localhost:' + port + '/1'; + Parse.CoreManager.setRESTController(RESTController); + done(); }) .catch(done.fail); diff --git a/src/ParseServer.js b/src/ParseServer.js index 8a01143afb..7396342666 100644 --- a/src/ParseServer.js +++ b/src/ParseServer.js @@ -185,8 +185,9 @@ class ParseServer { }); } - // Set direct access REST controller + // Bypass HTTP calls made by SDK during node runtime Parse.CoreManager.setRESTController(ParseServerRESTController(appId, appRouter)); + return api; } diff --git a/src/ParseServerRESTController.js b/src/ParseServerRESTController.js index 091b303e51..f86fc6d7f9 100644 --- a/src/ParseServerRESTController.js +++ b/src/ParseServerRESTController.js @@ -12,7 +12,7 @@ function getSessionToken(options) { } function getAuth(options = {}, config) { - const installationId = options.installationId || (process.env.TESTING ? 'directAccess' : 'cloud'); + const installationId = options.installationId || 'cloud'; if (options.useMasterKey) { return Promise.resolve(new Auth.Auth({ config, isMaster: true, installationId })); } @@ -103,7 +103,7 @@ function ParseServerRESTController(applicationId, router) { applicationId: applicationId, sessionToken: options.sessionToken, installationId: options.installationId, - context: options.context || {}, // Add context + context: options.context || {}, }, query, }; @@ -139,6 +139,7 @@ function ParseServerRESTController(applicationId, router) { return { request: handleRequest, ajax: RESTController.ajax, + handleError: RESTController.handleError, }; } From 92ae943b6b7f3a8114507b1c0ca901f0aa4446b5 Mon Sep 17 00:00:00 2001 From: Diamond Lewis Date: Fri, 8 Jan 2021 17:20:52 -0600 Subject: [PATCH 05/19] Properly handle RESTController --- spec/helper.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/spec/helper.js b/spec/helper.js index 728575f3f6..bb228abb16 100644 --- a/spec/helper.js +++ b/spec/helper.js @@ -135,6 +135,7 @@ const reconfigureServer = changedConfiguration => { if (error) { reject(error); } else { + Parse.CoreManager.setRESTController(RESTController); resolve(parseServer); } }, @@ -165,7 +166,6 @@ const reconfigureServer = changedConfiguration => { // Set up a Parse client to talk to our test API server const Parse = require('parse/node'); Parse.serverURL = 'http://localhost:' + port + '/1'; -Parse.CoreManager.setRESTController(RESTController); beforeEach(done => { try { @@ -189,7 +189,6 @@ beforeEach(done => { .then(() => { Parse.initialize('test', 'test', 'test'); Parse.serverURL = 'http://localhost:' + port + '/1'; - Parse.CoreManager.setRESTController(RESTController); done(); }) From b81fd739207938e80cac04a576cd56dded2dbdc2 Mon Sep 17 00:00:00 2001 From: Diamond Lewis Date: Fri, 8 Jan 2021 17:23:00 -0600 Subject: [PATCH 06/19] Documentation --- spec/helper.js | 1 - src/ParseServer.js | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/spec/helper.js b/spec/helper.js index bb228abb16..eecb22949e 100644 --- a/spec/helper.js +++ b/spec/helper.js @@ -189,7 +189,6 @@ beforeEach(done => { .then(() => { Parse.initialize('test', 'test', 'test'); Parse.serverURL = 'http://localhost:' + port + '/1'; - done(); }) .catch(done.fail); diff --git a/src/ParseServer.js b/src/ParseServer.js index 7396342666..9e0f371d9b 100644 --- a/src/ParseServer.js +++ b/src/ParseServer.js @@ -185,7 +185,7 @@ class ParseServer { }); } - // Bypass HTTP calls made by SDK during node runtime + // Replace HTTP Interface when using JS SDK in current node runtime Parse.CoreManager.setRESTController(ParseServerRESTController(appId, appRouter)); return api; From 1e600d69a3994b3239ee512f484e82c33af4f878 Mon Sep 17 00:00:00 2001 From: Diamond Lewis Date: Fri, 8 Jan 2021 17:52:11 -0600 Subject: [PATCH 07/19] revert changes --- spec/helper.js | 3 +- spec/index.spec.js | 10 + src/Options/Definitions.js | 1189 ++++++++++++++++++------------------ src/Options/index.js | 4 + src/ParseServer.js | 8 +- 5 files changed, 624 insertions(+), 590 deletions(-) diff --git a/spec/helper.js b/spec/helper.js index eecb22949e..5c90c76f02 100644 --- a/spec/helper.js +++ b/spec/helper.js @@ -30,7 +30,6 @@ const PostgresStorageAdapter = require('../lib/Adapters/Storage/Postgres/Postgre .default; const MongoStorageAdapter = require('../lib/Adapters/Storage/Mongo/MongoStorageAdapter').default; const RedisCacheAdapter = require('../lib/Adapters/Cache/RedisCacheAdapter').default; -const RESTController = require('parse/lib/node/RESTController'); const mongoURI = 'mongodb://localhost:27017/parseServerMongoAdapterTestDatabase'; const postgresURI = 'postgres://localhost:5432/parse_server_postgres_adapter_test_database'; @@ -87,6 +86,7 @@ const defaultConfiguration = { masterKey: 'test', readOnlyMasterKey: 'read-only-test', fileKey: 'test', + directAccess: false, silent, logLevel, fileUpload: { @@ -135,7 +135,6 @@ const reconfigureServer = changedConfiguration => { if (error) { reject(error); } else { - Parse.CoreManager.setRESTController(RESTController); resolve(parseServer); } }, diff --git a/spec/index.spec.js b/spec/index.spec.js index 778c888caf..1b542926c1 100644 --- a/spec/index.spec.js +++ b/spec/index.spec.js @@ -490,6 +490,16 @@ describe('server', () => { .catch(done.fail); }); + it('should allow direct access', async () => { + const RESTController = Parse.CoreManager.getRESTController(); + const spy = spyOn(Parse.CoreManager, 'setRESTController').and.callThrough(); + await reconfigureServer({ + directAccess: true, + }); + expect(spy).toHaveBeenCalledTimes(1); + Parse.CoreManager.setRESTController(RESTController); + }); + it('should load a middleware from string', done => { reconfigureServer({ middleware: 'spec/support/CustomMiddleware', diff --git a/src/Options/Definitions.js b/src/Options/Definitions.js index c0ea9b064f..4d252a4860 100644 --- a/src/Options/Definitions.js +++ b/src/Options/Definitions.js @@ -3,604 +3,625 @@ This code has been generated by resources/buildConfigDefinitions.js Do not edit manually, but update Options/index.js */ -var parsers = require("./parsers"); +var parsers = require('./parsers'); module.exports.ParseServerOptions = { - "accountLockout": { - "env": "PARSE_SERVER_ACCOUNT_LOCKOUT", - "help": "account lockout policy for failed login attempts", - "action": parsers.objectParser - }, - "allowClientClassCreation": { - "env": "PARSE_SERVER_ALLOW_CLIENT_CLASS_CREATION", - "help": "Enable (or disable) client class creation, defaults to true", - "action": parsers.booleanParser, - "default": true - }, - "allowCustomObjectId": { - "env": "PARSE_SERVER_ALLOW_CUSTOM_OBJECT_ID", - "help": "Enable (or disable) custom objectId", - "action": parsers.booleanParser, - "default": false - }, - "allowHeaders": { - "env": "PARSE_SERVER_ALLOW_HEADERS", - "help": "Add headers to Access-Control-Allow-Headers", - "action": parsers.arrayParser - }, - "allowOrigin": { - "env": "PARSE_SERVER_ALLOW_ORIGIN", - "help": "Sets the origin to Access-Control-Allow-Origin" - }, - "analyticsAdapter": { - "env": "PARSE_SERVER_ANALYTICS_ADAPTER", - "help": "Adapter module for the analytics", - "action": parsers.moduleOrObjectParser - }, - "appId": { - "env": "PARSE_SERVER_APPLICATION_ID", - "help": "Your Parse Application ID", - "required": true - }, - "appName": { - "env": "PARSE_SERVER_APP_NAME", - "help": "Sets the app name" - }, - "auth": { - "env": "PARSE_SERVER_AUTH_PROVIDERS", - "help": "Configuration for your authentication providers, as stringified JSON. See http://docs.parseplatform.org/parse-server/guide/#oauth-and-3rd-party-authentication", - "action": parsers.objectParser - }, - "cacheAdapter": { - "env": "PARSE_SERVER_CACHE_ADAPTER", - "help": "Adapter module for the cache", - "action": parsers.moduleOrObjectParser - }, - "cacheMaxSize": { - "env": "PARSE_SERVER_CACHE_MAX_SIZE", - "help": "Sets the maximum size for the in memory cache, defaults to 10000", - "action": parsers.numberParser("cacheMaxSize"), - "default": 10000 - }, - "cacheTTL": { - "env": "PARSE_SERVER_CACHE_TTL", - "help": "Sets the TTL for the in memory cache (in ms), defaults to 5000 (5 seconds)", - "action": parsers.numberParser("cacheTTL"), - "default": 5000 - }, - "clientKey": { - "env": "PARSE_SERVER_CLIENT_KEY", - "help": "Key for iOS, MacOS, tvOS clients" - }, - "cloud": { - "env": "PARSE_SERVER_CLOUD", - "help": "Full path to your cloud code main.js" - }, - "cluster": { - "env": "PARSE_SERVER_CLUSTER", - "help": "Run with cluster, optionally set the number of processes default to os.cpus().length", - "action": parsers.numberOrBooleanParser - }, - "collectionPrefix": { - "env": "PARSE_SERVER_COLLECTION_PREFIX", - "help": "A collection prefix for the classes", - "default": "" - }, - "customPages": { - "env": "PARSE_SERVER_CUSTOM_PAGES", - "help": "custom pages for password validation and reset", - "action": parsers.objectParser, - "default": {} - }, - "databaseAdapter": { - "env": "PARSE_SERVER_DATABASE_ADAPTER", - "help": "Adapter module for the database", - "action": parsers.moduleOrObjectParser - }, - "databaseOptions": { - "env": "PARSE_SERVER_DATABASE_OPTIONS", - "help": "Options to pass to the mongodb client", - "action": parsers.objectParser - }, - "databaseURI": { - "env": "PARSE_SERVER_DATABASE_URI", - "help": "The full URI to your database. Supported databases are mongodb or postgres.", - "required": true, - "default": "mongodb://localhost:27017/parse" - }, - "directAccess": { - "env": "PARSE_SERVER_ENABLE_EXPERIMENTAL_DIRECT_ACCESS", - "help": "Replace HTTP Interface when using JS SDK in current node runtime, defaults to false. Caution, this is an experimental feature that may not be appropriate for production.", - "action": parsers.booleanParser, - "default": false - }, - "dotNetKey": { - "env": "PARSE_SERVER_DOT_NET_KEY", - "help": "Key for Unity and .Net SDK" - }, - "emailAdapter": { - "env": "PARSE_SERVER_EMAIL_ADAPTER", - "help": "Adapter module for email sending", - "action": parsers.moduleOrObjectParser - }, - "emailVerifyTokenReuseIfValid": { - "env": "PARSE_SERVER_EMAIL_VERIFY_TOKEN_REUSE_IF_VALID", - "help": "an existing email verify token should be reused when resend verification email is requested", - "action": parsers.booleanParser, - "default": false - }, - "emailVerifyTokenValidityDuration": { - "env": "PARSE_SERVER_EMAIL_VERIFY_TOKEN_VALIDITY_DURATION", - "help": "Email verification token validity duration, in seconds", - "action": parsers.numberParser("emailVerifyTokenValidityDuration") - }, - "enableAnonymousUsers": { - "env": "PARSE_SERVER_ENABLE_ANON_USERS", - "help": "Enable (or disable) anonymous users, defaults to true", - "action": parsers.booleanParser, - "default": true - }, - "enableExpressErrorHandler": { - "env": "PARSE_SERVER_ENABLE_EXPRESS_ERROR_HANDLER", - "help": "Enables the default express error handler for all errors", - "action": parsers.booleanParser, - "default": false - }, - "enableSingleSchemaCache": { - "env": "PARSE_SERVER_ENABLE_SINGLE_SCHEMA_CACHE", - "help": "Use a single schema cache shared across requests. Reduces number of queries made to _SCHEMA, defaults to false, i.e. unique schema cache per request.", - "action": parsers.booleanParser, - "default": false - }, - "encryptionKey": { - "env": "PARSE_SERVER_ENCRYPTION_KEY", - "help": "Key for encrypting your files" - }, - "expireInactiveSessions": { - "env": "PARSE_SERVER_EXPIRE_INACTIVE_SESSIONS", - "help": "Sets wether we should expire the inactive sessions, defaults to true", - "action": parsers.booleanParser, - "default": true - }, - "fileKey": { - "env": "PARSE_SERVER_FILE_KEY", - "help": "Key for your files" - }, - "filesAdapter": { - "env": "PARSE_SERVER_FILES_ADAPTER", - "help": "Adapter module for the files sub-system", - "action": parsers.moduleOrObjectParser - }, - "fileUpload": { - "env": "PARSE_SERVER_FILE_UPLOAD_OPTIONS", - "help": "Options for file uploads", - "action": parsers.objectParser - }, - "graphQLPath": { - "env": "PARSE_SERVER_GRAPHQL_PATH", - "help": "Mount path for the GraphQL endpoint, defaults to /graphql", - "default": "/graphql" - }, - "graphQLSchema": { - "env": "PARSE_SERVER_GRAPH_QLSCHEMA", - "help": "Full path to your GraphQL custom schema.graphql file" - }, - "host": { - "env": "PARSE_SERVER_HOST", - "help": "The host to serve ParseServer on, defaults to 0.0.0.0", - "default": "0.0.0.0" - }, - "idempotencyOptions": { - "env": "PARSE_SERVER_EXPERIMENTAL_IDEMPOTENCY_OPTIONS", - "help": "Options for request idempotency to deduplicate identical requests that may be caused by network issues. Caution, this is an experimental feature that may not be appropriate for production.", - "action": parsers.objectParser, - "default": {} - }, - "javascriptKey": { - "env": "PARSE_SERVER_JAVASCRIPT_KEY", - "help": "Key for the Javascript SDK" - }, - "jsonLogs": { - "env": "JSON_LOGS", - "help": "Log as structured JSON objects", - "action": parsers.booleanParser - }, - "liveQuery": { - "env": "PARSE_SERVER_LIVE_QUERY", - "help": "parse-server's LiveQuery configuration object", - "action": parsers.objectParser - }, - "liveQueryServerOptions": { - "env": "PARSE_SERVER_LIVE_QUERY_SERVER_OPTIONS", - "help": "Live query server configuration options (will start the liveQuery server)", - "action": parsers.objectParser - }, - "loggerAdapter": { - "env": "PARSE_SERVER_LOGGER_ADAPTER", - "help": "Adapter module for the logging sub-system", - "action": parsers.moduleOrObjectParser - }, - "logLevel": { - "env": "PARSE_SERVER_LOG_LEVEL", - "help": "Sets the level for logs" - }, - "logsFolder": { - "env": "PARSE_SERVER_LOGS_FOLDER", - "help": "Folder for the logs (defaults to './logs'); set to null to disable file based logging", - "default": "./logs" - }, - "masterKey": { - "env": "PARSE_SERVER_MASTER_KEY", - "help": "Your Parse Master Key", - "required": true - }, - "masterKeyIps": { - "env": "PARSE_SERVER_MASTER_KEY_IPS", - "help": "Restrict masterKey to be used by only these ips, defaults to [] (allow all ips)", - "action": parsers.arrayParser, - "default": [] - }, - "maxLimit": { - "env": "PARSE_SERVER_MAX_LIMIT", - "help": "Max value for limit option on queries, defaults to unlimited", - "action": parsers.numberParser("maxLimit") - }, - "maxLogFiles": { - "env": "PARSE_SERVER_MAX_LOG_FILES", - "help": "Maximum number of logs to keep. If not set, no logs will be removed. This can be a number of files or number of days. If using days, add 'd' as the suffix. (default: null)", - "action": parsers.objectParser - }, - "maxUploadSize": { - "env": "PARSE_SERVER_MAX_UPLOAD_SIZE", - "help": "Max file size for uploads, defaults to 20mb", - "default": "20mb" - }, - "middleware": { - "env": "PARSE_SERVER_MIDDLEWARE", - "help": "middleware for express server, can be string or function" - }, - "mountGraphQL": { - "env": "PARSE_SERVER_MOUNT_GRAPHQL", - "help": "Mounts the GraphQL endpoint", - "action": parsers.booleanParser, - "default": false - }, - "mountPath": { - "env": "PARSE_SERVER_MOUNT_PATH", - "help": "Mount path for the server, defaults to /parse", - "default": "/parse" - }, - "mountPlayground": { - "env": "PARSE_SERVER_MOUNT_PLAYGROUND", - "help": "Mounts the GraphQL Playground - never use this option in production", - "action": parsers.booleanParser, - "default": false - }, - "objectIdSize": { - "env": "PARSE_SERVER_OBJECT_ID_SIZE", - "help": "Sets the number of characters in generated object id's, default 10", - "action": parsers.numberParser("objectIdSize"), - "default": 10 - }, - "passwordPolicy": { - "env": "PARSE_SERVER_PASSWORD_POLICY", - "help": "Password policy for enforcing password related rules", - "action": parsers.objectParser - }, - "playgroundPath": { - "env": "PARSE_SERVER_PLAYGROUND_PATH", - "help": "Mount path for the GraphQL Playground, defaults to /playground", - "default": "/playground" - }, - "port": { - "env": "PORT", - "help": "The port to run the ParseServer, defaults to 1337.", - "action": parsers.numberParser("port"), - "default": 1337 - }, - "preserveFileName": { - "env": "PARSE_SERVER_PRESERVE_FILE_NAME", - "help": "Enable (or disable) the addition of a unique hash to the file names", - "action": parsers.booleanParser, - "default": false - }, - "preventLoginWithUnverifiedEmail": { - "env": "PARSE_SERVER_PREVENT_LOGIN_WITH_UNVERIFIED_EMAIL", - "help": "Prevent user from login if email is not verified and PARSE_SERVER_VERIFY_USER_EMAILS is true, defaults to false", - "action": parsers.booleanParser, - "default": false - }, - "protectedFields": { - "env": "PARSE_SERVER_PROTECTED_FIELDS", - "help": "Protected fields that should be treated with extra security when fetching details.", - "action": parsers.objectParser, - "default": { - "_User": { - "*": ["email"] - } - } - }, - "publicServerURL": { - "env": "PARSE_PUBLIC_SERVER_URL", - "help": "Public URL to your parse server with http:// or https://." - }, - "push": { - "env": "PARSE_SERVER_PUSH", - "help": "Configuration for push, as stringified JSON. See http://docs.parseplatform.org/parse-server/guide/#push-notifications", - "action": parsers.objectParser - }, - "readOnlyMasterKey": { - "env": "PARSE_SERVER_READ_ONLY_MASTER_KEY", - "help": "Read-only key, which has the same capabilities as MasterKey without writes" - }, - "restAPIKey": { - "env": "PARSE_SERVER_REST_API_KEY", - "help": "Key for REST calls" - }, - "revokeSessionOnPasswordReset": { - "env": "PARSE_SERVER_REVOKE_SESSION_ON_PASSWORD_RESET", - "help": "When a user changes their password, either through the reset password email or while logged in, all sessions are revoked if this is true. Set to false if you don't want to revoke sessions.", - "action": parsers.booleanParser, - "default": true - }, - "scheduledPush": { - "env": "PARSE_SERVER_SCHEDULED_PUSH", - "help": "Configuration for push scheduling, defaults to false.", - "action": parsers.booleanParser, - "default": false - }, - "schemaCacheTTL": { - "env": "PARSE_SERVER_SCHEMA_CACHE_TTL", - "help": "The TTL for caching the schema for optimizing read/write operations. You should put a long TTL when your DB is in production. default to 5000; set 0 to disable.", - "action": parsers.numberParser("schemaCacheTTL"), - "default": 5000 - }, - "serverCloseComplete": { - "env": "PARSE_SERVER_SERVER_CLOSE_COMPLETE", - "help": "Callback when server has closed" - }, - "serverStartComplete": { - "env": "PARSE_SERVER_SERVER_START_COMPLETE", - "help": "Callback when server has started" - }, - "serverURL": { - "env": "PARSE_SERVER_URL", - "help": "URL to your parse server with http:// or https://.", - "required": true - }, - "sessionLength": { - "env": "PARSE_SERVER_SESSION_LENGTH", - "help": "Session duration, in seconds, defaults to 1 year", - "action": parsers.numberParser("sessionLength"), - "default": 31536000 - }, - "silent": { - "env": "SILENT", - "help": "Disables console output", - "action": parsers.booleanParser - }, - "startLiveQueryServer": { - "env": "PARSE_SERVER_START_LIVE_QUERY_SERVER", - "help": "Starts the liveQuery server", - "action": parsers.booleanParser - }, - "userSensitiveFields": { - "env": "PARSE_SERVER_USER_SENSITIVE_FIELDS", - "help": "Personally identifiable information fields in the user table the should be removed for non-authorized users. Deprecated @see protectedFields", - "action": parsers.arrayParser - }, - "verbose": { - "env": "VERBOSE", - "help": "Set the logging to verbose", - "action": parsers.booleanParser - }, - "verifyUserEmails": { - "env": "PARSE_SERVER_VERIFY_USER_EMAILS", - "help": "Enable (or disable) user email validation, defaults to false", - "action": parsers.booleanParser, - "default": false - }, - "webhookKey": { - "env": "PARSE_SERVER_WEBHOOK_KEY", - "help": "Key sent with outgoing webhook calls" - } + accountLockout: { + env: 'PARSE_SERVER_ACCOUNT_LOCKOUT', + help: 'account lockout policy for failed login attempts', + action: parsers.objectParser, + }, + allowClientClassCreation: { + env: 'PARSE_SERVER_ALLOW_CLIENT_CLASS_CREATION', + help: 'Enable (or disable) client class creation, defaults to true', + action: parsers.booleanParser, + default: true, + }, + allowCustomObjectId: { + env: 'PARSE_SERVER_ALLOW_CUSTOM_OBJECT_ID', + help: 'Enable (or disable) custom objectId', + action: parsers.booleanParser, + default: false, + }, + allowHeaders: { + env: 'PARSE_SERVER_ALLOW_HEADERS', + help: 'Add headers to Access-Control-Allow-Headers', + action: parsers.arrayParser, + }, + allowOrigin: { + env: 'PARSE_SERVER_ALLOW_ORIGIN', + help: 'Sets the origin to Access-Control-Allow-Origin', + }, + analyticsAdapter: { + env: 'PARSE_SERVER_ANALYTICS_ADAPTER', + help: 'Adapter module for the analytics', + action: parsers.moduleOrObjectParser, + }, + appId: { + env: 'PARSE_SERVER_APPLICATION_ID', + help: 'Your Parse Application ID', + required: true, + }, + appName: { + env: 'PARSE_SERVER_APP_NAME', + help: 'Sets the app name', + }, + auth: { + env: 'PARSE_SERVER_AUTH_PROVIDERS', + help: + 'Configuration for your authentication providers, as stringified JSON. See http://docs.parseplatform.org/parse-server/guide/#oauth-and-3rd-party-authentication', + action: parsers.objectParser, + }, + cacheAdapter: { + env: 'PARSE_SERVER_CACHE_ADAPTER', + help: 'Adapter module for the cache', + action: parsers.moduleOrObjectParser, + }, + cacheMaxSize: { + env: 'PARSE_SERVER_CACHE_MAX_SIZE', + help: 'Sets the maximum size for the in memory cache, defaults to 10000', + action: parsers.numberParser('cacheMaxSize'), + default: 10000, + }, + cacheTTL: { + env: 'PARSE_SERVER_CACHE_TTL', + help: 'Sets the TTL for the in memory cache (in ms), defaults to 5000 (5 seconds)', + action: parsers.numberParser('cacheTTL'), + default: 5000, + }, + clientKey: { + env: 'PARSE_SERVER_CLIENT_KEY', + help: 'Key for iOS, MacOS, tvOS clients', + }, + cloud: { + env: 'PARSE_SERVER_CLOUD', + help: 'Full path to your cloud code main.js', + }, + cluster: { + env: 'PARSE_SERVER_CLUSTER', + help: 'Run with cluster, optionally set the number of processes default to os.cpus().length', + action: parsers.numberOrBooleanParser, + }, + collectionPrefix: { + env: 'PARSE_SERVER_COLLECTION_PREFIX', + help: 'A collection prefix for the classes', + default: '', + }, + customPages: { + env: 'PARSE_SERVER_CUSTOM_PAGES', + help: 'custom pages for password validation and reset', + action: parsers.objectParser, + default: {}, + }, + databaseAdapter: { + env: 'PARSE_SERVER_DATABASE_ADAPTER', + help: 'Adapter module for the database', + action: parsers.moduleOrObjectParser, + }, + databaseOptions: { + env: 'PARSE_SERVER_DATABASE_OPTIONS', + help: 'Options to pass to the mongodb client', + action: parsers.objectParser, + }, + databaseURI: { + env: 'PARSE_SERVER_DATABASE_URI', + help: 'The full URI to your database. Supported databases are mongodb or postgres.', + required: true, + default: 'mongodb://localhost:27017/parse', + }, + directAccess: { + env: 'PARSE_SERVER_ENABLE_EXPERIMENTAL_DIRECT_ACCESS', + help: + 'Replace HTTP Interface when using JS SDK in current node runtime, defaults to false. Caution, this is an experimental feature that may not be appropriate for production.', + action: parsers.booleanParser, + default: true, + }, + dotNetKey: { + env: 'PARSE_SERVER_DOT_NET_KEY', + help: 'Key for Unity and .Net SDK', + }, + emailAdapter: { + env: 'PARSE_SERVER_EMAIL_ADAPTER', + help: 'Adapter module for email sending', + action: parsers.moduleOrObjectParser, + }, + emailVerifyTokenReuseIfValid: { + env: 'PARSE_SERVER_EMAIL_VERIFY_TOKEN_REUSE_IF_VALID', + help: + 'an existing email verify token should be reused when resend verification email is requested', + action: parsers.booleanParser, + default: false, + }, + emailVerifyTokenValidityDuration: { + env: 'PARSE_SERVER_EMAIL_VERIFY_TOKEN_VALIDITY_DURATION', + help: 'Email verification token validity duration, in seconds', + action: parsers.numberParser('emailVerifyTokenValidityDuration'), + }, + enableAnonymousUsers: { + env: 'PARSE_SERVER_ENABLE_ANON_USERS', + help: 'Enable (or disable) anonymous users, defaults to true', + action: parsers.booleanParser, + default: true, + }, + enableExpressErrorHandler: { + env: 'PARSE_SERVER_ENABLE_EXPRESS_ERROR_HANDLER', + help: 'Enables the default express error handler for all errors', + action: parsers.booleanParser, + default: false, + }, + enableSingleSchemaCache: { + env: 'PARSE_SERVER_ENABLE_SINGLE_SCHEMA_CACHE', + help: + 'Use a single schema cache shared across requests. Reduces number of queries made to _SCHEMA, defaults to false, i.e. unique schema cache per request.', + action: parsers.booleanParser, + default: false, + }, + encryptionKey: { + env: 'PARSE_SERVER_ENCRYPTION_KEY', + help: 'Key for encrypting your files', + }, + expireInactiveSessions: { + env: 'PARSE_SERVER_EXPIRE_INACTIVE_SESSIONS', + help: 'Sets wether we should expire the inactive sessions, defaults to true', + action: parsers.booleanParser, + default: true, + }, + fileKey: { + env: 'PARSE_SERVER_FILE_KEY', + help: 'Key for your files', + }, + filesAdapter: { + env: 'PARSE_SERVER_FILES_ADAPTER', + help: 'Adapter module for the files sub-system', + action: parsers.moduleOrObjectParser, + }, + fileUpload: { + env: 'PARSE_SERVER_FILE_UPLOAD_OPTIONS', + help: 'Options for file uploads', + action: parsers.objectParser, + }, + graphQLPath: { + env: 'PARSE_SERVER_GRAPHQL_PATH', + help: 'Mount path for the GraphQL endpoint, defaults to /graphql', + default: '/graphql', + }, + graphQLSchema: { + env: 'PARSE_SERVER_GRAPH_QLSCHEMA', + help: 'Full path to your GraphQL custom schema.graphql file', + }, + host: { + env: 'PARSE_SERVER_HOST', + help: 'The host to serve ParseServer on, defaults to 0.0.0.0', + default: '0.0.0.0', + }, + idempotencyOptions: { + env: 'PARSE_SERVER_EXPERIMENTAL_IDEMPOTENCY_OPTIONS', + help: + 'Options for request idempotency to deduplicate identical requests that may be caused by network issues. Caution, this is an experimental feature that may not be appropriate for production.', + action: parsers.objectParser, + default: {}, + }, + javascriptKey: { + env: 'PARSE_SERVER_JAVASCRIPT_KEY', + help: 'Key for the Javascript SDK', + }, + jsonLogs: { + env: 'JSON_LOGS', + help: 'Log as structured JSON objects', + action: parsers.booleanParser, + }, + liveQuery: { + env: 'PARSE_SERVER_LIVE_QUERY', + help: "parse-server's LiveQuery configuration object", + action: parsers.objectParser, + }, + liveQueryServerOptions: { + env: 'PARSE_SERVER_LIVE_QUERY_SERVER_OPTIONS', + help: 'Live query server configuration options (will start the liveQuery server)', + action: parsers.objectParser, + }, + loggerAdapter: { + env: 'PARSE_SERVER_LOGGER_ADAPTER', + help: 'Adapter module for the logging sub-system', + action: parsers.moduleOrObjectParser, + }, + logLevel: { + env: 'PARSE_SERVER_LOG_LEVEL', + help: 'Sets the level for logs', + }, + logsFolder: { + env: 'PARSE_SERVER_LOGS_FOLDER', + help: "Folder for the logs (defaults to './logs'); set to null to disable file based logging", + default: './logs', + }, + masterKey: { + env: 'PARSE_SERVER_MASTER_KEY', + help: 'Your Parse Master Key', + required: true, + }, + masterKeyIps: { + env: 'PARSE_SERVER_MASTER_KEY_IPS', + help: 'Restrict masterKey to be used by only these ips, defaults to [] (allow all ips)', + action: parsers.arrayParser, + default: [], + }, + maxLimit: { + env: 'PARSE_SERVER_MAX_LIMIT', + help: 'Max value for limit option on queries, defaults to unlimited', + action: parsers.numberParser('maxLimit'), + }, + maxLogFiles: { + env: 'PARSE_SERVER_MAX_LOG_FILES', + help: + "Maximum number of logs to keep. If not set, no logs will be removed. This can be a number of files or number of days. If using days, add 'd' as the suffix. (default: null)", + action: parsers.objectParser, + }, + maxUploadSize: { + env: 'PARSE_SERVER_MAX_UPLOAD_SIZE', + help: 'Max file size for uploads, defaults to 20mb', + default: '20mb', + }, + middleware: { + env: 'PARSE_SERVER_MIDDLEWARE', + help: 'middleware for express server, can be string or function', + }, + mountGraphQL: { + env: 'PARSE_SERVER_MOUNT_GRAPHQL', + help: 'Mounts the GraphQL endpoint', + action: parsers.booleanParser, + default: false, + }, + mountPath: { + env: 'PARSE_SERVER_MOUNT_PATH', + help: 'Mount path for the server, defaults to /parse', + default: '/parse', + }, + mountPlayground: { + env: 'PARSE_SERVER_MOUNT_PLAYGROUND', + help: 'Mounts the GraphQL Playground - never use this option in production', + action: parsers.booleanParser, + default: false, + }, + objectIdSize: { + env: 'PARSE_SERVER_OBJECT_ID_SIZE', + help: "Sets the number of characters in generated object id's, default 10", + action: parsers.numberParser('objectIdSize'), + default: 10, + }, + passwordPolicy: { + env: 'PARSE_SERVER_PASSWORD_POLICY', + help: 'Password policy for enforcing password related rules', + action: parsers.objectParser, + }, + playgroundPath: { + env: 'PARSE_SERVER_PLAYGROUND_PATH', + help: 'Mount path for the GraphQL Playground, defaults to /playground', + default: '/playground', + }, + port: { + env: 'PORT', + help: 'The port to run the ParseServer, defaults to 1337.', + action: parsers.numberParser('port'), + default: 1337, + }, + preserveFileName: { + env: 'PARSE_SERVER_PRESERVE_FILE_NAME', + help: 'Enable (or disable) the addition of a unique hash to the file names', + action: parsers.booleanParser, + default: false, + }, + preventLoginWithUnverifiedEmail: { + env: 'PARSE_SERVER_PREVENT_LOGIN_WITH_UNVERIFIED_EMAIL', + help: + 'Prevent user from login if email is not verified and PARSE_SERVER_VERIFY_USER_EMAILS is true, defaults to false', + action: parsers.booleanParser, + default: false, + }, + protectedFields: { + env: 'PARSE_SERVER_PROTECTED_FIELDS', + help: 'Protected fields that should be treated with extra security when fetching details.', + action: parsers.objectParser, + default: { + _User: { + '*': ['email'], + }, + }, + }, + publicServerURL: { + env: 'PARSE_PUBLIC_SERVER_URL', + help: 'Public URL to your parse server with http:// or https://.', + }, + push: { + env: 'PARSE_SERVER_PUSH', + help: + 'Configuration for push, as stringified JSON. See http://docs.parseplatform.org/parse-server/guide/#push-notifications', + action: parsers.objectParser, + }, + readOnlyMasterKey: { + env: 'PARSE_SERVER_READ_ONLY_MASTER_KEY', + help: 'Read-only key, which has the same capabilities as MasterKey without writes', + }, + restAPIKey: { + env: 'PARSE_SERVER_REST_API_KEY', + help: 'Key for REST calls', + }, + revokeSessionOnPasswordReset: { + env: 'PARSE_SERVER_REVOKE_SESSION_ON_PASSWORD_RESET', + help: + "When a user changes their password, either through the reset password email or while logged in, all sessions are revoked if this is true. Set to false if you don't want to revoke sessions.", + action: parsers.booleanParser, + default: true, + }, + scheduledPush: { + env: 'PARSE_SERVER_SCHEDULED_PUSH', + help: 'Configuration for push scheduling, defaults to false.', + action: parsers.booleanParser, + default: false, + }, + schemaCacheTTL: { + env: 'PARSE_SERVER_SCHEMA_CACHE_TTL', + help: + 'The TTL for caching the schema for optimizing read/write operations. You should put a long TTL when your DB is in production. default to 5000; set 0 to disable.', + action: parsers.numberParser('schemaCacheTTL'), + default: 5000, + }, + serverCloseComplete: { + env: 'PARSE_SERVER_SERVER_CLOSE_COMPLETE', + help: 'Callback when server has closed', + }, + serverStartComplete: { + env: 'PARSE_SERVER_SERVER_START_COMPLETE', + help: 'Callback when server has started', + }, + serverURL: { + env: 'PARSE_SERVER_URL', + help: 'URL to your parse server with http:// or https://.', + required: true, + }, + sessionLength: { + env: 'PARSE_SERVER_SESSION_LENGTH', + help: 'Session duration, in seconds, defaults to 1 year', + action: parsers.numberParser('sessionLength'), + default: 31536000, + }, + silent: { + env: 'SILENT', + help: 'Disables console output', + action: parsers.booleanParser, + }, + startLiveQueryServer: { + env: 'PARSE_SERVER_START_LIVE_QUERY_SERVER', + help: 'Starts the liveQuery server', + action: parsers.booleanParser, + }, + userSensitiveFields: { + env: 'PARSE_SERVER_USER_SENSITIVE_FIELDS', + help: + 'Personally identifiable information fields in the user table the should be removed for non-authorized users. Deprecated @see protectedFields', + action: parsers.arrayParser, + }, + verbose: { + env: 'VERBOSE', + help: 'Set the logging to verbose', + action: parsers.booleanParser, + }, + verifyUserEmails: { + env: 'PARSE_SERVER_VERIFY_USER_EMAILS', + help: 'Enable (or disable) user email validation, defaults to false', + action: parsers.booleanParser, + default: false, + }, + webhookKey: { + env: 'PARSE_SERVER_WEBHOOK_KEY', + help: 'Key sent with outgoing webhook calls', + }, }; module.exports.CustomPagesOptions = { - "choosePassword": { - "env": "PARSE_SERVER_CUSTOM_PAGES_CHOOSE_PASSWORD", - "help": "choose password page path" - }, - "invalidLink": { - "env": "PARSE_SERVER_CUSTOM_PAGES_INVALID_LINK", - "help": "invalid link page path" - }, - "invalidVerificationLink": { - "env": "PARSE_SERVER_CUSTOM_PAGES_INVALID_VERIFICATION_LINK", - "help": "invalid verification link page path" - }, - "linkSendFail": { - "env": "PARSE_SERVER_CUSTOM_PAGES_LINK_SEND_FAIL", - "help": "verification link send fail page path" - }, - "linkSendSuccess": { - "env": "PARSE_SERVER_CUSTOM_PAGES_LINK_SEND_SUCCESS", - "help": "verification link send success page path" - }, - "parseFrameURL": { - "env": "PARSE_SERVER_CUSTOM_PAGES_PARSE_FRAME_URL", - "help": "for masking user-facing pages" - }, - "passwordResetSuccess": { - "env": "PARSE_SERVER_CUSTOM_PAGES_PASSWORD_RESET_SUCCESS", - "help": "password reset success page path" - }, - "verifyEmailSuccess": { - "env": "PARSE_SERVER_CUSTOM_PAGES_VERIFY_EMAIL_SUCCESS", - "help": "verify email success page path" - } + choosePassword: { + env: 'PARSE_SERVER_CUSTOM_PAGES_CHOOSE_PASSWORD', + help: 'choose password page path', + }, + invalidLink: { + env: 'PARSE_SERVER_CUSTOM_PAGES_INVALID_LINK', + help: 'invalid link page path', + }, + invalidVerificationLink: { + env: 'PARSE_SERVER_CUSTOM_PAGES_INVALID_VERIFICATION_LINK', + help: 'invalid verification link page path', + }, + linkSendFail: { + env: 'PARSE_SERVER_CUSTOM_PAGES_LINK_SEND_FAIL', + help: 'verification link send fail page path', + }, + linkSendSuccess: { + env: 'PARSE_SERVER_CUSTOM_PAGES_LINK_SEND_SUCCESS', + help: 'verification link send success page path', + }, + parseFrameURL: { + env: 'PARSE_SERVER_CUSTOM_PAGES_PARSE_FRAME_URL', + help: 'for masking user-facing pages', + }, + passwordResetSuccess: { + env: 'PARSE_SERVER_CUSTOM_PAGES_PASSWORD_RESET_SUCCESS', + help: 'password reset success page path', + }, + verifyEmailSuccess: { + env: 'PARSE_SERVER_CUSTOM_PAGES_VERIFY_EMAIL_SUCCESS', + help: 'verify email success page path', + }, }; module.exports.LiveQueryOptions = { - "classNames": { - "env": "PARSE_SERVER_LIVEQUERY_CLASSNAMES", - "help": "parse-server's LiveQuery classNames", - "action": parsers.arrayParser - }, - "pubSubAdapter": { - "env": "PARSE_SERVER_LIVEQUERY_PUB_SUB_ADAPTER", - "help": "LiveQuery pubsub adapter", - "action": parsers.moduleOrObjectParser - }, - "redisOptions": { - "env": "PARSE_SERVER_LIVEQUERY_REDIS_OPTIONS", - "help": "parse-server's LiveQuery redisOptions", - "action": parsers.objectParser - }, - "redisURL": { - "env": "PARSE_SERVER_LIVEQUERY_REDIS_URL", - "help": "parse-server's LiveQuery redisURL" - }, - "wssAdapter": { - "env": "PARSE_SERVER_LIVEQUERY_WSS_ADAPTER", - "help": "Adapter module for the WebSocketServer", - "action": parsers.moduleOrObjectParser - } + classNames: { + env: 'PARSE_SERVER_LIVEQUERY_CLASSNAMES', + help: "parse-server's LiveQuery classNames", + action: parsers.arrayParser, + }, + pubSubAdapter: { + env: 'PARSE_SERVER_LIVEQUERY_PUB_SUB_ADAPTER', + help: 'LiveQuery pubsub adapter', + action: parsers.moduleOrObjectParser, + }, + redisOptions: { + env: 'PARSE_SERVER_LIVEQUERY_REDIS_OPTIONS', + help: "parse-server's LiveQuery redisOptions", + action: parsers.objectParser, + }, + redisURL: { + env: 'PARSE_SERVER_LIVEQUERY_REDIS_URL', + help: "parse-server's LiveQuery redisURL", + }, + wssAdapter: { + env: 'PARSE_SERVER_LIVEQUERY_WSS_ADAPTER', + help: 'Adapter module for the WebSocketServer', + action: parsers.moduleOrObjectParser, + }, }; module.exports.LiveQueryServerOptions = { - "appId": { - "env": "PARSE_LIVE_QUERY_SERVER_APP_ID", - "help": "This string should match the appId in use by your Parse Server. If you deploy the LiveQuery server alongside Parse Server, the LiveQuery server will try to use the same appId." - }, - "cacheTimeout": { - "env": "PARSE_LIVE_QUERY_SERVER_CACHE_TIMEOUT", - "help": "Number in milliseconds. When clients provide the sessionToken to the LiveQuery server, the LiveQuery server will try to fetch its ParseUser's objectId from parse server and store it in the cache. The value defines the duration of the cache. Check the following Security section and our protocol specification for details, defaults to 5 * 1000 ms (5 seconds).", - "action": parsers.numberParser("cacheTimeout") - }, - "keyPairs": { - "env": "PARSE_LIVE_QUERY_SERVER_KEY_PAIRS", - "help": "A JSON object that serves as a whitelist of keys. It is used for validating clients when they try to connect to the LiveQuery server. Check the following Security section and our protocol specification for details.", - "action": parsers.objectParser - }, - "logLevel": { - "env": "PARSE_LIVE_QUERY_SERVER_LOG_LEVEL", - "help": "This string defines the log level of the LiveQuery server. We support VERBOSE, INFO, ERROR, NONE, defaults to INFO." - }, - "masterKey": { - "env": "PARSE_LIVE_QUERY_SERVER_MASTER_KEY", - "help": "This string should match the masterKey in use by your Parse Server. If you deploy the LiveQuery server alongside Parse Server, the LiveQuery server will try to use the same masterKey." - }, - "port": { - "env": "PARSE_LIVE_QUERY_SERVER_PORT", - "help": "The port to run the LiveQuery server, defaults to 1337.", - "action": parsers.numberParser("port"), - "default": 1337 - }, - "pubSubAdapter": { - "env": "PARSE_LIVE_QUERY_SERVER_PUB_SUB_ADAPTER", - "help": "LiveQuery pubsub adapter", - "action": parsers.moduleOrObjectParser - }, - "redisOptions": { - "env": "PARSE_LIVE_QUERY_SERVER_REDIS_OPTIONS", - "help": "parse-server's LiveQuery redisOptions", - "action": parsers.objectParser - }, - "redisURL": { - "env": "PARSE_LIVE_QUERY_SERVER_REDIS_URL", - "help": "parse-server's LiveQuery redisURL" - }, - "serverURL": { - "env": "PARSE_LIVE_QUERY_SERVER_SERVER_URL", - "help": "This string should match the serverURL in use by your Parse Server. If you deploy the LiveQuery server alongside Parse Server, the LiveQuery server will try to use the same serverURL." - }, - "websocketTimeout": { - "env": "PARSE_LIVE_QUERY_SERVER_WEBSOCKET_TIMEOUT", - "help": "Number of milliseconds between ping/pong frames. The WebSocket server sends ping/pong frames to the clients to keep the WebSocket alive. This value defines the interval of the ping/pong frame from the server to clients, defaults to 10 * 1000 ms (10 s).", - "action": parsers.numberParser("websocketTimeout") - }, - "wssAdapter": { - "env": "PARSE_LIVE_QUERY_SERVER_WSS_ADAPTER", - "help": "Adapter module for the WebSocketServer", - "action": parsers.moduleOrObjectParser - } + appId: { + env: 'PARSE_LIVE_QUERY_SERVER_APP_ID', + help: + 'This string should match the appId in use by your Parse Server. If you deploy the LiveQuery server alongside Parse Server, the LiveQuery server will try to use the same appId.', + }, + cacheTimeout: { + env: 'PARSE_LIVE_QUERY_SERVER_CACHE_TIMEOUT', + help: + "Number in milliseconds. When clients provide the sessionToken to the LiveQuery server, the LiveQuery server will try to fetch its ParseUser's objectId from parse server and store it in the cache. The value defines the duration of the cache. Check the following Security section and our protocol specification for details, defaults to 5 * 1000 ms (5 seconds).", + action: parsers.numberParser('cacheTimeout'), + }, + keyPairs: { + env: 'PARSE_LIVE_QUERY_SERVER_KEY_PAIRS', + help: + 'A JSON object that serves as a whitelist of keys. It is used for validating clients when they try to connect to the LiveQuery server. Check the following Security section and our protocol specification for details.', + action: parsers.objectParser, + }, + logLevel: { + env: 'PARSE_LIVE_QUERY_SERVER_LOG_LEVEL', + help: + 'This string defines the log level of the LiveQuery server. We support VERBOSE, INFO, ERROR, NONE, defaults to INFO.', + }, + masterKey: { + env: 'PARSE_LIVE_QUERY_SERVER_MASTER_KEY', + help: + 'This string should match the masterKey in use by your Parse Server. If you deploy the LiveQuery server alongside Parse Server, the LiveQuery server will try to use the same masterKey.', + }, + port: { + env: 'PARSE_LIVE_QUERY_SERVER_PORT', + help: 'The port to run the LiveQuery server, defaults to 1337.', + action: parsers.numberParser('port'), + default: 1337, + }, + pubSubAdapter: { + env: 'PARSE_LIVE_QUERY_SERVER_PUB_SUB_ADAPTER', + help: 'LiveQuery pubsub adapter', + action: parsers.moduleOrObjectParser, + }, + redisOptions: { + env: 'PARSE_LIVE_QUERY_SERVER_REDIS_OPTIONS', + help: "parse-server's LiveQuery redisOptions", + action: parsers.objectParser, + }, + redisURL: { + env: 'PARSE_LIVE_QUERY_SERVER_REDIS_URL', + help: "parse-server's LiveQuery redisURL", + }, + serverURL: { + env: 'PARSE_LIVE_QUERY_SERVER_SERVER_URL', + help: + 'This string should match the serverURL in use by your Parse Server. If you deploy the LiveQuery server alongside Parse Server, the LiveQuery server will try to use the same serverURL.', + }, + websocketTimeout: { + env: 'PARSE_LIVE_QUERY_SERVER_WEBSOCKET_TIMEOUT', + help: + 'Number of milliseconds between ping/pong frames. The WebSocket server sends ping/pong frames to the clients to keep the WebSocket alive. This value defines the interval of the ping/pong frame from the server to clients, defaults to 10 * 1000 ms (10 s).', + action: parsers.numberParser('websocketTimeout'), + }, + wssAdapter: { + env: 'PARSE_LIVE_QUERY_SERVER_WSS_ADAPTER', + help: 'Adapter module for the WebSocketServer', + action: parsers.moduleOrObjectParser, + }, }; module.exports.IdempotencyOptions = { - "paths": { - "env": "PARSE_SERVER_EXPERIMENTAL_IDEMPOTENCY_PATHS", - "help": "An array of paths for which the feature should be enabled. The mount path must not be included, for example instead of `/parse/functions/myFunction` specifiy `functions/myFunction`. The entries are interpreted as regular expression, for example `functions/.*` matches all functions, `jobs/.*` matches all jobs, `classes/.*` matches all classes, `.*` matches all paths.", - "action": parsers.arrayParser, - "default": [] - }, - "ttl": { - "env": "PARSE_SERVER_EXPERIMENTAL_IDEMPOTENCY_TTL", - "help": "The duration in seconds after which a request record is discarded from the database, defaults to 300s.", - "action": parsers.numberParser("ttl"), - "default": 300 - } + paths: { + env: 'PARSE_SERVER_EXPERIMENTAL_IDEMPOTENCY_PATHS', + help: + 'An array of paths for which the feature should be enabled. The mount path must not be included, for example instead of `/parse/functions/myFunction` specifiy `functions/myFunction`. The entries are interpreted as regular expression, for example `functions/.*` matches all functions, `jobs/.*` matches all jobs, `classes/.*` matches all classes, `.*` matches all paths.', + action: parsers.arrayParser, + default: [], + }, + ttl: { + env: 'PARSE_SERVER_EXPERIMENTAL_IDEMPOTENCY_TTL', + help: + 'The duration in seconds after which a request record is discarded from the database, defaults to 300s.', + action: parsers.numberParser('ttl'), + default: 300, + }, }; module.exports.AccountLockoutOptions = { - "duration": { - "env": "PARSE_SERVER_ACCOUNT_LOCKOUT_DURATION", - "help": "number of minutes that a locked-out account remains locked out before automatically becoming unlocked.", - "action": parsers.numberParser("duration") - }, - "threshold": { - "env": "PARSE_SERVER_ACCOUNT_LOCKOUT_THRESHOLD", - "help": "number of failed sign-in attempts that will cause a user account to be locked", - "action": parsers.numberParser("threshold") - } + duration: { + env: 'PARSE_SERVER_ACCOUNT_LOCKOUT_DURATION', + help: + 'number of minutes that a locked-out account remains locked out before automatically becoming unlocked.', + action: parsers.numberParser('duration'), + }, + threshold: { + env: 'PARSE_SERVER_ACCOUNT_LOCKOUT_THRESHOLD', + help: 'number of failed sign-in attempts that will cause a user account to be locked', + action: parsers.numberParser('threshold'), + }, }; module.exports.PasswordPolicyOptions = { - "doNotAllowUsername": { - "env": "PARSE_SERVER_PASSWORD_POLICY_DO_NOT_ALLOW_USERNAME", - "help": "disallow username in passwords", - "action": parsers.booleanParser - }, - "maxPasswordAge": { - "env": "PARSE_SERVER_PASSWORD_POLICY_MAX_PASSWORD_AGE", - "help": "days for password expiry", - "action": parsers.numberParser("maxPasswordAge") - }, - "maxPasswordHistory": { - "env": "PARSE_SERVER_PASSWORD_POLICY_MAX_PASSWORD_HISTORY", - "help": "setting to prevent reuse of previous n passwords", - "action": parsers.numberParser("maxPasswordHistory") - }, - "resetTokenReuseIfValid": { - "env": "PARSE_SERVER_PASSWORD_POLICY_RESET_TOKEN_REUSE_IF_VALID", - "help": "resend token if it's still valid", - "action": parsers.booleanParser - }, - "resetTokenValidityDuration": { - "env": "PARSE_SERVER_PASSWORD_POLICY_RESET_TOKEN_VALIDITY_DURATION", - "help": "time for token to expire", - "action": parsers.numberParser("resetTokenValidityDuration") - }, - "validatorCallback": { - "env": "PARSE_SERVER_PASSWORD_POLICY_VALIDATOR_CALLBACK", - "help": "a callback function to be invoked to validate the password" - }, - "validatorPattern": { - "env": "PARSE_SERVER_PASSWORD_POLICY_VALIDATOR_PATTERN", - "help": "a RegExp object or a regex string representing the pattern to enforce" - } + doNotAllowUsername: { + env: 'PARSE_SERVER_PASSWORD_POLICY_DO_NOT_ALLOW_USERNAME', + help: 'disallow username in passwords', + action: parsers.booleanParser, + }, + maxPasswordAge: { + env: 'PARSE_SERVER_PASSWORD_POLICY_MAX_PASSWORD_AGE', + help: 'days for password expiry', + action: parsers.numberParser('maxPasswordAge'), + }, + maxPasswordHistory: { + env: 'PARSE_SERVER_PASSWORD_POLICY_MAX_PASSWORD_HISTORY', + help: 'setting to prevent reuse of previous n passwords', + action: parsers.numberParser('maxPasswordHistory'), + }, + resetTokenReuseIfValid: { + env: 'PARSE_SERVER_PASSWORD_POLICY_RESET_TOKEN_REUSE_IF_VALID', + help: "resend token if it's still valid", + action: parsers.booleanParser, + }, + resetTokenValidityDuration: { + env: 'PARSE_SERVER_PASSWORD_POLICY_RESET_TOKEN_VALIDITY_DURATION', + help: 'time for token to expire', + action: parsers.numberParser('resetTokenValidityDuration'), + }, + validatorCallback: { + env: 'PARSE_SERVER_PASSWORD_POLICY_VALIDATOR_CALLBACK', + help: 'a callback function to be invoked to validate the password', + }, + validatorPattern: { + env: 'PARSE_SERVER_PASSWORD_POLICY_VALIDATOR_PATTERN', + help: 'a RegExp object or a regex string representing the pattern to enforce', + }, }; module.exports.FileUploadOptions = { - "enableForAnonymousUser": { - "env": "PARSE_SERVER_FILE_UPLOAD_ENABLE_FOR_ANONYMOUS_USER", - "help": "Is true if file upload should be allowed for anonymous users.", - "action": parsers.booleanParser, - "default": false - }, - "enableForAuthenticatedUser": { - "env": "PARSE_SERVER_FILE_UPLOAD_ENABLE_FOR_AUTHENTICATED_USER", - "help": "Is true if file upload should be allowed for authenticated users.", - "action": parsers.booleanParser, - "default": true - }, - "enableForPublic": { - "env": "PARSE_SERVER_FILE_UPLOAD_ENABLE_FOR_PUBLIC", - "help": "Is true if file upload should be allowed for anyone, regardless of user authentication.", - "action": parsers.booleanParser, - "default": false - } + enableForAnonymousUser: { + env: 'PARSE_SERVER_FILE_UPLOAD_ENABLE_FOR_ANONYMOUS_USER', + help: 'Is true if file upload should be allowed for anonymous users.', + action: parsers.booleanParser, + default: false, + }, + enableForAuthenticatedUser: { + env: 'PARSE_SERVER_FILE_UPLOAD_ENABLE_FOR_AUTHENTICATED_USER', + help: 'Is true if file upload should be allowed for authenticated users.', + action: parsers.booleanParser, + default: true, + }, + enableForPublic: { + env: 'PARSE_SERVER_FILE_UPLOAD_ENABLE_FOR_PUBLIC', + help: 'Is true if file upload should be allowed for anyone, regardless of user authentication.', + action: parsers.booleanParser, + default: false, + }, }; diff --git a/src/Options/index.js b/src/Options/index.js index a72a3eade4..69cc705306 100644 --- a/src/Options/index.js +++ b/src/Options/index.js @@ -163,6 +163,10 @@ export interface ParseServerOptions { /* Sets the maximum size for the in memory cache, defaults to 10000 :DEFAULT: 10000 */ cacheMaxSize: ?number; + /* Replace HTTP Interface when using JS SDK in current node runtime, defaults to false. Caution, this is an experimental feature that may not be appropriate for production. + :ENV: PARSE_SERVER_ENABLE_EXPERIMENTAL_DIRECT_ACCESS + :DEFAULT: true */ + directAccess: ?boolean; /* Use a single schema cache shared across requests. Reduces number of queries made to _SCHEMA, defaults to false, i.e. unique schema cache per request. :DEFAULT: false */ enableSingleSchemaCache: ?boolean; diff --git a/src/ParseServer.js b/src/ParseServer.js index 9e0f371d9b..c8b0b1dbaa 100644 --- a/src/ParseServer.js +++ b/src/ParseServer.js @@ -134,7 +134,7 @@ class ParseServer { * @static * Create an express app for the parse server * @param {Object} options let you specify the maxUploadSize when creating the express app */ - static app({ maxUploadSize = '20mb', appId }) { + static app({ maxUploadSize = '20mb', appId, directAccess }) { // This app serves the Parse API directly. // It's the equivalent of https://api.parse.com/1 in the hosted Parse API. var api = express(); @@ -184,9 +184,9 @@ class ParseServer { ParseServer.verifyServerUrl(); }); } - - // Replace HTTP Interface when using JS SDK in current node runtime - Parse.CoreManager.setRESTController(ParseServerRESTController(appId, appRouter)); + if (process.env.PARSE_SERVER_ENABLE_EXPERIMENTAL_DIRECT_ACCESS === '1' || directAccess) { + Parse.CoreManager.setRESTController(ParseServerRESTController(appId, appRouter)); + } return api; } From 27992ad3f559947c6d910218b717034e4530e169 Mon Sep 17 00:00:00 2001 From: Diamond Lewis Date: Fri, 8 Jan 2021 18:33:09 -0600 Subject: [PATCH 08/19] rerun tests --- src/ParseServer.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/ParseServer.js b/src/ParseServer.js index c8b0b1dbaa..a607ec15eb 100644 --- a/src/ParseServer.js +++ b/src/ParseServer.js @@ -187,7 +187,6 @@ class ParseServer { if (process.env.PARSE_SERVER_ENABLE_EXPERIMENTAL_DIRECT_ACCESS === '1' || directAccess) { Parse.CoreManager.setRESTController(ParseServerRESTController(appId, appRouter)); } - return api; } From 21422f45f1548ebddddd1c4ccbc03a94b4994429 Mon Sep 17 00:00:00 2001 From: Diamond Lewis Date: Fri, 8 Jan 2021 21:43:07 -0600 Subject: [PATCH 09/19] remove extra parse instance --- spec/ParseAPI.spec.js | 33 +++++-------------- spec/helper.js | 1 - spec/testing-routes.js | 72 ------------------------------------------ 3 files changed, 8 insertions(+), 98 deletions(-) delete mode 100644 spec/testing-routes.js diff --git a/spec/ParseAPI.spec.js b/spec/ParseAPI.spec.js index 0a8c147592..39aed06206 100644 --- a/spec/ParseAPI.spec.js +++ b/spec/ParseAPI.spec.js @@ -24,31 +24,14 @@ const headers = { }; describe_only_db('mongo')('miscellaneous', () => { - it('test rest_create_app', function (done) { - let appId; - Parse._request('POST', 'rest_create_app') - .then(res => { - expect(typeof res.application_id).toEqual('string'); - expect(res.master_key).toEqual('master'); - appId = res.application_id; - Parse.initialize(appId, 'unused'); - const obj = new Parse.Object('TestObject'); - obj.set('foo', 'bar'); - return obj.save(); - }) - .then(() => { - const config = Config.get(appId); - return config.database.adapter.find('TestObject', { fields: {} }, {}, {}); - }) - .then(results => { - expect(results.length).toEqual(1); - expect(results[0]['foo']).toEqual('bar'); - done(); - }) - .catch(error => { - fail(JSON.stringify(error)); - done(); - }); + it('db contains document after successful save', async () => { + const obj = new Parse.Object('TestObject'); + obj.set('foo', 'bar'); + await obj.save(); + const config = Config.get(defaultConfiguration.appId); + const results = await config.database.adapter.find('TestObject', { fields: {} }, {}, {}); + expect(results.length).toEqual(1); + expect(results[0]['foo']).toEqual('bar'); }); }); diff --git a/spec/helper.js b/spec/helper.js index 5c90c76f02..ab9294e493 100644 --- a/spec/helper.js +++ b/spec/helper.js @@ -143,7 +143,6 @@ const reconfigureServer = changedConfiguration => { }); cache.clear(); parseServer = ParseServer.start(newConfiguration); - parseServer.app.use(require('./testing-routes').router); parseServer.expressApp.use('/1', err => { console.error(err); fail('should not call next'); diff --git a/spec/testing-routes.js b/spec/testing-routes.js deleted file mode 100644 index 4cf626bc66..0000000000 --- a/spec/testing-routes.js +++ /dev/null @@ -1,72 +0,0 @@ -// testing-routes.js -const AppCache = require('../lib/cache').default; -const middlewares = require('../lib/middlewares'); -const { ParseServer } = require('../lib/index'); -const { Parse } = require('parse/node'); - -const express = require('express'), - cryptoUtils = require('../lib/cryptoUtils'); - -const router = express.Router(); - -// creates a unique app in the cache, with a collection prefix -function createApp(req, res) { - const appId = cryptoUtils.randomHexString(32); - - ParseServer({ - databaseURI: 'mongodb://localhost:27017/parseServerMongoAdapterTestDatabase', - appId: appId, - masterKey: 'master', - serverURL: Parse.serverURL, - collectionPrefix: appId, - }); - const keys = { - application_id: appId, - client_key: 'unused', - windows_key: 'unused', - javascript_key: 'unused', - webhook_key: 'unused', - rest_api_key: 'unused', - master_key: 'master', - }; - res.status(200).send(keys); -} - -// deletes all collections that belong to the app -function clearApp(req, res) { - if (!req.auth.isMaster) { - return res.status(401).send({ error: 'unauthorized' }); - } - return req.config.database.deleteEverything().then(() => { - res.status(200).send({}); - }); -} - -// deletes all collections and drops the app from cache -function dropApp(req, res) { - if (!req.auth.isMaster) { - return res.status(401).send({ error: 'unauthorized' }); - } - return req.config.database.deleteEverything().then(() => { - AppCache.del(req.config.applicationId); - res.status(200).send({}); - }); -} - -// Lets just return a success response and see what happens. -function notImplementedYet(req, res) { - res.status(200).send({}); -} - -router.post('/rest_clear_app', middlewares.handleParseHeaders, clearApp); -router.post('/rest_block', middlewares.handleParseHeaders, notImplementedYet); -router.post('/rest_mock_v8_client', middlewares.handleParseHeaders, notImplementedYet); -router.post('/rest_unmock_v8_client', middlewares.handleParseHeaders, notImplementedYet); -router.post('/rest_verify_analytics', middlewares.handleParseHeaders, notImplementedYet); -router.post('/rest_create_app', createApp); -router.post('/rest_drop_app', middlewares.handleParseHeaders, dropApp); -router.post('/rest_configure_app', middlewares.handleParseHeaders, notImplementedYet); - -module.exports = { - router: router, -}; From 11db4aa069ad956167bff2180241b5a1cd15c380 Mon Sep 17 00:00:00 2001 From: Diamond Lewis Date: Fri, 8 Jan 2021 22:44:32 -0600 Subject: [PATCH 10/19] Revert "remove extra parse instance" This reverts commit 21422f45f1548ebddddd1c4ccbc03a94b4994429. --- spec/ParseAPI.spec.js | 33 ++++++++++++++----- spec/helper.js | 1 + spec/testing-routes.js | 72 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 98 insertions(+), 8 deletions(-) create mode 100644 spec/testing-routes.js diff --git a/spec/ParseAPI.spec.js b/spec/ParseAPI.spec.js index 39aed06206..0a8c147592 100644 --- a/spec/ParseAPI.spec.js +++ b/spec/ParseAPI.spec.js @@ -24,14 +24,31 @@ const headers = { }; describe_only_db('mongo')('miscellaneous', () => { - it('db contains document after successful save', async () => { - const obj = new Parse.Object('TestObject'); - obj.set('foo', 'bar'); - await obj.save(); - const config = Config.get(defaultConfiguration.appId); - const results = await config.database.adapter.find('TestObject', { fields: {} }, {}, {}); - expect(results.length).toEqual(1); - expect(results[0]['foo']).toEqual('bar'); + it('test rest_create_app', function (done) { + let appId; + Parse._request('POST', 'rest_create_app') + .then(res => { + expect(typeof res.application_id).toEqual('string'); + expect(res.master_key).toEqual('master'); + appId = res.application_id; + Parse.initialize(appId, 'unused'); + const obj = new Parse.Object('TestObject'); + obj.set('foo', 'bar'); + return obj.save(); + }) + .then(() => { + const config = Config.get(appId); + return config.database.adapter.find('TestObject', { fields: {} }, {}, {}); + }) + .then(results => { + expect(results.length).toEqual(1); + expect(results[0]['foo']).toEqual('bar'); + done(); + }) + .catch(error => { + fail(JSON.stringify(error)); + done(); + }); }); }); diff --git a/spec/helper.js b/spec/helper.js index ab9294e493..5c90c76f02 100644 --- a/spec/helper.js +++ b/spec/helper.js @@ -143,6 +143,7 @@ const reconfigureServer = changedConfiguration => { }); cache.clear(); parseServer = ParseServer.start(newConfiguration); + parseServer.app.use(require('./testing-routes').router); parseServer.expressApp.use('/1', err => { console.error(err); fail('should not call next'); diff --git a/spec/testing-routes.js b/spec/testing-routes.js new file mode 100644 index 0000000000..4cf626bc66 --- /dev/null +++ b/spec/testing-routes.js @@ -0,0 +1,72 @@ +// testing-routes.js +const AppCache = require('../lib/cache').default; +const middlewares = require('../lib/middlewares'); +const { ParseServer } = require('../lib/index'); +const { Parse } = require('parse/node'); + +const express = require('express'), + cryptoUtils = require('../lib/cryptoUtils'); + +const router = express.Router(); + +// creates a unique app in the cache, with a collection prefix +function createApp(req, res) { + const appId = cryptoUtils.randomHexString(32); + + ParseServer({ + databaseURI: 'mongodb://localhost:27017/parseServerMongoAdapterTestDatabase', + appId: appId, + masterKey: 'master', + serverURL: Parse.serverURL, + collectionPrefix: appId, + }); + const keys = { + application_id: appId, + client_key: 'unused', + windows_key: 'unused', + javascript_key: 'unused', + webhook_key: 'unused', + rest_api_key: 'unused', + master_key: 'master', + }; + res.status(200).send(keys); +} + +// deletes all collections that belong to the app +function clearApp(req, res) { + if (!req.auth.isMaster) { + return res.status(401).send({ error: 'unauthorized' }); + } + return req.config.database.deleteEverything().then(() => { + res.status(200).send({}); + }); +} + +// deletes all collections and drops the app from cache +function dropApp(req, res) { + if (!req.auth.isMaster) { + return res.status(401).send({ error: 'unauthorized' }); + } + return req.config.database.deleteEverything().then(() => { + AppCache.del(req.config.applicationId); + res.status(200).send({}); + }); +} + +// Lets just return a success response and see what happens. +function notImplementedYet(req, res) { + res.status(200).send({}); +} + +router.post('/rest_clear_app', middlewares.handleParseHeaders, clearApp); +router.post('/rest_block', middlewares.handleParseHeaders, notImplementedYet); +router.post('/rest_mock_v8_client', middlewares.handleParseHeaders, notImplementedYet); +router.post('/rest_unmock_v8_client', middlewares.handleParseHeaders, notImplementedYet); +router.post('/rest_verify_analytics', middlewares.handleParseHeaders, notImplementedYet); +router.post('/rest_create_app', createApp); +router.post('/rest_drop_app', middlewares.handleParseHeaders, dropApp); +router.post('/rest_configure_app', middlewares.handleParseHeaders, notImplementedYet); + +module.exports = { + router: router, +}; From f38c052a99be2a668199d8da9cc09e7db5284aca Mon Sep 17 00:00:00 2001 From: Diamond Lewis Date: Fri, 8 Jan 2021 22:46:13 -0600 Subject: [PATCH 11/19] Ensure restcontroller is set --- spec/helper.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/spec/helper.js b/spec/helper.js index 5c90c76f02..43b8eefbd4 100644 --- a/spec/helper.js +++ b/spec/helper.js @@ -30,6 +30,7 @@ const PostgresStorageAdapter = require('../lib/Adapters/Storage/Postgres/Postgre .default; const MongoStorageAdapter = require('../lib/Adapters/Storage/Mongo/MongoStorageAdapter').default; const RedisCacheAdapter = require('../lib/Adapters/Cache/RedisCacheAdapter').default; +const RESTController = require('parse/lib/node/RESTController'); const mongoURI = 'mongodb://localhost:27017/parseServerMongoAdapterTestDatabase'; const postgresURI = 'postgres://localhost:5432/parse_server_postgres_adapter_test_database'; @@ -135,6 +136,7 @@ const reconfigureServer = changedConfiguration => { if (error) { reject(error); } else { + Parse.CoreManager.setRESTController(RESTController); resolve(parseServer); } }, From 153771f3e43741071d39a2ab874db8908d64f7d0 Mon Sep 17 00:00:00 2001 From: Diamond Lewis Date: Fri, 8 Jan 2021 22:58:07 -0600 Subject: [PATCH 12/19] Fix test --- spec/index.spec.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/index.spec.js b/spec/index.spec.js index 1b542926c1..75c5b691ae 100644 --- a/spec/index.spec.js +++ b/spec/index.spec.js @@ -496,7 +496,7 @@ describe('server', () => { await reconfigureServer({ directAccess: true, }); - expect(spy).toHaveBeenCalledTimes(1); + expect(spy).toHaveBeenCalledTimes(2); Parse.CoreManager.setRESTController(RESTController); }); From dd94086724a2f4070d90d5c13eb32f90cf06a0b1 Mon Sep 17 00:00:00 2001 From: Manuel Trezza <5673677+mtrezza@users.noreply.github.com> Date: Fri, 19 Mar 2021 02:01:25 +0100 Subject: [PATCH 13/19] improved option docs --- src/Options/Definitions.js | 4 ++-- src/Options/docs.js | 2 +- src/Options/index.js | 8 ++++++-- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/src/Options/Definitions.js b/src/Options/Definitions.js index 211c990e2b..7c68d26450 100644 --- a/src/Options/Definitions.js +++ b/src/Options/Definitions.js @@ -112,9 +112,9 @@ module.exports.ParseServerOptions = { directAccess: { env: 'PARSE_SERVER_ENABLE_EXPERIMENTAL_DIRECT_ACCESS', help: - 'Replace HTTP Interface when using JS SDK in current node runtime, defaults to false. Caution, this is an experimental feature that may not be appropriate for production.', + 'Set to `true` if Parse requests within the same Node.js environment as Parse Server should be routed to Parse Server directly instead of via the HTTP interface. Default is `false`.

If set to `false` then Parse requests within the same Node.js environment as Parse Server are executed as a HTTP requests to Parse Server via the `serverURL`. For example, a `Parse.Query` in Cloud Code is calling Parse Server via a HTTP request. The server is essentially making a HTTP request to itself, unnecessarily using network resources such as network ports.

\u26A0\uFE0F In environments where multiple Parse Server instances run behind a load balancer and Parse requests within the current Node.js environment should be routed via the load balancer and distributed as HTTP requests among all instances via the `serverURL`, this should be set to `false`.', action: parsers.booleanParser, - default: true, + default: false, }, dotNetKey: { env: 'PARSE_SERVER_DOT_NET_KEY', diff --git a/src/Options/docs.js b/src/Options/docs.js index dccf436d8c..7ca1bc74d9 100644 --- a/src/Options/docs.js +++ b/src/Options/docs.js @@ -20,7 +20,7 @@ * @property {Adapter} databaseAdapter Adapter module for the database * @property {DatabaseOptions} databaseOptions Options to pass to the database client * @property {String} databaseURI The full URI to your database. Supported databases are mongodb or postgres. - * @property {Boolean} directAccess Replace HTTP Interface when using JS SDK in current node runtime, defaults to false. Caution, this is an experimental feature that may not be appropriate for production. + * @property {Boolean} directAccess Set to `true` if Parse requests within the same Node.js environment as Parse Server should be routed to Parse Server directly instead of via the HTTP interface. Default is `false`.

If set to `false` then Parse requests within the same Node.js environment as Parse Server are executed as a HTTP requests to Parse Server via the `serverURL`. For example, a `Parse.Query` in Cloud Code is calling Parse Server via a HTTP request. The server is essentially making a HTTP request to itself, unnecessarily using network resources such as network ports.

⚠️ In environments where multiple Parse Server instances run behind a load balancer and Parse requests within the current Node.js environment should be routed via the load balancer and distributed as HTTP requests among all instances via the `serverURL`, this should be set to `false`. * @property {String} dotNetKey Key for Unity and .Net SDK * @property {Adapter} emailAdapter Adapter module for email sending * @property {Boolean} emailVerifyTokenReuseIfValid an existing email verify token should be reused when resend verification email is requested diff --git a/src/Options/index.js b/src/Options/index.js index e067f526e8..8fa32a9754 100644 --- a/src/Options/index.js +++ b/src/Options/index.js @@ -165,9 +165,13 @@ export interface ParseServerOptions { /* Sets the maximum size for the in memory cache, defaults to 10000 :DEFAULT: 10000 */ cacheMaxSize: ?number; - /* Replace HTTP Interface when using JS SDK in current node runtime, defaults to false. Caution, this is an experimental feature that may not be appropriate for production. + /* Set to `true` if Parse requests within the same Node.js environment as Parse Server should be routed to Parse Server directly instead of via the HTTP interface. Default is `false`. +

+ If set to `false` then Parse requests within the same Node.js environment as Parse Server are executed as a HTTP requests to Parse Server via the `serverURL`. For example, a `Parse.Query` in Cloud Code is calling Parse Server via a HTTP request. The server is essentially making a HTTP request to itself, unnecessarily using network resources such as network ports. +

+ ⚠️ In environments where multiple Parse Server instances run behind a load balancer and Parse requests within the current Node.js environment should be routed via the load balancer and distributed as HTTP requests among all instances via the `serverURL`, this should be set to `false`. :ENV: PARSE_SERVER_ENABLE_EXPERIMENTAL_DIRECT_ACCESS - :DEFAULT: true */ + :DEFAULT: false */ directAccess: ?boolean; /* Enables the default express error handler for all errors :DEFAULT: false */ From a1d10b1d057c9b682e93504ab5c620add772499d Mon Sep 17 00:00:00 2001 From: Manuel Trezza <5673677+mtrezza@users.noreply.github.com> Date: Mon, 29 Mar 2021 02:41:23 +0200 Subject: [PATCH 14/19] renamed direct access env var --- src/Options/Definitions.js | 2 +- src/Options/index.js | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Options/Definitions.js b/src/Options/Definitions.js index 7c68d26450..765eacfdcf 100644 --- a/src/Options/Definitions.js +++ b/src/Options/Definitions.js @@ -110,7 +110,7 @@ module.exports.ParseServerOptions = { default: 'mongodb://localhost:27017/parse', }, directAccess: { - env: 'PARSE_SERVER_ENABLE_EXPERIMENTAL_DIRECT_ACCESS', + env: 'PARSE_SERVER_DIRECT_ACCESS', help: 'Set to `true` if Parse requests within the same Node.js environment as Parse Server should be routed to Parse Server directly instead of via the HTTP interface. Default is `false`.

If set to `false` then Parse requests within the same Node.js environment as Parse Server are executed as a HTTP requests to Parse Server via the `serverURL`. For example, a `Parse.Query` in Cloud Code is calling Parse Server via a HTTP request. The server is essentially making a HTTP request to itself, unnecessarily using network resources such as network ports.

\u26A0\uFE0F In environments where multiple Parse Server instances run behind a load balancer and Parse requests within the current Node.js environment should be routed via the load balancer and distributed as HTTP requests among all instances via the `serverURL`, this should be set to `false`.', action: parsers.booleanParser, diff --git a/src/Options/index.js b/src/Options/index.js index 8fa32a9754..23503c39ed 100644 --- a/src/Options/index.js +++ b/src/Options/index.js @@ -170,7 +170,6 @@ export interface ParseServerOptions { If set to `false` then Parse requests within the same Node.js environment as Parse Server are executed as a HTTP requests to Parse Server via the `serverURL`. For example, a `Parse.Query` in Cloud Code is calling Parse Server via a HTTP request. The server is essentially making a HTTP request to itself, unnecessarily using network resources such as network ports.

⚠️ In environments where multiple Parse Server instances run behind a load balancer and Parse requests within the current Node.js environment should be routed via the load balancer and distributed as HTTP requests among all instances via the `serverURL`, this should be set to `false`. - :ENV: PARSE_SERVER_ENABLE_EXPERIMENTAL_DIRECT_ACCESS :DEFAULT: false */ directAccess: ?boolean; /* Enables the default express error handler for all errors From def122ffe5be72b99f050be471c626bc84263e58 Mon Sep 17 00:00:00 2001 From: Manuel Trezza <5673677+mtrezza@users.noreply.github.com> Date: Wed, 31 Mar 2021 00:15:12 +0200 Subject: [PATCH 15/19] added deprecations to README --- README.md | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 3f9ed6ffd2..54099f5793 100644 --- a/README.md +++ b/README.md @@ -75,6 +75,7 @@ The full documentation for Parse Server is available in the [wiki](https://githu - [Reserved Keys](#reserved-keys) - [Parameters](#parameters-1) - [Logging](#logging) +- [Deprecations](#deprecations) - [Live Query](#live-query) - [GraphQL](#graphql) - [Running](#running) @@ -115,7 +116,7 @@ Parse Server is continuously tested with the most recent releases of Node.js to | Node.js 10 | 10.24.0 | April 2021 | ✅ Fully compatible | | Node.js 12 | 12.21.0 | April 2022 | ✅ Fully compatible | | Node.js 14 | 14.16.0 | April 2023 | ✅ Fully compatible | -| Node.js 15 | 15.12.0 | June 2021 | ✅ Fully compatible | +| Node.js 15 | 15.12.0 | June 2021 | ✅ Fully compatible | #### MongoDB Parse Server is continuously tested with the most recent releases of MongoDB to ensure compatibility. We follow the [MongoDB support schedule](https://www.mongodb.com/support-policy) and only test against versions that are officially supported and have not reached their end-of-life date. @@ -755,6 +756,14 @@ Logs are also viewable in Parse Dashboard. **Want new line delimited JSON error logs (for consumption by CloudWatch, Google Cloud Logging, etc)?** Pass the `JSON_LOGS` environment variable when starting `parse-server`. Usage :- `JSON_LOGS='1' parse-server --appId APPLICATION_ID --masterKey MASTER_KEY` +# Deprecations + +The following Parse Server options and APIs are deprecated and will change in future versions. The "Deprecation" version indicates from when an item has been deprecated with runtime warnings. The "End-of-Life" version indicates when the deprecation period has ended and the breaking change came into effect. In rare cases, deprecations may be revoked without any breaking change coming into effect. + +| Type | Item | Deprecation | End-of-Life | Details | +|--------|----------------|-------------|-------------|-----------------------------------------| +| Option | `directAccess` | `5.0.0` | tbd | Default changes from `false` to `true`. | + # Live Query Live queries are meant to be used in real-time reactive applications, where just using the traditional query paradigm could cause several problems, like increased response time and high network and server usage. Live queries should be used in cases where you need to continuously update a page with fresh data coming from the database, which often happens in (but is not limited to) online games, messaging clients and shared to-do lists. From 8edff335bf5d6c6c65f9bdddc9c9264dca4d828d Mon Sep 17 00:00:00 2001 From: Manuel Trezza <5673677+mtrezza@users.noreply.github.com> Date: Wed, 31 Mar 2021 00:15:26 +0200 Subject: [PATCH 16/19] added deprecation definition --- src/Deprecator/Deprecations.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Deprecator/Deprecations.js b/src/Deprecator/Deprecations.js index 5c7cc3630f..f75adcaf49 100644 --- a/src/Deprecator/Deprecations.js +++ b/src/Deprecator/Deprecations.js @@ -11,4 +11,4 @@ * * If there are no deprecations this must return an empty array anyway. */ -module.exports = []; +module.exports = [{ optionKey: 'directAccess', changeNewDefault: 'true' }]; From e9f124e94a0257f2f691b8c994affb78fd4dab5c Mon Sep 17 00:00:00 2001 From: Manuel Trezza <5673677+mtrezza@users.noreply.github.com> Date: Wed, 31 Mar 2021 00:21:39 +0200 Subject: [PATCH 17/19] fixed docs typo --- src/Options/Definitions.js | 2 +- src/Options/docs.js | 2 +- src/Options/index.js | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Options/Definitions.js b/src/Options/Definitions.js index 765eacfdcf..dff37662bb 100644 --- a/src/Options/Definitions.js +++ b/src/Options/Definitions.js @@ -112,7 +112,7 @@ module.exports.ParseServerOptions = { directAccess: { env: 'PARSE_SERVER_DIRECT_ACCESS', help: - 'Set to `true` if Parse requests within the same Node.js environment as Parse Server should be routed to Parse Server directly instead of via the HTTP interface. Default is `false`.

If set to `false` then Parse requests within the same Node.js environment as Parse Server are executed as a HTTP requests to Parse Server via the `serverURL`. For example, a `Parse.Query` in Cloud Code is calling Parse Server via a HTTP request. The server is essentially making a HTTP request to itself, unnecessarily using network resources such as network ports.

\u26A0\uFE0F In environments where multiple Parse Server instances run behind a load balancer and Parse requests within the current Node.js environment should be routed via the load balancer and distributed as HTTP requests among all instances via the `serverURL`, this should be set to `false`.', + 'Set to `true` if Parse requests within the same Node.js environment as Parse Server should be routed to Parse Server directly instead of via the HTTP interface. Default is `false`.

If set to `false` then Parse requests within the same Node.js environment as Parse Server are executed as HTTP requests sent to Parse Server via the `serverURL`. For example, a `Parse.Query` in Cloud Code is calling Parse Server via a HTTP request. The server is essentially making a HTTP request to itself, unnecessarily using network resources such as network ports.

\u26A0\uFE0F In environments where multiple Parse Server instances run behind a load balancer and Parse requests within the current Node.js environment should be routed via the load balancer and distributed as HTTP requests among all instances via the `serverURL`, this should be set to `false`.', action: parsers.booleanParser, default: false, }, diff --git a/src/Options/docs.js b/src/Options/docs.js index 7ca1bc74d9..c58339f06d 100644 --- a/src/Options/docs.js +++ b/src/Options/docs.js @@ -20,7 +20,7 @@ * @property {Adapter} databaseAdapter Adapter module for the database * @property {DatabaseOptions} databaseOptions Options to pass to the database client * @property {String} databaseURI The full URI to your database. Supported databases are mongodb or postgres. - * @property {Boolean} directAccess Set to `true` if Parse requests within the same Node.js environment as Parse Server should be routed to Parse Server directly instead of via the HTTP interface. Default is `false`.

If set to `false` then Parse requests within the same Node.js environment as Parse Server are executed as a HTTP requests to Parse Server via the `serverURL`. For example, a `Parse.Query` in Cloud Code is calling Parse Server via a HTTP request. The server is essentially making a HTTP request to itself, unnecessarily using network resources such as network ports.

⚠️ In environments where multiple Parse Server instances run behind a load balancer and Parse requests within the current Node.js environment should be routed via the load balancer and distributed as HTTP requests among all instances via the `serverURL`, this should be set to `false`. + * @property {Boolean} directAccess Set to `true` if Parse requests within the same Node.js environment as Parse Server should be routed to Parse Server directly instead of via the HTTP interface. Default is `false`.

If set to `false` then Parse requests within the same Node.js environment as Parse Server are executed as HTTP requests sent to Parse Server via the `serverURL`. For example, a `Parse.Query` in Cloud Code is calling Parse Server via a HTTP request. The server is essentially making a HTTP request to itself, unnecessarily using network resources such as network ports.

⚠️ In environments where multiple Parse Server instances run behind a load balancer and Parse requests within the current Node.js environment should be routed via the load balancer and distributed as HTTP requests among all instances via the `serverURL`, this should be set to `false`. * @property {String} dotNetKey Key for Unity and .Net SDK * @property {Adapter} emailAdapter Adapter module for email sending * @property {Boolean} emailVerifyTokenReuseIfValid an existing email verify token should be reused when resend verification email is requested diff --git a/src/Options/index.js b/src/Options/index.js index 23503c39ed..bd32855e8d 100644 --- a/src/Options/index.js +++ b/src/Options/index.js @@ -167,7 +167,7 @@ export interface ParseServerOptions { cacheMaxSize: ?number; /* Set to `true` if Parse requests within the same Node.js environment as Parse Server should be routed to Parse Server directly instead of via the HTTP interface. Default is `false`.

- If set to `false` then Parse requests within the same Node.js environment as Parse Server are executed as a HTTP requests to Parse Server via the `serverURL`. For example, a `Parse.Query` in Cloud Code is calling Parse Server via a HTTP request. The server is essentially making a HTTP request to itself, unnecessarily using network resources such as network ports. + If set to `false` then Parse requests within the same Node.js environment as Parse Server are executed as HTTP requests sent to Parse Server via the `serverURL`. For example, a `Parse.Query` in Cloud Code is calling Parse Server via a HTTP request. The server is essentially making a HTTP request to itself, unnecessarily using network resources such as network ports.

⚠️ In environments where multiple Parse Server instances run behind a load balancer and Parse requests within the current Node.js environment should be routed via the load balancer and distributed as HTTP requests among all instances via the `serverURL`, this should be set to `false`. :DEFAULT: false */ From 563a0a88a5aa7c6b2843efa097e9bf30bef988fe Mon Sep 17 00:00:00 2001 From: Manuel Trezza <5673677+mtrezza@users.noreply.github.com> Date: Wed, 31 Mar 2021 00:41:29 +0200 Subject: [PATCH 18/19] improve promise rejection warning test --- spec/ParseServer.spec.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/ParseServer.spec.js b/spec/ParseServer.spec.js index 904e0b164e..fcb15f643f 100644 --- a/spec/ParseServer.spec.js +++ b/spec/ParseServer.spec.js @@ -107,7 +107,7 @@ describe('Server Url Checks', () => { }); parseServerProcess.on('close', async code => { expect(code).toEqual(1); - expect(stdout).toBeUndefined(); + expect(stdout).not.toContain('UnhandledPromiseRejectionWarning'); expect(stderr).toContain('MongoServerSelectionError'); await reconfigureServer(); done(); From 40ff567109bd3732c51d859911baa333c98c9102 Mon Sep 17 00:00:00 2001 From: Manuel Trezza <5673677+mtrezza@users.noreply.github.com> Date: Wed, 31 Mar 2021 01:38:08 +0200 Subject: [PATCH 19/19] added renaming of env var to deprecation warning --- src/Deprecator/Deprecations.js | 15 +++++++++++++-- src/Deprecator/Deprecator.js | 3 ++- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/src/Deprecator/Deprecations.js b/src/Deprecator/Deprecations.js index f75adcaf49..e32b305fb0 100644 --- a/src/Deprecator/Deprecations.js +++ b/src/Deprecator/Deprecations.js @@ -8,7 +8,18 @@ * or set to an empty string if the current key will be removed without replacement. * - `changeNewDefault`: Set the new default value if the key's default value * will change in a future version. + * - `solution`: The instruction to resolve this deprecation warning. Optional. This + * instruction must not include the deprecation warning which is auto-generated. + * It should only contain additional instruction regarding the deprecation if + * necessary. * - * If there are no deprecations this must return an empty array anyway. + * If there are no deprecations, this must return an empty array. */ -module.exports = [{ optionKey: 'directAccess', changeNewDefault: 'true' }]; +module.exports = [ + { + optionKey: 'directAccess', + changeNewDefault: 'true', + solution: + "Additionally, the environment variable 'PARSE_SERVER_ENABLE_EXPERIMENTAL_DIRECT_ACCESS' will be deprecated and renamed to 'PARSE_SERVER_DIRECT_ACCESS' in a future version; it is currently possible to use either one.", + }, +]; diff --git a/src/Deprecator/Deprecator.js b/src/Deprecator/Deprecator.js index 53036fcb1f..5ab0bb43ee 100644 --- a/src/Deprecator/Deprecator.js +++ b/src/Deprecator/Deprecator.js @@ -16,12 +16,13 @@ class Deprecator { // Scan for deprecations for (const deprecation of Deprecator._getDeprecations()) { // Get deprecation properties + const solution = deprecation.solution; const optionKey = deprecation.optionKey; const changeNewDefault = deprecation.changeNewDefault; // If default will change, only throw a warning if option is not set if (changeNewDefault != null && options[optionKey] == null) { - Deprecator._log({ optionKey, changeNewDefault }); + Deprecator._log({ optionKey, changeNewDefault, solution }); } } }