From e634eba57c7a760308353262bee418d0ab4f1acd Mon Sep 17 00:00:00 2001 From: dblythy Date: Fri, 4 Dec 2020 08:03:29 +1100 Subject: [PATCH] fix: definitions for accountLockout and passwordPolicy (#7040) * fix: definitions for accountLockout and passwordPolicy * redo env prefix --- resources/buildConfigDefinitions.js | 23 ++++++------- src/Options/Definitions.js | 51 +++++++++++++++++++++++++++-- src/Options/docs.js | 21 ++++++++++-- src/Options/index.js | 28 ++++++++++++++-- 4 files changed, 104 insertions(+), 19 deletions(-) diff --git a/resources/buildConfigDefinitions.js b/resources/buildConfigDefinitions.js index a640e1c3..99b57b13 100644 --- a/resources/buildConfigDefinitions.js +++ b/resources/buildConfigDefinitions.js @@ -40,20 +40,17 @@ function getCommentValue(comment) { } function getENVPrefix(iface) { - if (iface.id.name === 'ParseServerOptions') { - return 'PARSE_SERVER_'; + const options = { + 'ParseServerOptions' : 'PARSE_SERVER_', + '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_' } - if (iface.id.name === 'CustomPagesOptions') { - return 'PARSE_SERVER_CUSTOM_PAGES_'; - } - if (iface.id.name === 'LiveQueryServerOptions') { - return 'PARSE_LIVE_QUERY_SERVER_'; - } - if (iface.id.name === 'LiveQueryOptions') { - return 'PARSE_SERVER_LIVEQUERY_'; - } - if (iface.id.name === 'IdempotencyOptions') { - return 'PARSE_SERVER_EXPERIMENTAL_IDEMPOTENCY_'; + if (options[iface.id.name]) { + return options[iface.id.name] } } diff --git a/src/Options/Definitions.js b/src/Options/Definitions.js index 69123741..a615db60 100644 --- a/src/Options/Definitions.js +++ b/src/Options/Definitions.js @@ -127,8 +127,7 @@ module.exports.ParseServerOptions = { }, 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', + help: 'an existing email verify token should be reused when resend verification email is requested', action: parsers.booleanParser, default: false, }, @@ -552,3 +551,51 @@ module.exports.IdempotencyOptions = { 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'), + }, +}; +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', + }, +}; diff --git a/src/Options/docs.js b/src/Options/docs.js index 03fd3eb4..576ff60a 100644 --- a/src/Options/docs.js +++ b/src/Options/docs.js @@ -1,6 +1,6 @@ /** * @interface ParseServerOptions - * @property {Any} accountLockout account lockout policy for failed login attempts + * @property {AccountLockoutOptions} accountLockout account lockout policy for failed login attempts * @property {Boolean} allowClientClassCreation Enable (or disable) client class creation, defaults to true * @property {Boolean} allowCustomObjectId Enable (or disable) custom objectId * @property {String[]} allowHeaders Add headers to Access-Control-Allow-Headers @@ -53,7 +53,7 @@ * @property {String} mountPath Mount path for the server, defaults to /parse * @property {Boolean} mountPlayground Mounts the GraphQL Playground - never use this option in production * @property {Number} objectIdSize Sets the number of characters in generated object id's, default 10 - * @property {Any} passwordPolicy Password policy for enforcing password related rules + * @property {PasswordPolicyOptions} passwordPolicy Password policy for enforcing password related rules * @property {String} playgroundPath Mount path for the GraphQL Playground, defaults to /playground * @property {Number} port The port to run the ParseServer, defaults to 1337. * @property {Boolean} preserveFileName Enable (or disable) the addition of a unique hash to the file names @@ -120,3 +120,20 @@ * @property {String[]} paths 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. * @property {Number} ttl The duration in seconds after which a request record is discarded from the database, defaults to 300s. */ + +/** + * @interface AccountLockoutOptions + * @property {Number} duration number of minutes that a locked-out account remains locked out before automatically becoming unlocked. + * @property {Number} threshold number of failed sign-in attempts that will cause a user account to be locked + */ + +/** + * @interface PasswordPolicyOptions + * @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 resend token if it's still valid + * @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 + */ diff --git a/src/Options/index.js b/src/Options/index.js index b83e51af..d2237e08 100644 --- a/src/Options/index.js +++ b/src/Options/index.js @@ -128,9 +128,9 @@ export interface ParseServerOptions { :DEFAULT: false */ emailVerifyTokenReuseIfValid: ?boolean; /* account lockout policy for failed login attempts */ - accountLockout: ?any; + accountLockout: ?AccountLockoutOptions; /* Password policy for enforcing password related rules */ - passwordPolicy: ?any; + passwordPolicy: ?PasswordPolicyOptions; /* Adapter module for the cache */ cacheAdapter: ?Adapter; /* Adapter module for email sending */ @@ -291,3 +291,27 @@ export interface IdempotencyOptions { :DEFAULT: 300 */ ttl: ?number; } + +export interface AccountLockoutOptions { + /* number of minutes that a locked-out account remains locked out before automatically becoming unlocked. */ + duration: ?number; + /* number of failed sign-in attempts that will cause a user account to be locked */ + threshold: ?number; +} + +export interface PasswordPolicyOptions { + /* a RegExp object or a regex string representing the pattern to enforce */ + validatorPattern: ?string; + /* a callback function to be invoked to validate the password */ + validatorCallback: ?() => void; + /* disallow username in passwords */ + doNotAllowUsername: ?boolean; + /* days for password expiry */ + maxPasswordAge: ?number; + /* setting to prevent reuse of previous n passwords */ + maxPasswordHistory: ?number; + /* time for token to expire */ + resetTokenValidityDuration: ?number; + /* resend token if it's still valid */ + resetTokenReuseIfValid: ?boolean; +}