From 1b686cd5a89b1a6fbe6f2a941b56dc81625d7beb Mon Sep 17 00:00:00 2001 From: Manuel Trezza <5673677+mtrezza@users.noreply.github.com> Date: Wed, 24 Feb 2021 12:32:52 +0100 Subject: [PATCH 1/5] improved contribution guide for parameter groups --- CONTRIBUTING.md | 12 ++++--- resources/buildConfigDefinitions.js | 54 +++++++++++++++++++---------- 2 files changed, 42 insertions(+), 24 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index a761f91955..fe6bdeed14 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -275,11 +275,13 @@ Introducing new Parse Errors requires the following steps: Introducing new [Parse Server configuration][config] parameters requires the following steps: 1. Add parameters definitions in [/src/Options/index.js][config-index]. -1. If a nested configuration object has been added, add the environment variable option prefix to `getENVPrefix` in [/resources/buildConfigDefinition.js](https://github.com/parse-community/parse-server/blob/master/resources/buildConfigDefinition.js). -1. Execute `npm run definitions` to automatically create the definitions in [/src/Options/Definitions.js][config-def] and [/src/Options/docs.js][config-docs]. -1. Add parameter value validation in [/src/Config.js](https://github.com/parse-community/parse-server/blob/master/src/Config.js). -1. Add test cases to ensure the correct parameter value validation. Parse Server throws an error at launch if an invalid value is set for any configuration parameter. -1. Execute `npm run docs` to generate the documentation in the `/out` directory. Take a look at the documentation whether the description and formatting of the newly introduced parameters is satisfactory. +2. If a parameter group (nested parameter) has been added: + - add the environment variable prefix for the parameter group to `nestedOptionEnvPrefix` in [/resources/buildConfigDefinition.js](https://github.com/parse-community/parse-server/blob/master/resources/buildConfigDefinition.js) + - add the parameter group type to `nestedOptionTypes` in [/resources/buildConfigDefinition.js](https://github.com/parse-community/parse-server/blob/master/resources/buildConfigDefinition.js) +3. Execute `npm run definitions` to automatically create the definitions in [/src/Options/Definitions.js][config-def] and [/src/Options/docs.js][config-docs]. +4. Add parameter value validation in [/src/Config.js](https://github.com/parse-community/parse-server/blob/master/src/Config.js). +5. Add test cases to ensure the correct parameter value validation. Parse Server throws an error at launch if an invalid value is set for any configuration parameter. +6. Execute `npm run docs` to generate the documentation in the `/out` directory. Take a look at the documentation whether the description and formatting of the newly introduced parameters is satisfactory. ## Code of Conduct diff --git a/resources/buildConfigDefinitions.js b/resources/buildConfigDefinitions.js index ef4994af47..52ff3ac7a8 100644 --- a/resources/buildConfigDefinitions.js +++ b/resources/buildConfigDefinitions.js @@ -11,6 +11,37 @@ */ const parsers = require('../src/Options/parsers'); +/** The types of nested options. */ +const nestedOptionTypes = [ + 'CustomPagesOptions', + 'DatabaseOptions', + 'FileUploadOptions', + 'IdempotencyOptions', + 'Object', + 'PagesCustomUrlsOptions', + 'PagesOptions', + 'PagesRoute', + 'PasswordPolicyOptions', + 'SecurityOptions', +]; + +/** The prefix of environment variables for nested options. */ +const nestedOptionEnvPrefix = { + 'AccountLockoutOptions' : 'PARSE_SERVER_ACCOUNT_LOCKOUT_', + 'CustomPagesOptions' : 'PARSE_SERVER_CUSTOM_PAGES_', + 'DatabaseOptions': 'PARSE_SERVER_DATABASE_', + 'FileUploadOptions' : 'PARSE_SERVER_FILE_UPLOAD_', + 'IdempotencyOptions' : 'PARSE_SERVER_EXPERIMENTAL_IDEMPOTENCY_', + 'LiveQueryOptions' : 'PARSE_SERVER_LIVEQUERY_', + 'LiveQueryServerOptions' : 'PARSE_LIVE_QUERY_SERVER_', + 'PagesCustomUrlsOptions' : 'PARSE_SERVER_PAGES_CUSTOM_URL_', + 'PagesOptions' : 'PARSE_SERVER_PAGES_', + 'PagesRoute': 'PARSE_SERVER_PAGES_ROUTE_', + 'ParseServerOptions' : 'PARSE_SERVER_', + 'PasswordPolicyOptions' : 'PARSE_SERVER_PASSWORD_POLICY_', + 'SecurityOptions': 'PARSE_SERVER_SECURITY_', +}; + function last(array) { return array[array.length - 1]; } @@ -40,23 +71,8 @@ function getCommentValue(comment) { } function getENVPrefix(iface) { - const options = { - 'ParseServerOptions' : 'PARSE_SERVER_', - 'PagesOptions' : 'PARSE_SERVER_PAGES_', - 'PagesRoute': 'PARSE_SERVER_PAGES_ROUTE_', - 'PagesCustomUrlsOptions' : 'PARSE_SERVER_PAGES_CUSTOM_URL_', - 'CustomPagesOptions' : 'PARSE_SERVER_CUSTOM_PAGES_', - 'LiveQueryServerOptions' : 'PARSE_LIVE_QUERY_SERVER_', - 'LiveQueryOptions' : 'PARSE_SERVER_LIVEQUERY_', - 'IdempotencyOptions' : 'PARSE_SERVER_EXPERIMENTAL_IDEMPOTENCY_', - 'AccountLockoutOptions' : 'PARSE_SERVER_ACCOUNT_LOCKOUT_', - 'PasswordPolicyOptions' : 'PARSE_SERVER_PASSWORD_POLICY_', - 'FileUploadOptions' : 'PARSE_SERVER_FILE_UPLOAD_', - 'SecurityOptions': 'PARSE_SERVER_SECURITY_', - 'DatabaseOptions': 'PARSE_SERVER_DATABASE_' - } - if (options[iface.id.name]) { - return options[iface.id.name] + if (nestedOptionEnvPrefix[iface.id.name]) { + return nestedOptionEnvPrefix[iface.id.name] } } @@ -169,8 +185,8 @@ function parseDefaultValue(elt, value, t) { if (type == 'NumberOrBoolean') { literalValue = t.numericLiteral(parsers.numberOrBoolParser('')(value)); } - const literalTypes = ['Object', 'SecurityOptions', 'PagesRoute', 'IdempotencyOptions','FileUploadOptions','CustomPagesOptions', 'PagesCustomUrlsOptions', 'PagesOptions', 'DatabaseOptions']; - if (literalTypes.includes(type)) { + + if (nestedOptionTypes.includes(type)) { const object = parsers.objectParser(value); const props = Object.keys(object).map((key) => { return t.objectProperty(key, object[value]); From 52e531ede83644423a091d696de74253ed2b18e9 Mon Sep 17 00:00:00 2001 From: Manuel Trezza <5673677+mtrezza@users.noreply.github.com> Date: Wed, 24 Feb 2021 12:54:19 +0100 Subject: [PATCH 2/5] improved resetTokenReuseIfValid docs --- src/Options/Definitions.js | 4 ++++ src/Options/docs.js | 10 ++++++++++ 2 files changed, 14 insertions(+) diff --git a/src/Options/Definitions.js b/src/Options/Definitions.js index 65799f8191..13d33f97f9 100644 --- a/src/Options/Definitions.js +++ b/src/Options/Definitions.js @@ -746,7 +746,11 @@ module.exports.PasswordPolicyOptions = { resetTokenReuseIfValid: { env: 'PARSE_SERVER_PASSWORD_POLICY_RESET_TOKEN_REUSE_IF_VALID', help: +<<<<<<< HEAD 'Set to `true` if a password reset token should be reused in case another token is requested but there is a token that is still valid, i.e. has not expired. This avoids the often observed issue that a user requests multiple emails and does not know which link contains a valid token because each newly generated token would invalidate the previous token.

Default is `false`.', +======= + 'Reuse password reset token if it has not expired; requires `resetTokenValidityDuration` to be set. Default is `false`.', +>>>>>>> improved resetTokenReuseIfValid docs action: parsers.booleanParser, default: false, }, diff --git a/src/Options/docs.js b/src/Options/docs.js index 30b3aba1a0..5bff82cd03 100644 --- a/src/Options/docs.js +++ b/src/Options/docs.js @@ -173,6 +173,7 @@ /** * @interface PasswordPolicyOptions +<<<<<<< HEAD * @property {Boolean} doNotAllowUsername Set to `true` to disallow the username as part of the password.

Default is `false`. * @property {Number} maxPasswordAge Set the number of days after which a password expires. Login attempts fail if the user does not reset the password before expiration. * @property {Number} maxPasswordHistory Set the number of previous password that will not be allowed to be set as new password. If the option is not set or set to `0`, no previous passwords will be considered.

Valid values are >= `0` and <= `20`.
Default is `0`. @@ -181,6 +182,15 @@ * @property {String} validationError Set the error message to be sent.

Default is `Password does not meet the Password Policy requirements.` * @property {Function} validatorCallback Set a callback function to validate a password to be accepted.

If used in combination with `validatorPattern`, the password must pass both to be accepted. * @property {String} validatorPattern Set the regular expression validation pattern a password must match to be accepted.

If used in combination with `validatorCallback`, the password must pass both to be accepted. +======= + * @property {Boolean} doNotAllowUsername disallow username in passwords + * @property {Number} maxPasswordAge days for password expiry + * @property {Number} maxPasswordHistory setting to prevent reuse of previous n passwords + * @property {Boolean} resetTokenReuseIfValid Reuse password reset token if it has not expired; requires `resetTokenValidityDuration` to be set. Default is `false`. + * @property {Number} resetTokenValidityDuration time for token to expire + * @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 +>>>>>>> improved resetTokenReuseIfValid docs */ /** From 6a13cb20bb94963fbe4281477ab9ca43ea77685b Mon Sep 17 00:00:00 2001 From: Manuel Trezza <5673677+mtrezza@users.noreply.github.com> Date: Wed, 24 Feb 2021 13:05:17 +0100 Subject: [PATCH 3/5] improved resetTokenValidityDuration docs --- src/Options/Definitions.js | 8 ++++++++ src/Options/docs.js | 4 ++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/Options/Definitions.js b/src/Options/Definitions.js index 13d33f97f9..bdcbdd3b30 100644 --- a/src/Options/Definitions.js +++ b/src/Options/Definitions.js @@ -746,18 +746,26 @@ module.exports.PasswordPolicyOptions = { resetTokenReuseIfValid: { env: 'PARSE_SERVER_PASSWORD_POLICY_RESET_TOKEN_REUSE_IF_VALID', help: +<<<<<<< HEAD <<<<<<< HEAD 'Set to `true` if a password reset token should be reused in case another token is requested but there is a token that is still valid, i.e. has not expired. This avoids the often observed issue that a user requests multiple emails and does not know which link contains a valid token because each newly generated token would invalidate the previous token.

Default is `false`.', ======= 'Reuse password reset token if it has not expired; requires `resetTokenValidityDuration` to be set. Default is `false`.', >>>>>>> improved resetTokenReuseIfValid docs +======= + 'Is true if the password reset token should be reused if it has not expired; requires `resetTokenValidityDuration` to be set. Default is `false`.', +>>>>>>> improved resetTokenValidityDuration docs action: parsers.booleanParser, default: false, }, resetTokenValidityDuration: { env: 'PARSE_SERVER_PASSWORD_POLICY_RESET_TOKEN_VALIDITY_DURATION', help: +<<<<<<< HEAD 'Set the validity duration of the password reset token in seconds after which the token expires. The token is used in the link that is set in the email. After the token expires, the link becomes invalid and a new link has to be sent. If the option is not set or set to `undefined`, then the token never expires.

For example, to expire the token after 2 hours, set a value of 7200 seconds (= 60 seconds * 60 minutes * 2 hours).

Default is `undefined`.', +======= + 'The time duration in seconds after which a password reset token expires and becomes invalid. Default is indefinite (never expires).', +>>>>>>> improved resetTokenValidityDuration docs action: parsers.numberParser('resetTokenValidityDuration'), }, validationError: { diff --git a/src/Options/docs.js b/src/Options/docs.js index 5bff82cd03..a6c1d827a5 100644 --- a/src/Options/docs.js +++ b/src/Options/docs.js @@ -186,8 +186,8 @@ * @property {Boolean} doNotAllowUsername disallow username in passwords * @property {Number} maxPasswordAge days for password expiry * @property {Number} maxPasswordHistory setting to prevent reuse of previous n passwords - * @property {Boolean} resetTokenReuseIfValid Reuse password reset token if it has not expired; requires `resetTokenValidityDuration` to be set. Default is `false`. - * @property {Number} resetTokenValidityDuration time for token to expire + * @property {Boolean} resetTokenReuseIfValid Is true if the password reset token should be reused if it has not expired; requires `resetTokenValidityDuration` to be set. Default is `false`. + * @property {Number} resetTokenValidityDuration The time duration in seconds after which a password reset token expires and becomes invalid. Default is indefinite (never expires). * @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 >>>>>>> improved resetTokenReuseIfValid docs From 7fc548fb893623e0c1b13575bae2b4f0758773e8 Mon Sep 17 00:00:00 2001 From: Manuel Trezza <5673677+mtrezza@users.noreply.github.com> Date: Sun, 2 May 2021 21:05:55 +0200 Subject: [PATCH 4/5] recreated definitions --- src/Options/Definitions.js | 12 ------------ src/Options/docs.js | 10 ---------- 2 files changed, 22 deletions(-) diff --git a/src/Options/Definitions.js b/src/Options/Definitions.js index bdcbdd3b30..65799f8191 100644 --- a/src/Options/Definitions.js +++ b/src/Options/Definitions.js @@ -746,26 +746,14 @@ module.exports.PasswordPolicyOptions = { resetTokenReuseIfValid: { env: 'PARSE_SERVER_PASSWORD_POLICY_RESET_TOKEN_REUSE_IF_VALID', help: -<<<<<<< HEAD -<<<<<<< HEAD 'Set to `true` if a password reset token should be reused in case another token is requested but there is a token that is still valid, i.e. has not expired. This avoids the often observed issue that a user requests multiple emails and does not know which link contains a valid token because each newly generated token would invalidate the previous token.

Default is `false`.', -======= - 'Reuse password reset token if it has not expired; requires `resetTokenValidityDuration` to be set. Default is `false`.', ->>>>>>> improved resetTokenReuseIfValid docs -======= - 'Is true if the password reset token should be reused if it has not expired; requires `resetTokenValidityDuration` to be set. Default is `false`.', ->>>>>>> improved resetTokenValidityDuration docs action: parsers.booleanParser, default: false, }, resetTokenValidityDuration: { env: 'PARSE_SERVER_PASSWORD_POLICY_RESET_TOKEN_VALIDITY_DURATION', help: -<<<<<<< HEAD 'Set the validity duration of the password reset token in seconds after which the token expires. The token is used in the link that is set in the email. After the token expires, the link becomes invalid and a new link has to be sent. If the option is not set or set to `undefined`, then the token never expires.

For example, to expire the token after 2 hours, set a value of 7200 seconds (= 60 seconds * 60 minutes * 2 hours).

Default is `undefined`.', -======= - 'The time duration in seconds after which a password reset token expires and becomes invalid. Default is indefinite (never expires).', ->>>>>>> improved resetTokenValidityDuration docs action: parsers.numberParser('resetTokenValidityDuration'), }, validationError: { diff --git a/src/Options/docs.js b/src/Options/docs.js index a6c1d827a5..30b3aba1a0 100644 --- a/src/Options/docs.js +++ b/src/Options/docs.js @@ -173,7 +173,6 @@ /** * @interface PasswordPolicyOptions -<<<<<<< HEAD * @property {Boolean} doNotAllowUsername Set to `true` to disallow the username as part of the password.

Default is `false`. * @property {Number} maxPasswordAge Set the number of days after which a password expires. Login attempts fail if the user does not reset the password before expiration. * @property {Number} maxPasswordHistory Set the number of previous password that will not be allowed to be set as new password. If the option is not set or set to `0`, no previous passwords will be considered.

Valid values are >= `0` and <= `20`.
Default is `0`. @@ -182,15 +181,6 @@ * @property {String} validationError Set the error message to be sent.

Default is `Password does not meet the Password Policy requirements.` * @property {Function} validatorCallback Set a callback function to validate a password to be accepted.

If used in combination with `validatorPattern`, the password must pass both to be accepted. * @property {String} validatorPattern Set the regular expression validation pattern a password must match to be accepted.

If used in combination with `validatorCallback`, the password must pass both to be accepted. -======= - * @property {Boolean} doNotAllowUsername disallow username in passwords - * @property {Number} maxPasswordAge days for password expiry - * @property {Number} maxPasswordHistory setting to prevent reuse of previous n passwords - * @property {Boolean} resetTokenReuseIfValid Is true if the password reset token should be reused if it has not expired; requires `resetTokenValidityDuration` to be set. Default is `false`. - * @property {Number} resetTokenValidityDuration The time duration in seconds after which a password reset token expires and becomes invalid. Default is indefinite (never expires). - * @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 ->>>>>>> improved resetTokenReuseIfValid docs */ /** From afa8b3ee0931ba6007ad018c65c422b4ac984ae3 Mon Sep 17 00:00:00 2001 From: Manuel Trezza <5673677+mtrezza@users.noreply.github.com> Date: Mon, 26 Jul 2021 22:06:06 +0200 Subject: [PATCH 5/5] improved parameter group wording --- CONTRIBUTING.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 5cf90567d9..c082ee271b 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -277,9 +277,12 @@ Introducing new Parse Errors requires the following steps: Introducing new [Parse Server configuration][config] parameters requires the following steps: 1. Add parameters definitions in [/src/Options/index.js][config-index]. -2. If a parameter group (nested parameter) has been added: +2. If the new parameter does not have one single value but is a parameter group (an object containing multiple sub-parameters): - add the environment variable prefix for the parameter group to `nestedOptionEnvPrefix` in [/resources/buildConfigDefinition.js](https://github.com/parse-community/parse-server/blob/master/resources/buildConfigDefinition.js) - add the parameter group type to `nestedOptionTypes` in [/resources/buildConfigDefinition.js](https://github.com/parse-community/parse-server/blob/master/resources/buildConfigDefinition.js) + + For example, take a look at the existing Parse Server `security` parameter. It is a parameter group, because it has multiple sub-parameter such as `checkGroups`. Its interface is defined in [index.js][config-index] as `export interface SecurityOptions`. Therefore, the value to add to `nestedOptionTypes` would be `SecurityOptions`, the value to add to `nestedOptionEnvPrefix` would be `PARSE_SERVER_SECURITY_`. + 3. Execute `npm run definitions` to automatically create the definitions in [/src/Options/Definitions.js][config-def] and [/src/Options/docs.js][config-docs]. 4. Add parameter value validation in [/src/Config.js](https://github.com/parse-community/parse-server/blob/master/src/Config.js). 5. Add test cases to ensure the correct parameter value validation. Parse Server throws an error at launch if an invalid value is set for any configuration parameter.