From fb036875289619ae878dd25b7e3015e35053f6ed Mon Sep 17 00:00:00 2001 From: djmaze Date: Mon, 1 Mar 2021 00:52:46 +0100 Subject: [PATCH] Revamp Issue #51 to make the whole "change password" thing a plugin --- dev/Common/Enums.js | 5 - dev/Knoin/Knoin.js | 1 + dev/Remote/User/Fetch.js | 12 -- dev/Screen/User/Settings.js | 10 -- dev/Settings/User/ChangePassword.js | 90 -------------- .../ChangePasswordExampleDriver.php | 36 ------ plugins/change-password-example/index.php | 49 -------- .../LICENSE | 2 +- plugins/change-password/index.php | 76 ++++++++++++ .../js/ChangePasswordUserSettings.js | 110 ++++++++++++++++++ plugins/change-password/langs/en.ini | 12 ++ .../templates}/SettingsChangePassword.html | 0 .../0.0.0/app/libraries/RainLoop/Actions.php | 3 - .../app/libraries/RainLoop/Notifications.php | 5 - .../RainLoop/Providers/ChangePassword.php | 71 ----------- .../ChangePasswordInterface.php | 10 -- .../app/libraries/RainLoop/ServiceActions.php | 12 +- 17 files changed, 207 insertions(+), 297 deletions(-) delete mode 100644 dev/Settings/User/ChangePassword.js delete mode 100644 plugins/change-password-example/ChangePasswordExampleDriver.php delete mode 100644 plugins/change-password-example/index.php rename plugins/{change-password-example => change-password}/LICENSE (96%) create mode 100644 plugins/change-password/index.php create mode 100644 plugins/change-password/js/ChangePasswordUserSettings.js create mode 100644 plugins/change-password/langs/en.ini rename {snappymail/v/0.0.0/app/templates/Views/User => plugins/change-password/templates}/SettingsChangePassword.html (100%) delete mode 100644 snappymail/v/0.0.0/app/libraries/RainLoop/Providers/ChangePassword.php delete mode 100644 snappymail/v/0.0.0/app/libraries/RainLoop/Providers/ChangePassword/ChangePasswordInterface.php diff --git a/dev/Common/Enums.js b/dev/Common/Enums.js index 916ed3aaf..3a0606d3f 100644 --- a/dev/Common/Enums.js +++ b/dev/Common/Enums.js @@ -98,11 +98,6 @@ export const Notification = { AccountTwoFactorAuthRequired: 120, AccountTwoFactorAuthError: 121, - CouldNotSaveNewPassword: 130, - CurrentPasswordIncorrect: 131, - NewPasswordShort: 132, - NewPasswordWeak: 133, - ContactsSyncError: 140, CantGetMessageList: 201, diff --git a/dev/Knoin/Knoin.js b/dev/Knoin/Knoin.js index 11a883e71..49cda365d 100644 --- a/dev/Knoin/Knoin.js +++ b/dev/Knoin/Knoin.js @@ -337,6 +337,7 @@ function decorateKoCommands(thisArg, commands) { thisArg[key] = fn; }); } +ko.decorateCommands = decorateKoCommands; /** * @param {miced} $items diff --git a/dev/Remote/User/Fetch.js b/dev/Remote/User/Fetch.js index 936a2d7eb..f04325b8d 100644 --- a/dev/Remote/User/Fetch.js +++ b/dev/Remote/User/Fetch.js @@ -594,18 +594,6 @@ class RemoteUserFetch extends AbstractFetchRemote { }; } - /** - * @param {?Function} fCallback - * @param {string} prevPassword - * @param {string} newPassword - */ - changePassword(fCallback, prevPassword, newPassword) { - this.defaultRequest(fCallback, 'ChangePassword', { - 'PrevPassword': prevPassword, - 'NewPassword': newPassword - }); - } - /** * @param {?Function} fCallback * @param {string} sFolderFullNameRaw diff --git a/dev/Screen/User/Settings.js b/dev/Screen/User/Settings.js index 918c067a9..75bf6c026 100644 --- a/dev/Screen/User/Settings.js +++ b/dev/Screen/User/Settings.js @@ -18,7 +18,6 @@ import { TemplatesUserSettings } from 'Settings/User/Templates'; import { FoldersUserSettings } from 'Settings/User/Folders'; import { ThemesUserSettings } from 'Settings/User/Themes'; import { OpenPgpUserSettings } from 'Settings/User/OpenPgp'; -import { ChangePasswordUserSettings } from 'Settings/User/ChangePassword'; import { SystemDropDownSettingsUserView } from 'View/User/Settings/SystemDropDown'; import { MenuSettingsUserView } from 'View/User/Settings/Menu'; @@ -78,15 +77,6 @@ export class SettingsUserScreen extends AbstractSettingsScreen { ); } - if (Settings.get('ChangePasswordIsAllowed')) { - settingsAddViewModel( - ChangePasswordUserSettings, - 'SettingsChangePassword', - 'GLOBAL/PASSWORD', - 'change-password' - ); - } - if (Settings.capa(Capa.Folders)) { settingsAddViewModel(FoldersUserSettings, 'SettingsFolders', 'SETTINGS_LABELS/LABEL_FOLDERS_NAME', 'folders'); } diff --git a/dev/Settings/User/ChangePassword.js b/dev/Settings/User/ChangePassword.js deleted file mode 100644 index 4ab2bac95..000000000 --- a/dev/Settings/User/ChangePassword.js +++ /dev/null @@ -1,90 +0,0 @@ -import ko from 'ko'; - -import { StorageResultType, Notification } from 'Common/Enums'; -import { getNotificationFromResponse, i18n } from 'Common/Translator'; -import { Settings } from 'Common/Globals'; - -import Remote from 'Remote/User/Fetch'; - -import { decorateKoCommands } from 'Knoin/Knoin'; - -export class ChangePasswordUserSettings { - constructor() { - ko.addObservablesTo(this, { - changeProcess: false, - - errorDescription: '', - passwordMismatch: false, - passwordUpdateError: false, - passwordUpdateSuccess: false, - - currentPassword: '', - currentPasswordError: false, - newPassword: '', - newPassword2: '', - }); - - this.currentPassword.subscribe(() => this.resetUpdate(true)); - this.newPassword.subscribe(() => this.resetUpdate()); - this.newPassword2.subscribe(() => this.resetUpdate()); - - decorateKoCommands(this, { - saveNewPasswordCommand: self => !self.changeProcess() - && '' !== self.currentPassword() - && '' !== self.newPassword() - && '' !== self.newPassword2() - }); - } - - saveNewPasswordCommand() { - if (this.newPassword() !== this.newPassword2()) { - this.passwordMismatch(true); - this.errorDescription(i18n('SETTINGS_CHANGE_PASSWORD/ERROR_PASSWORD_MISMATCH')); - } else { - this.reset(true); - Remote.changePassword(this.onChangePasswordResponse.bind(this), this.currentPassword(), this.newPassword()); - } - } - - reset(change) { - this.changeProcess(change); - this.resetUpdate(); - this.currentPasswordError(false); - this.errorDescription(''); - } - - resetUpdate(current) { - this.passwordUpdateError(false); - this.passwordUpdateSuccess(false); - current ? this.currentPasswordError(false) : this.passwordMismatch(false); - } - - onHide() { - this.reset(false); - this.currentPassword(''); - this.newPassword(''); - this.newPassword2(''); - } - - onChangePasswordResponse(result, data) { - this.reset(false); - - if (StorageResultType.Success === result && data && data.Result) { - this.currentPassword(''); - this.newPassword(''); - this.newPassword2(''); - - this.passwordUpdateSuccess(true); - - rl.hash.set(); - Settings.set('AuthAccountHash', data.Result); - } else { - if (data && Notification.CurrentPasswordIncorrect === data.ErrorCode) { - this.currentPasswordError(true); - } - - this.passwordUpdateError(true); - this.errorDescription(getNotificationFromResponse(data, Notification.CouldNotSaveNewPassword)); - } - } -} diff --git a/plugins/change-password-example/ChangePasswordExampleDriver.php b/plugins/change-password-example/ChangePasswordExampleDriver.php deleted file mode 100644 index 884a31932..000000000 --- a/plugins/change-password-example/ChangePasswordExampleDriver.php +++ /dev/null @@ -1,36 +0,0 @@ -sAllowedEmails = $sAllowedEmails; - return $this; - } - - public function isPossible(\RainLoop\Model\Account $oAccount) : bool - { - $sFoundedValue = ''; - return $oAccount && $oAccount->Email() && - \RainLoop\Plugins\Helper::ValidateWildcardValues($oAccount->Email(), $this->sAllowedEmails, $sFoundedValue); - } - - public function ChangePassword(\RainLoop\Model\Account $oAccount, string $sPrevPassword, string $sNewPassword) : bool - { - $bResult = false; - - // TODO - - return $bResult; - } -} diff --git a/plugins/change-password-example/index.php b/plugins/change-password-example/index.php deleted file mode 100644 index 1f3f2783e..000000000 --- a/plugins/change-password-example/index.php +++ /dev/null @@ -1,49 +0,0 @@ -addHook('main.fabrica', 'MainFabrica'); - } - - /** - * @param string $sName - * @param mixed $oProvider - */ - public function MainFabrica($sName, &$oProvider) - { - switch ($sName) - { - case 'change-password': - - include_once __DIR__.'/ChangePasswordExampleDriver.php'; - - $oProvider = new ChangePasswordExampleDriver(); - $oProvider->SetAllowedEmails(\strtolower(\trim($this->Config()->Get('plugin', 'allowed_emails', '')))); - - break; - } - } - - /** - * @return array - */ - public function configMapping() : array - { - return array( - \RainLoop\Plugins\Property::NewInstance('allowed_emails')->SetLabel('Allowed emails') - ->SetType(\RainLoop\Enumerations\PluginPropertyType::STRING_TEXT) - ->SetDescription('Allowed emails, space as delimiter, wildcard supported. Example: user1@domain1.net user2@domain1.net *@domain2.net') - ->SetDefaultValue('*') - ); - } -} diff --git a/plugins/change-password-example/LICENSE b/plugins/change-password/LICENSE similarity index 96% rename from plugins/change-password-example/LICENSE rename to plugins/change-password/LICENSE index 271342337..4aed64b3a 100644 --- a/plugins/change-password-example/LICENSE +++ b/plugins/change-password/LICENSE @@ -1,6 +1,6 @@ The MIT License (MIT) -Copyright (c) 2013 RainLoop Team +Copyright (c) 2015 RainLoop Team Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in diff --git a/plugins/change-password/index.php b/plugins/change-password/index.php new file mode 100644 index 000000000..d6d91cdbd --- /dev/null +++ b/plugins/change-password/index.php @@ -0,0 +1,76 @@ +UseLangs(true); // start use langs folder + + $this->addJs('js/ChangePasswordUserSettings.js'); // add js file + $this->addJsonHook('ChangePassword', 'ChangePassword'); + $this->addTemplate('templates/SettingsChangePassword.html'); + + /** + * Admin + */ +/* + $this->addJs('js/ChangePasswordAdminSettings.js', true); // add js file + $this->addJsonHook('AdminChangePassword', 'AdminChangePassword'); + $this->addTemplate('templates/ChangePasswordAdminSettings.html', true); +*/ + } + + public function ChangePassword() + { + $sPrevPassword = $this->jsonParam('PrevPassword'); + $sNewPassword = $this->jsonParam('NewPassword'); + + $oActions = $this->Manager()->Actions(); + $oAccount = $oActions->GetAccount(); +/* + if (!$this->isPossible($oAccount)) { + throw new ClientException(static::CouldNotSaveNewPassword); + } +*/ + if ($sPrevPassword !== $oAccount->Password()) { + throw new ClientException(static::CurrentPasswordIncorrect, null, $oActions->StaticI18N('NOTIFICATIONS/CURRENT_PASSWORD_INCORRECT')); + } + + $sPasswordForCheck = \trim($sNewPassword); + if (10 > \strlen($sPasswordForCheck)) { + throw new ClientException(static::NewPasswordShort, null, $oActions->StaticI18N('NOTIFICATIONS/NEW_PASSWORD_SHORT')); + } + + if (!\MailSo\Base\Utils::PasswordWeaknessCheck($sPasswordForCheck)) { + throw new ClientException(static::NewPasswordWeak, null, $oActions->StaticI18N('NOTIFICATIONS/NEW_PASSWORD_WEAK')); + } +/* + if (!$this->oDriver->ChangePassword($oAccount, $sPrevPassword, $sNewPassword)) { + throw new ClientException(static::CouldNotSaveNewPassword); + } + + $oAccount->SetPassword($sNewPassword); + $oActions->SetAuthToken($oAccount); +*/ + return $oActions->GetSpecAuthToken(); +// return $this->jsonResponse(__FUNCTION__, $oActions->GetSpecAuthToken()); + } + + public function AdminChangePassword() + { + } + +} diff --git a/plugins/change-password/js/ChangePasswordUserSettings.js b/plugins/change-password/js/ChangePasswordUserSettings.js new file mode 100644 index 000000000..2e1c7b2aa --- /dev/null +++ b/plugins/change-password/js/ChangePasswordUserSettings.js @@ -0,0 +1,110 @@ + +(rl => { + + if (!rl) + { + return; + } + + class ChangePasswordUserSettings + { + constructor() { + ko.addObservablesTo(this, { + changeProcess: false, + + errorDescription: '', + passwordMismatch: false, + passwordUpdateError: false, + passwordUpdateSuccess: false, + + currentPassword: '', + currentPasswordError: false, + newPassword: '', + newPassword2: '', + }); + + this.currentPassword.subscribe(() => this.resetUpdate(true)); + this.newPassword.subscribe(() => this.resetUpdate()); + this.newPassword2.subscribe(() => this.resetUpdate()); + + ko.decorateCommands(this, { + saveNewPasswordCommand: self => !self.changeProcess() + && '' !== self.currentPassword() + && '' !== self.newPassword() + && '' !== self.newPassword2() + }); + } + + saveNewPasswordCommand() { + if (this.newPassword() !== this.newPassword2()) { + this.passwordMismatch(true); + this.errorDescription(rl.i18n('SETTINGS_CHANGE_PASSWORD/ERROR_PASSWORD_MISMATCH')); + } else { + this.reset(true); + rl.pluginRemoteRequest( + (...args) => { + console.dir(...args); + this.onChangePasswordResponse(...args); + }, + 'ChangePassword', + { + 'PrevPassword': this.currentPassword(), + 'NewPassword': this.newPassword() + } + ); + } + } + + reset(change) { + this.changeProcess(change); + this.resetUpdate(); + this.currentPasswordError(false); + this.errorDescription(''); + } + + resetUpdate(current) { + this.passwordUpdateError(false); + this.passwordUpdateSuccess(false); + current ? this.currentPasswordError(false) : this.passwordMismatch(false); + } + + onHide() { + this.reset(false); + this.currentPassword(''); + this.newPassword(''); + this.newPassword2(''); + } + + onChangePasswordResponse(result, data) { + this.reset(false); + if (rl.Enums.StorageResultType.Success === result && data && data.Result) { + this.currentPassword(''); + this.newPassword(''); + this.newPassword2(''); + this.passwordUpdateSuccess(true); + rl.hash.set(); + rl.settings.set('AuthAccountHash', data.Result); + } else { + this.passwordUpdateError(true); + this.errorDescription(rl.i18n('NOTIFICATIONS/COULD_NOT_SAVE_NEW_PASSWORD')); + if (data) { + if (131 === data.ErrorCode) { + // Notification.CurrentPasswordIncorrect + this.currentPasswordError(true); + } + if (data.ErrorMessageAdditional) { + this.errorDescription(data.ErrorMessageAdditional); + } + } + } + } + } + + rl.addSettingsViewModel( + ChangePasswordUserSettings, + 'SettingsChangePassword', + 'GLOBAL/PASSWORD', + 'change-password' + ); + +})(window.rl); diff --git a/plugins/change-password/langs/en.ini b/plugins/change-password/langs/en.ini new file mode 100644 index 000000000..8d3db7374 --- /dev/null +++ b/plugins/change-password/langs/en.ini @@ -0,0 +1,12 @@ +[SETTINGS_CHANGE_PASSWORD] +LEGEND_CHANGE_PASSWORD = "Change Password" +LABEL_CURRENT_PASSWORD = "Current password" +LABEL_NEW_PASSWORD = "New password" +LABEL_REPEAT_PASSWORD = "Confirm New Password" +BUTTON_UPDATE_PASSWORD = "Set New Password" +ERROR_PASSWORD_MISMATCH = "Passwords do not match, please try again" +[NOTIFICATIONS] +COULD_NOT_SAVE_NEW_PASSWORD = "Could not save new password" +CURRENT_PASSWORD_INCORRECT = "Current password incorrect" +NEW_PASSWORD_SHORT = "Password is too short" +NEW_PASSWORD_WEAK = "Password is too easy" diff --git a/snappymail/v/0.0.0/app/templates/Views/User/SettingsChangePassword.html b/plugins/change-password/templates/SettingsChangePassword.html similarity index 100% rename from snappymail/v/0.0.0/app/templates/Views/User/SettingsChangePassword.html rename to plugins/change-password/templates/SettingsChangePassword.html diff --git a/snappymail/v/0.0.0/app/libraries/RainLoop/Actions.php b/snappymail/v/0.0.0/app/libraries/RainLoop/Actions.php index 8a305d2eb..2fa65c6fb 100644 --- a/snappymail/v/0.0.0/app/libraries/RainLoop/Actions.php +++ b/snappymail/v/0.0.0/app/libraries/RainLoop/Actions.php @@ -12,7 +12,6 @@ class Actions use Actions\User; use Actions\Raw; use Actions\Response; - use Actions\ChangePassword; const AUTH_TFA_SIGN_ME_TOKEN_KEY = 'rltfasmauth'; const AUTH_SIGN_ME_TOKEN_KEY = 'rlsmauth'; @@ -1065,7 +1064,6 @@ class Actions 'StartupUrl' => \trim(\ltrim(\trim($oConfig->Get('labs', 'startup_url', '')), '#/')), 'SieveAllowFileintoInbox' => (bool)$oConfig->Get('labs', 'sieve_allow_fileinto_inbox', false), 'ContactsIsAllowed' => false, - 'ChangePasswordIsAllowed' => false, 'RequireTwoFactor' => false, 'Admin' => array(), 'Capa' => array(), @@ -1117,7 +1115,6 @@ class Actions $aResult['OutLogin'] = $oAccount->OutLogin(); $aResult['AccountHash'] = $oAccount->Hash(); $aResult['AccountSignMe'] = $oAccount->SignMe(); - $aResult['ChangePasswordIsAllowed'] = $this->ChangePasswordProvider()->isPossible($oAccount); $aResult['ContactsIsAllowed'] = $oAddressBookProvider->IsActive(); $aResult['ContactsSyncIsAllowed'] = (bool)$oConfig->Get('contacts', 'allow_sync', false); $aResult['ContactsSyncInterval'] = (int)$oConfig->Get('contacts', 'sync_interval', 20); diff --git a/snappymail/v/0.0.0/app/libraries/RainLoop/Notifications.php b/snappymail/v/0.0.0/app/libraries/RainLoop/Notifications.php index ed8443242..fba260a86 100644 --- a/snappymail/v/0.0.0/app/libraries/RainLoop/Notifications.php +++ b/snappymail/v/0.0.0/app/libraries/RainLoop/Notifications.php @@ -13,11 +13,6 @@ class Notifications const AccountTwoFactorAuthRequired = 120; const AccountTwoFactorAuthError = 121; - const CouldNotSaveNewPassword = 130; - const CurrentPasswordIncorrect = 131; - const NewPasswordShort = 132; - const NewPasswordWeak = 133; - const ContactsSyncError = 140; const CantGetMessageList = 201; diff --git a/snappymail/v/0.0.0/app/libraries/RainLoop/Providers/ChangePassword.php b/snappymail/v/0.0.0/app/libraries/RainLoop/Providers/ChangePassword.php deleted file mode 100644 index f247fe41a..000000000 --- a/snappymail/v/0.0.0/app/libraries/RainLoop/Providers/ChangePassword.php +++ /dev/null @@ -1,71 +0,0 @@ -oActions = $oActions; - $this->oDriver = $oDriver; - $this->bCheckWeak = $bCheckWeak; - } - - public function isPossible(Account $oAccount) : bool - { - return $this->IsActive() && $this->oDriver->isPossible($oAccount); - } - - public function ChangePassword(Account $oAccount, string $sPrevPassword, string $sNewPassword) : bool - { - if (!$this->isPossible($oAccount)) { - throw new ClientException(Notifications::CouldNotSaveNewPassword); - } - - if ($sPrevPassword !== $oAccount->Password()) { - throw new ClientException(Notifications::CurrentPasswordIncorrect); - } - - $sPasswordForCheck = \trim($sNewPassword); - if (10 > \strlen($sPasswordForCheck)) { - throw new ClientException(Notifications::NewPasswordShort); - } - - if ($this->bCheckWeak && !\MailSo\Base\Utils::PasswordWeaknessCheck($sPasswordForCheck)) { - throw new ClientException(Notifications::NewPasswordWeak); - } - - if (!$this->oDriver->ChangePassword($oAccount, $sPrevPassword, $sNewPassword)) { - throw new ClientException(Notifications::CouldNotSaveNewPassword); - } - - $oAccount->SetPassword($sNewPassword); - $this->oActions->SetAuthToken($oAccount); - - return $this->oActions->GetSpecAuthToken(); - } - - public function IsActive() : bool - { - return $this->oDriver instanceof ChangePassword\ChangePasswordInterface; - } -} diff --git a/snappymail/v/0.0.0/app/libraries/RainLoop/Providers/ChangePassword/ChangePasswordInterface.php b/snappymail/v/0.0.0/app/libraries/RainLoop/Providers/ChangePassword/ChangePasswordInterface.php deleted file mode 100644 index 4d4c66c63..000000000 --- a/snappymail/v/0.0.0/app/libraries/RainLoop/Providers/ChangePassword/ChangePasswordInterface.php +++ /dev/null @@ -1,10 +0,0 @@ -oActions->SetActionParams($aPost, $sMethodName); + foreach ($aPost as $key => $value) { + if (false !== \stripos($key, 'Password')) { + $aPost[$key] = '*******'; + } + } +/* switch ($sMethodName) { case 'DoLogin': @@ -118,12 +124,8 @@ class ServiceActions case 'DoAccountAdd': $this->Logger()->AddSecret($this->oActions->GetActionParam('Password', '')); break; - case 'DoChangePassword': - $this->Logger()->AddSecret($this->oActions->GetActionParam('PrevPassword', '')); - $this->Logger()->AddSecret($this->oActions->GetActionParam('NewPassword', '')); - break; } - +*/ $this->Logger()->Write(\MailSo\Base\Utils::Php2js($aPost, $this->Logger()), \MailSo\Log\Enumerations\Type::INFO, 'POST', true); }