1: <?php
2: /**
3: * This code is licensed under AGPLv3 license or Afterlogic Software License
4: * if commercial version of the product was purchased.
5: * For full statements of the licenses see LICENSE-AFTERLOGIC and LICENSE-AGPL3 files.
6: */
7:
8: namespace Aurora\Modules\MailChangePasswordPoppassdPlugin;
9:
10: /**
11: * Allows users to change passwords on their email accounts using POPPASSD protocol.
12: *
13: * @license https://www.gnu.org/licenses/agpl-3.0.html AGPL-3.0
14: * @license https://afterlogic.com/products/common-licensing Afterlogic Software License
15: * @copyright Copyright (c) 2023, Afterlogic Corp.
16: *
17: * @package Modules
18: */
19: class Module extends \Aurora\System\Module\AbstractModule
20: {
21: /**
22: * @var CApiPoppassdProtocol
23: */
24: protected $oPopPassD;
25:
26: /**
27: * @param CApiPluginManager $oPluginManager
28: */
29:
30: public function init()
31: {
32: $this->oPopPassD = null;
33:
34: $this->subscribeEvent('Mail::Account::ToResponseArray', array($this, 'onMailAccountToResponseArray'));
35: $this->subscribeEvent('Mail::ChangeAccountPassword', array($this, 'onChangeAccountPassword'));
36: }
37:
38: /**
39: * Adds to account response array information about if allowed to change the password for this account.
40: * @param array $aArguments
41: * @param mixed $mResult
42: */
43: public function onMailAccountToResponseArray($aArguments, &$mResult)
44: {
45: $oAccount = $aArguments['Account'];
46:
47: if ($oAccount && $this->checkCanChangePassword($oAccount)) {
48: if (!isset($mResult['Extend']) || !is_array($mResult['Extend'])) {
49: $mResult['Extend'] = [];
50: }
51: $mResult['Extend']['AllowChangePasswordOnMailServer'] = true;
52: }
53: }
54:
55: /**
56: * Tries to change password for account if allowed.
57: * @param array $aArguments
58: * @param mixed $mResult
59: */
60: public function onChangeAccountPassword($aArguments, &$mResult)
61: {
62: $bPasswordChanged = false;
63: $bBreakSubscriptions = false;
64:
65: $oAccount = $aArguments['Account'];
66: if ($oAccount && $this->checkCanChangePassword($oAccount) && $oAccount->getPassword() === $aArguments['CurrentPassword']) {
67: $bPasswordChanged = $this->changePassword($oAccount, $aArguments['NewPassword']);
68: $bBreakSubscriptions = true; // break if Poppassd plugin tries to change password in this account.
69: }
70:
71: if (is_array($mResult)) {
72: $mResult['AccountPasswordChanged'] = $mResult['AccountPasswordChanged'] || $bPasswordChanged;
73: }
74:
75: return $bBreakSubscriptions;
76: }
77:
78: /**
79: * Checks if allowed to change password for account.
80: * @param \Aurora\Modules\Mail\Classes\Account $oAccount
81: * @return bool
82: */
83: protected function checkCanChangePassword($oAccount)
84: {
85: $bFound = in_array('*', $this->getConfig('SupportedServers', array()));
86:
87: if (!$bFound) {
88: $oServer = $oAccount->getServer();
89:
90: if ($oServer && in_array($oServer->IncomingServer, $this->getConfig('SupportedServers'))) {
91: $bFound = true;
92: }
93: }
94:
95: return $bFound;
96: }
97:
98: /**
99: * Tries to change password for account.
100: * @param \Aurora\Modules\Mail\Classes\Account $oAccount
101: * @param string $sPassword
102: * @return boolean
103: * @throws \Aurora\System\Exceptions\ApiException
104: */
105: protected function changePassword($oAccount, $sPassword)
106: {
107: $bResult = false;
108:
109: if (0 < strlen($oAccount->getPassword()) && $oAccount->getPassword() !== $sPassword) {
110: if (null === $this->oPopPassD) {
111: $this->oPopPassD = new Poppassd(
112: $this->getConfig('Host', '127.0.0.1'),
113: $this->getConfig('Port', 106)
114: );
115: }
116:
117: if ($this->oPopPassD && $this->oPopPassD->Connect()) {
118: try {
119: if ($this->oPopPassD->Login($oAccount->IncomingLogin, $oAccount->getPassword())) {
120: $aNewPasswordResult = $this->oPopPassD->NewPass($sPassword);
121: if (!$aNewPasswordResult[0]) {
122: throw new \Aurora\System\Exceptions\ApiException(\Aurora\System\Exceptions\Errs::UserManager_AccountNewPasswordRejected, null, $aNewPasswordResult[1]);
123: } else {
124: $bResult = true;
125: }
126: } else {
127: throw new \Aurora\System\Exceptions\ApiException(\Aurora\System\Exceptions\Errs::UserManager_AccountOldPasswordNotCorrect);
128: }
129: } catch (\Exception $oException) {
130: $this->oPopPassD->Disconnect();
131: throw $oException;
132: }
133: } else {
134: throw new \Aurora\System\Exceptions\ApiException(\Aurora\System\Exceptions\Errs::UserManager_AccountNewPasswordUpdateError);
135: }
136: }
137:
138: return $bResult;
139: }
140:
141: /**
142: * Obtains list of module settings for super admin.
143: * @return array
144: */
145: public function GetSettings()
146: {
147: \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::SuperAdmin);
148:
149: $sSupportedServers = implode("\n", $this->getConfig('SupportedServers', array()));
150:
151: $aAppData = array(
152: 'SupportedServers' => $sSupportedServers,
153: 'Host' => $this->getConfig('Host', ''),
154: 'Port' => $this->getConfig('Port', 0),
155: );
156:
157: return $aAppData;
158: }
159:
160: /**
161: * Updates module's super admin settings.
162: * @param string $SupportedServers
163: * @param string $Host
164: * @param int $Port
165: * @return boolean
166: */
167: public function UpdateSettings($SupportedServers, $Host, $Port)
168: {
169: \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::SuperAdmin);
170:
171: $aSupportedServers = preg_split('/\r\n|[\r\n]/', $SupportedServers);
172:
173: $this->setConfig('SupportedServers', $aSupportedServers);
174: $this->setConfig('Host', $Host);
175: $this->setConfig('Port', $Port);
176:
177: return $this->saveModuleConfig();
178: }
179: }
180: