diff --git a/packages/accounts-base/accounts_common.js b/packages/accounts-base/accounts_common.js index 37ec282985..14f34fadda 100644 --- a/packages/accounts-base/accounts_common.js +++ b/packages/accounts-base/accounts_common.js @@ -213,19 +213,20 @@ export class AccountsCommon { } } - // The options argument is only used by tests. - _getTokenLifetimeMs(options) { - options = options || this._options; - if (options.loginExpirationInDays === null) { - // We disable login expiration by returning Infinity - return Infinity; - } - return (options.loginExpirationInDays || - DEFAULT_LOGIN_EXPIRATION_DAYS) * 24 * 60 * 60 * 1000; + _getTokenLifetimeMs() { + // When loginExpirationInDays is set to null, we'll use a really high + // number of days (LOGIN_UNEXPIRABLE_TOKEN_DAYS) to simulate an + // unexpiring token. + const loginExpirationInDays = + (this._options.loginExpirationInDays === null) + ? LOGIN_UNEXPIRING_TOKEN_DAYS + : this._options.loginExpirationInDays; + return (loginExpirationInDays + || DEFAULT_LOGIN_EXPIRATION_DAYS) * 24 * 60 * 60 * 1000; } _getPasswordResetTokenLifetimeMs() { - return (this._options.passwordResetTokenExpirationInDays || + return (this._options.passwordResetTokenExpirationInDays || DEFAULT_PASSWORD_RESET_TOKEN_EXPIRATION_DAYS) * 24 * 60 * 60 * 1000; } @@ -273,7 +274,10 @@ Meteor.user = function () { }; // how long (in days) until a login token expires -var DEFAULT_LOGIN_EXPIRATION_DAYS = 90; +const DEFAULT_LOGIN_EXPIRATION_DAYS = 90; +// Expose for testing. +Ap.DEFAULT_LOGIN_EXPIRATION_DAYS = DEFAULT_LOGIN_EXPIRATION_DAYS; + // how long (in days) until reset password token expires var DEFAULT_PASSWORD_RESET_TOKEN_EXPIRATION_DAYS = 3; // how long (in days) until enrol password token expires @@ -288,6 +292,12 @@ EXPIRE_TOKENS_INTERVAL_MS = 600 * 1000; // 10 minutes // called CONNECTION_CLOSE_DELAY_MS = 10 * 1000; +// A large number of expiration days (approximately 100 years worth) that is +// used when creating unexpiring tokens. +const LOGIN_UNEXPIRING_TOKEN_DAYS = 365 * 100; +// Expose for testing. +Ap.LOGIN_UNEXPIRING_TOKEN_DAYS = LOGIN_UNEXPIRING_TOKEN_DAYS; + // loginServiceConfiguration and ConfigError are maintained for backwards compatibility Meteor.startup(function () { var ServiceConfiguration = diff --git a/packages/accounts-base/accounts_tests.js b/packages/accounts-base/accounts_tests.js index c12144c830..90daa73c4e 100644 --- a/packages/accounts-base/accounts_tests.js +++ b/packages/accounts-base/accounts_tests.js @@ -13,23 +13,49 @@ Tinytest.add('accounts - config validates keys', function (test) { }); }); -// test the loginExpirationInDays config - -Tinytest.add( 'accounts - config - token limetime', function (test) { - var config = { loginExpirationInDays: 2 }; - test.equal(Accounts._getTokenLifetimeMs(config), 2 * 24 * 60 * 60 * 1000); +Tinytest.add('accounts - config - token lifetime', function (test) { + const loginExpirationInDays = Accounts._options.loginExpirationInDays; + Accounts._options.loginExpirationInDays = 2; + test.equal(Accounts._getTokenLifetimeMs(), 2 * 24 * 60 * 60 * 1000); + Accounts._options.loginExpirationInDays = loginExpirationInDays; }); -Tinytest.add( 'accounts - config - unexpiring tokens', function (test) { - var config = { loginExpirationInDays: null }; - test.equal(Accounts._getTokenLifetimeMs(config), Infinity); +Tinytest.add('accounts - config - unexpiring tokens', function (test) { + const loginExpirationInDays = Accounts._options.loginExpirationInDays; + + // When setting loginExpirationInDays to null in the global Accounts + // config object, make sure the returned token lifetime represents an + // unexpiring token date (is very far into the future). + Accounts._options.loginExpirationInDays = null; + test.equal( + Accounts._getTokenLifetimeMs(), + Accounts.LOGIN_UNEXPIRING_TOKEN_DAYS * 24 * 60 * 60 * 1000, + ); + + // Verify token expiration date retrieval returns a Date. + // (verifies https://github.com/meteor/meteor/issues/9066) + test.isTrue( + !isNaN(Accounts._tokenExpiration(new Date())), + 'Returned token expiration should be a Date', + ); + + // Verify the token expiration check works properly. + // (verifies https://github.com/meteor/meteor/issues/9066) + const futureDate = new Date(); + futureDate.setDate(futureDate.getDate() + 200); + test.isFalse(Accounts._tokenExpiresSoon(futureDate)); + + Accounts._options.loginExpirationInDays = loginExpirationInDays; }); -Tinytest.add( 'accounts - config - default token limetime', function(test) { - var DEFAULT_LOGIN_EXPIRATION_DAYS = 90; // copied from accounts_common.js - var config1 = {}; - var config2 = { loginExpirationInDays: DEFAULT_LOGIN_EXPIRATION_DAYS }; - test.equal(Accounts._getTokenLifetimeMs(config1), Accounts._getTokenLifetimeMs(config2)); +Tinytest.add('accounts - config - default token lifetime', function (test) { + const options = Accounts._options; + Accounts._options = {}; + test.equal( + Accounts._getTokenLifetimeMs(), + Accounts.DEFAULT_LOGIN_EXPIRATION_DAYS * 24 * 60 * 60 * 1000, + ); + Accounts._options = options; }); var idsInValidateNewUser = {};