1: | <?php |
2: | |
3: | |
4: | |
5: | |
6: | |
7: | |
8: | namespace Aurora\Modules\RocketChatWebclient; |
9: | |
10: | use Aurora\Api; |
11: | use Aurora\Modules\Contacts\Enums\StorageType; |
12: | use Aurora\Modules\Contacts\Module as ContactsModule; |
13: | use Aurora\Modules\Core\Module as CoreModule; |
14: | use Aurora\System\Enums\UserRole; |
15: | use Aurora\System\Exceptions\ApiException; |
16: | use Aurora\System\Utils; |
17: | use GuzzleHttp\Client; |
18: | use GuzzleHttp\Exception\ConnectException; |
19: | use GuzzleHttp\HandlerStack; |
20: | use GuzzleHttp\MessageFormatter; |
21: | use GuzzleHttp\Middleware; |
22: | use Monolog\Handler\RotatingFileHandler; |
23: | use Monolog\Logger; |
24: | |
25: | |
26: | |
27: | |
28: | |
29: | |
30: | |
31: | |
32: | |
33: | |
34: | class Module extends \Aurora\System\Module\AbstractModule |
35: | { |
36: | public $oRocketChatSettingsManager = null; |
37: | |
38: | protected $sChatUrl = ""; |
39: | |
40: | protected $sDemoPass = "demo"; |
41: | |
42: | |
43: | |
44: | |
45: | protected $client = null; |
46: | |
47: | protected $adminAccount = null; |
48: | |
49: | protected $stack = null; |
50: | |
51: | protected $curUserData = false; |
52: | |
53: | protected $curUserInfo = false; |
54: | |
55: | |
56: | |
57: | |
58: | public static function getInstance() |
59: | { |
60: | return parent::getInstance(); |
61: | } |
62: | |
63: | |
64: | |
65: | |
66: | public static function Decorator() |
67: | { |
68: | return parent::Decorator(); |
69: | } |
70: | |
71: | |
72: | |
73: | |
74: | public function getModuleSettings() |
75: | { |
76: | return $this->oModuleSettings; |
77: | } |
78: | |
79: | public function init() |
80: | { |
81: | $this->initLogging(); |
82: | |
83: | $this->oRocketChatSettingsManager = new Managers\RocketChatSettings\Manager($this); |
84: | |
85: | $this->initConfig(); |
86: | |
87: | $this->AddEntry('chat', 'EntryChat'); |
88: | $this->AddEntry('chat-direct', 'EntryChatDirect'); |
89: | |
90: | $this->subscribeEvent('Core::DeleteUser::before', array($this, 'onBeforeDeleteUser')); |
91: | $this->subscribeEvent('Core::Logout::after', array($this, 'onAfterLogout')); |
92: | } |
93: | |
94: | |
95: | |
96: | |
97: | |
98: | |
99: | |
100: | |
101: | public function GetSettings($TenantId = null) |
102: | { |
103: | $aResult = []; |
104: | Api::checkUserRoleIsAtLeast(UserRole::NormalUser); |
105: | |
106: | $oUser = \Aurora\System\Api::getAuthenticatedUser(); |
107: | if ($oUser) { |
108: | $sChatUrl = ''; |
109: | $sAdminUsername = ''; |
110: | |
111: | $oSettings = $this->oModuleSettings; |
112: | if (!empty($TenantId)) { |
113: | Api::checkUserRoleIsAtLeast(UserRole::TenantAdmin); |
114: | $oTenant = Api::getTenantById($TenantId); |
115: | |
116: | if ($oTenant && ($oUser->isAdmin() || $oUser->IdTenant === $oTenant->Id)) { |
117: | $sChatUrl = $oSettings->GetTenantValue($oTenant->Name, 'ChatUrl', $sChatUrl); |
118: | $sAdminUsername = $oSettings->GetTenantValue($oTenant->Name, 'AdminUsername', $sAdminUsername); |
119: | } |
120: | } else { |
121: | $sChatUrl = $oSettings->ChatUrl; |
122: | $sAdminUsername = $oSettings->AdminUsername; |
123: | } |
124: | |
125: | if ($oUser->isNormalOrTenant()) { |
126: | $aResult = [ |
127: | 'ChatUrl' => $sChatUrl, |
128: | 'AllowAddMeetingLinkToEvent' => $this->oModuleSettings->AllowAddMeetingLinkToEvent, |
129: | 'MeetingLinkUrl' => $this->oModuleSettings->MeetingLinkUrl |
130: | ]; |
131: | |
132: | } elseif ($oUser->isAdmin()) { |
133: | $aResult = [ |
134: | 'ChatUrl' => $sChatUrl, |
135: | 'AdminUsername' => $sAdminUsername |
136: | ]; |
137: | } |
138: | } |
139: | |
140: | return $aResult; |
141: | } |
142: | |
143: | |
144: | |
145: | |
146: | |
147: | |
148: | |
149: | |
150: | |
151: | |
152: | public function UpdateSettings($TenantId, $ChatUrl, $AdminUsername, $AdminPassword = null) |
153: | { |
154: | $oSettings = $this->oModuleSettings; |
155: | if (!empty($TenantId)) { |
156: | Api::checkUserRoleIsAtLeast(UserRole::TenantAdmin); |
157: | $oTenant = Api::getTenantById($TenantId); |
158: | $oUser = Api::getAuthenticatedUser(); |
159: | |
160: | if ($oTenant && ($oUser->isAdmin() || $oUser->IdTenant === $oTenant->Id)) { |
161: | $aValues = [ |
162: | 'ChatUrl' => $ChatUrl, |
163: | 'AdminUsername' => $AdminUsername |
164: | ]; |
165: | |
166: | if ($AdminPassword) { |
167: | $sDecryptedPassword = Utils::DecryptValue($AdminPassword); |
168: | |
169: | if ($sDecryptedPassword === false) { |
170: | $aValues['AdminPassword'] = Utils::EncryptValue($AdminPassword); |
171: | } else { |
172: | $aValues['AdminPassword'] = $AdminPassword; |
173: | } |
174: | } |
175: | |
176: | return $oSettings->SaveTenantSettings($oTenant->Name, $aValues); |
177: | } |
178: | } else { |
179: | Api::checkUserRoleIsAtLeast(UserRole::SuperAdmin); |
180: | |
181: | $oSettings->ChatUrl = $ChatUrl; |
182: | $oSettings->AdminUsername = $AdminUsername; |
183: | |
184: | if ($AdminPassword) { |
185: | $sDecryptedPassword = Utils::DecryptValue($AdminPassword); |
186: | |
187: | if ($sDecryptedPassword === false) { |
188: | $oSettings->AdminPassword = Utils::EncryptValue($AdminPassword); |
189: | } else { |
190: | $oSettings->AdminPassword = $AdminPassword; |
191: | } |
192: | } |
193: | |
194: | return $oSettings->Save(); |
195: | } |
196: | |
197: | return false; |
198: | } |
199: | |
200: | |
201: | |
202: | |
203: | |
204: | |
205: | |
206: | public function GetRocketChatSettings($TenantId = null) |
207: | { |
208: | \Aurora\System\Api::checkUserRoleIsAtLeast(UserRole::SuperAdmin); |
209: | |
210: | return $this->oRocketChatSettingsManager->get( |
211: | $this->getClient($TenantId), |
212: | $this->getAdminHeaders($TenantId) |
213: | ); |
214: | } |
215: | |
216: | |
217: | |
218: | |
219: | |
220: | |
221: | |
222: | |
223: | |
224: | |
225: | public function TestConnection($TenantId, $ChatUrl, $AdminUsername, $AdminPassword = null) |
226: | { |
227: | return false; |
228: | } |
229: | |
230: | |
231: | |
232: | |
233: | |
234: | |
235: | |
236: | public function ApplyRocketChatRequiredChanges($TenantId = null) |
237: | { |
238: | \Aurora\System\Api::checkUserRoleIsAtLeast(UserRole::SuperAdmin); |
239: | |
240: | return $this->oRocketChatSettingsManager->setConfigs( |
241: | $this->getClient($TenantId), |
242: | $this->getAdminHeaders($TenantId) |
243: | ); |
244: | } |
245: | |
246: | |
247: | |
248: | |
249: | |
250: | |
251: | |
252: | public function ApplyRocketChatTextChanges($TenantId = null) |
253: | { |
254: | \Aurora\System\Api::checkUserRoleIsAtLeast(UserRole::SuperAdmin); |
255: | |
256: | return $this->oRocketChatSettingsManager->setTexts( |
257: | $this->getClient($TenantId), |
258: | $this->getAdminHeaders($TenantId) |
259: | ); |
260: | } |
261: | |
262: | |
263: | |
264: | |
265: | |
266: | |
267: | |
268: | public function ApplyRocketChatCssChanges($TenantId = null) |
269: | { |
270: | \Aurora\System\Api::checkUserRoleIsAtLeast(UserRole::SuperAdmin); |
271: | |
272: | return $this->oRocketChatSettingsManager->setCss( |
273: | $this->getClient($TenantId), |
274: | $this->getAdminHeaders($TenantId) |
275: | ); |
276: | } |
277: | |
278: | |
279: | |
280: | |
281: | public function EntryChatDirect() |
282: | { |
283: | try { |
284: | Api::checkUserRoleIsAtLeast(UserRole::NormalUser); |
285: | |
286: | $sContactUuid = $this->oHttp->GetQuery('chat-direct'); |
287: | $oCurrentUser = Api::getAuthenticatedUser(); |
288: | $oContact = ContactsModule::Decorator()->GetContact($sContactUuid, $oCurrentUser->Id); |
289: | $sUserPublicId = null; |
290: | if ($oContact) { |
291: | if ($oContact->Storage === StorageType::Team) { |
292: | $sUserPublicId = $oContact->ViewEmail; |
293: | } else { |
294: | $oUser = $oContact ? Api::getUserById($oContact->IdUser) : null; |
295: | if ($oUser && $oCurrentUser && $oCurrentUser->IdTenant === $oUser->IdTenant) { |
296: | $sUserPublicId = $oUser->PublicId; |
297: | } |
298: | } |
299: | } |
300: | if ($sUserPublicId) { |
301: | $sChatLogin = $this->GetLoginForEmail($sUserPublicId); |
302: | |
303: | if ($sChatLogin) { |
304: | $this->showChat('direct/' . $sChatLogin . '?layout=embedded'); |
305: | } else { |
306: | $this->showError('User not found'); |
307: | } |
308: | } else { |
309: | $this->showError('User not found'); |
310: | } |
311: | } catch (ApiException $oEx) { |
312: | $this->showError('User not found'); |
313: | } |
314: | } |
315: | |
316: | |
317: | |
318: | |
319: | public function EntryChat() |
320: | { |
321: | $oIntegrator = \Aurora\System\Managers\Integrator::getInstance(); |
322: | $this->showChat('', $oIntegrator->buildHeadersLink()); |
323: | } |
324: | |
325: | |
326: | |
327: | |
328: | public function InitChat() |
329: | { |
330: | if (!$this->curUserData) { |
331: | $mResult = false; |
332: | $oUser = Api::getAuthenticatedUser(); |
333: | if ($oUser && $this->client && $this->initUser()) { |
334: | $sAuthToken = isset($_COOKIE['RocketChatAuthToken']) ? $_COOKIE['RocketChatAuthToken'] : null; |
335: | $sUserId = isset($_COOKIE['RocketChatUserId']) ? $_COOKIE['RocketChatUserId'] : null; |
336: | |
337: | if ($sAuthToken !== null && $sUserId !== null) { |
338: | $sAuthToken = Utils::DecryptValue($sAuthToken); |
339: | Api::AddSecret($sAuthToken); |
340: | try { |
341: | $res = $this->client->get('me', [ |
342: | 'headers' => [ |
343: | "X-Auth-Token" => $sAuthToken, |
344: | "X-User-Id" => $sUserId, |
345: | ], |
346: | 'http_errors' => false |
347: | ]); |
348: | if ($res->getStatusCode() === 200) { |
349: | $body = \json_decode($res->getBody(), true); |
350: | $sLang = ''; |
351: | if (isset($body->settings->preferences->language)) { |
352: | $sLang = $body->settings->preferences->language; |
353: | } |
354: | $sUserLang = Utils::ConvertLanguageNameToShort($oUser->Language); |
355: | if ($sUserLang !== $sLang) { |
356: | $this->updateLanguage($sUserId, $sAuthToken, $sUserLang); |
357: | } |
358: | |
359: | $mResult = true; |
360: | } |
361: | } catch (ConnectException $oException) { |
362: | } |
363: | } |
364: | |
365: | if (!$mResult) { |
366: | $currentUserInfo = $this->getCurrentUserInfo(); |
367: | $mLoginResult = false; |
368: | if ($currentUserInfo) { |
369: | $mLoginResult = $this->loginCurrentUser(); |
370: | if (!$mLoginResult && !$this->isDemoUser($oUser->PublicId)) { |
371: | if ($this->updateUserPassword($currentUserInfo)) { |
372: | $mLoginResult = $this->loginCurrentUser(); |
373: | } |
374: | } |
375: | } elseif ($this->createCurrentUser() !== false) { |
376: | $mLoginResult = $this->loginCurrentUser(); |
377: | } |
378: | |
379: | if ($mLoginResult && isset($mLoginResult->data)) { |
380: | $iAuthTokenCookieExpireTime = (int) CoreModule::getInstance()->oModuleSettings->AuthTokenCookieExpireTime; |
381: | $sSameSite = CoreModule::getInstance()->oModuleSettings->CookieSameSite; |
382: | |
383: | $sAuthToken = $mLoginResult->data->authToken; |
384: | $sUserId = $mLoginResult->data->userId; |
385: | |
386: | Api::setCookie( |
387: | 'RocketChatAuthToken', |
388: | Utils::EncryptValue($sAuthToken), |
389: | \strtotime('+' . $iAuthTokenCookieExpireTime . ' days'), |
390: | true, |
391: | $sSameSite |
392: | ); |
393: | |
394: | Api::setCookie( |
395: | 'RocketChatUserId', |
396: | $sUserId, |
397: | \strtotime('+' . $iAuthTokenCookieExpireTime . ' days'), |
398: | true, |
399: | $sSameSite |
400: | ); |
401: | |
402: | $oUser->save(); |
403: | } |
404: | } |
405: | |
406: | if ($sAuthToken && $sUserId) { |
407: | $mResult = [ |
408: | 'authToken' => $sAuthToken, |
409: | 'userId' => $sUserId, |
410: | 'unreadCounter' => $this->getUnreadCounter($sUserId, $sAuthToken) |
411: | ]; |
412: | } |
413: | } |
414: | |
415: | $this->curUserData = $mResult; |
416: | } |
417: | |
418: | return $this->curUserData; |
419: | } |
420: | |
421: | |
422: | |
423: | |
424: | public function GetLoginForCurrentUser() |
425: | { |
426: | $mResult = false; |
427: | |
428: | $oUser = Api::getAuthenticatedUser(); |
429: | if ($oUser) { |
430: | $mResult = $this->getUserNameFromEmail($oUser->PublicId); |
431: | } |
432: | |
433: | return $mResult; |
434: | } |
435: | |
436: | |
437: | |
438: | |
439: | |
440: | |
441: | |
442: | |
443: | public function GetLoginForEmail($Email) |
444: | { |
445: | $mResult = false; |
446: | $oUserInfo = $this->getUserInfo($Email); |
447: | if (!$oUserInfo) { |
448: | $oUserInfo = $this->createUser($Email); |
449: | } |
450: | if ($oUserInfo && $oUserInfo->success) { |
451: | $mResult = $oUserInfo->user->username; |
452: | } |
453: | |
454: | return $mResult; |
455: | } |
456: | |
457: | |
458: | |
459: | |
460: | |
461: | |
462: | protected function getUnreadCounter($sUserId, $sToken) |
463: | { |
464: | $iResult = 0; |
465: | if ($this->client) { |
466: | try { |
467: | $res = $this->client->get('subscriptions.get', [ |
468: | 'headers' => [ |
469: | "X-Auth-Token" => $sToken, |
470: | "X-User-Id" => $sUserId, |
471: | ], |
472: | 'http_errors' => false |
473: | ]); |
474: | if ($res->getStatusCode() === 200) { |
475: | $aResponse = \json_decode($res->getBody(), true); |
476: | if (is_array($aResponse['update'])) { |
477: | foreach ($aResponse['update'] as $update) { |
478: | $iResult += $update['unread']; |
479: | } |
480: | } |
481: | } |
482: | } catch (ConnectException $oException) { |
483: | } |
484: | } |
485: | |
486: | return $iResult; |
487: | } |
488: | |
489: | |
490: | |
491: | |
492: | |
493: | |
494: | |
495: | protected function getClient($iTenantId = null) |
496: | { |
497: | $mResult = null; |
498: | $oSettings = $this->oModuleSettings; |
499: | $sChatUrl = ''; |
500: | if (isset($iTenantId)) { |
501: | $oTenant = Api::getTenantById($iTenantId); |
502: | if ($oTenant) { |
503: | $sChatUrl = $oSettings->GetTenantValue($oTenant->Name, 'ChatUrl', ''); |
504: | } |
505: | } else { |
506: | $sChatUrl = $oSettings->ChatUrl; |
507: | if (isset($this->client)) { |
508: | return $this->client; |
509: | } |
510: | } |
511: | if (!empty($sChatUrl)) { |
512: | $mResult = new Client([ |
513: | 'base_uri' => \rtrim($sChatUrl, '/') . '/api/v1/', |
514: | 'verify' => false, |
515: | 'handler' => $this->stack |
516: | ]); |
517: | } |
518: | |
519: | return $mResult; |
520: | } |
521: | |
522: | |
523: | |
524: | |
525: | protected function initConfig() |
526: | { |
527: | $this->sChatUrl = $this->oModuleSettings->ChatUrl; |
528: | $sAdminUser = $this->oModuleSettings->AdminUsername; |
529: | |
530: | if (!empty($this->sChatUrl) && !empty($sAdminUser)) { |
531: | $this->client = new Client([ |
532: | 'base_uri' => \rtrim($this->sChatUrl, '/') . '/api/v1/', |
533: | 'verify' => false, |
534: | 'handler' => $this->stack |
535: | ]); |
536: | } |
537: | } |
538: | |
539: | |
540: | |
541: | |
542: | |
543: | |
544: | |
545: | protected function isDemoUser($sEmail) |
546: | { |
547: | $bDemo = false; |
548: | |
549: | if (class_exists('\Aurora\Modules\DemoModePlugin\Module')) { |
550: | |
551: | $oDemoModePlugin = Api::GetModuleDecorator('DemoModePlugin'); |
552: | $bDemo = $oDemoModePlugin && $oDemoModePlugin->CheckDemoUser($sEmail); |
553: | } |
554: | |
555: | return $bDemo; |
556: | } |
557: | |
558: | |
559: | |
560: | |
561: | protected function initLogging() |
562: | { |
563: | if ($this->oModuleSettings->EnableLogging && !$this->stack) { |
564: | $stack = HandlerStack::create(); |
565: | $oLogger = new Logger('rocketchat'); |
566: | $handler = new RotatingFileHandler(Api::GetLogFileDir() . 'rocketchat-log.txt'); |
567: | $oLogger->pushHandler($handler); |
568: | |
569: | $oLogger->setExceptionHandler(function ($e) { |
570: | Api::LogException($e); |
571: | }); |
572: | collect([ |
573: | "REQUEST: {method} - {uri} - HTTP/{version} - {req_headers} - {req_body}", |
574: | "RESPONSE: {code} - {res_body}", |
575: | ])->each(function ($messageFormat) use ($stack, $oLogger) { |
576: | |
577: | $oLogger->pushProcessor(function ($record) { |
578: | $record['message'] = str_replace(Api::$aSecretWords, '*****', $record['message']); |
579: | $record['message'] = preg_replace( |
580: | [ |
581: | '/(X-Auth-Token|X-2fa-code):(.+?\s)/i', |
582: | '/("bcrypt"):(.*?\})/i', |
583: | '/("authToken"):(.*?,)/i' |
584: | ], |
585: | '$1: ***** ', |
586: | $record['message'] |
587: | ); |
588: | return $record; |
589: | }); |
590: | |
591: | $stack->unshift(Middleware::log( |
592: | $oLogger, |
593: | new MessageFormatter($messageFormat) |
594: | )); |
595: | }); |
596: | $this->stack = $stack; |
597: | } |
598: | } |
599: | |
600: | |
601: | |
602: | |
603: | |
604: | |
605: | protected function initUser() |
606: | { |
607: | $bResult = true; |
608: | if (!$this->getCurrentUserInfo()) { |
609: | if (!$this->createCurrentUser()) { |
610: | $bResult = false; |
611: | } |
612: | } |
613: | |
614: | return $bResult; |
615: | } |
616: | |
617: | |
618: | |
619: | |
620: | |
621: | |
622: | |
623: | |
624: | |
625: | protected function showChat($sUrl = '', $sIntegratorLinks = '') |
626: | { |
627: | $aUser = $this->InitChat(); |
628: | $sResult = \file_get_contents($this->GetPath() . '/templates/Chat.html'); |
629: | if (\is_string($sResult)) { |
630: | echo strtr($sResult, [ |
631: | '{{TOKEN}}' => $aUser ? $aUser['authToken'] : '', |
632: | '{{URL}}' => rtrim($this->sChatUrl, '/') . '/' . $sUrl, |
633: | '{{IntegratorLinks}}' => $sIntegratorLinks, |
634: | ]); |
635: | } |
636: | } |
637: | |
638: | |
639: | |
640: | |
641: | |
642: | |
643: | protected function showError($sMessage = '') |
644: | { |
645: | echo $sMessage; |
646: | } |
647: | |
648: | |
649: | |
650: | |
651: | |
652: | |
653: | |
654: | protected function getUserNameFromEmail($sEmail) |
655: | { |
656: | $mResult = false; |
657: | $iChatUsernameFormat = $this->oModuleSettings->ChatUsernameFormat; |
658: | |
659: | $aEmailParts = explode("@", $sEmail); |
660: | if (isset($aEmailParts[1])) { |
661: | $aDomainParts = explode(".", $aEmailParts[1]); |
662: | } |
663: | |
664: | if (isset($aEmailParts[0])) { |
665: | $mResult = $aEmailParts[0]; |
666: | if (isset($aDomainParts[0]) && ($iChatUsernameFormat == \Aurora\Modules\RocketChatWebclient\Enums\UsernameFormat::UsernameAndDomain)) { |
667: | $mResult .= "." . $aDomainParts[0]; |
668: | } |
669: | if (isset($aEmailParts[1]) && ($iChatUsernameFormat == \Aurora\Modules\RocketChatWebclient\Enums\UsernameFormat::UsernameAndFullDomainName)) { |
670: | $mResult .= "." . $aEmailParts[1]; |
671: | } |
672: | } |
673: | |
674: | return $mResult; |
675: | } |
676: | |
677: | |
678: | |
679: | |
680: | |
681: | |
682: | |
683: | |
684: | protected function getAdminCredentials($TenantId = null, $EncrypdedPassword = true) |
685: | { |
686: | static $mResult = false; |
687: | |
688: | if (!$mResult) { |
689: | $adminCreds = []; |
690: | $oSettings = $this->oModuleSettings; |
691: | if (isset($TenantId)) { |
692: | $oTenant = Api::getTenantById($TenantId); |
693: | if ($oTenant) { |
694: | $adminCreds = [ |
695: | 'AdminUser' => $oSettings->GetTenantValue($oTenant->Name, 'AdminUsername', ''), |
696: | 'AdminPass' => $oSettings->GetTenantValue($oTenant->Name, 'AdminPassword', '') |
697: | ]; |
698: | } |
699: | } else { |
700: | $adminCreds = [ |
701: | 'AdminUser' => $oSettings->AdminUsername, |
702: | 'AdminPass' => $oSettings->AdminPassword |
703: | ]; |
704: | } |
705: | if (is_array($adminCreds) && isset($adminCreds['AdminPass'])) { |
706: | if ($EncrypdedPassword) { |
707: | $adminCreds['AdminPass'] = Utils::DecryptValue($adminCreds['AdminPass']); |
708: | } |
709: | if ($adminCreds['AdminPass']) { |
710: | Api::AddSecret($adminCreds['AdminPass']); |
711: | $mResult = $adminCreds; |
712: | } |
713: | } |
714: | } |
715: | |
716: | return $mResult; |
717: | } |
718: | |
719: | |
720: | |
721: | |
722: | |
723: | |
724: | |
725: | |
726: | protected function loginAdminAccount($TenantId, $aAdminCreds) |
727: | { |
728: | $mResult = false; |
729: | |
730: | $client = $this->getClient($TenantId); |
731: | try { |
732: | if ($client && $aAdminCreds) { |
733: | $res = $client->post('login', [ |
734: | 'form_params' => [ |
735: | 'user' => $aAdminCreds['AdminUser'], |
736: | 'password' => $aAdminCreds['AdminPass'] |
737: | ], |
738: | 'http_errors' => false |
739: | ]); |
740: | if ($res->getStatusCode() === 200) { |
741: | $mResult = \json_decode($res->getBody()); |
742: | } |
743: | } |
744: | } catch (ConnectException $oException) { |
745: | } |
746: | |
747: | return $mResult; |
748: | } |
749: | |
750: | |
751: | |
752: | |
753: | |
754: | protected function getAdminAccount($TenantId = null) |
755: | { |
756: | $mResult = false; |
757: | |
758: | if (!isset($TenantId) && isset($this->adminAccount)) { |
759: | return $this->adminAccount; |
760: | } |
761: | |
762: | $aAdminCreds = $this->getAdminCredentials($TenantId); |
763: | if ($aAdminCreds) { |
764: | $mResult = $this->loginAdminAccount($TenantId, $aAdminCreds); |
765: | } |
766: | if (!$mResult) { |
767: | $aAdminCreds = $this->getAdminCredentials($TenantId, false); |
768: | $mResult = $this->loginAdminAccount($TenantId, $aAdminCreds); |
769: | } |
770: | if (!isset($TenantId) && $mResult) { |
771: | $this->adminAccount = $mResult; |
772: | } |
773: | |
774: | return $mResult; |
775: | } |
776: | |
777: | |
778: | |
779: | |
780: | |
781: | protected function getAdminHeaders($TenantId = null) |
782: | { |
783: | $oAdmin = $this->getAdminAccount($TenantId); |
784: | $aAdminCreds = $this->getAdminCredentials($TenantId); |
785: | if ($oAdmin && $aAdminCreds) { |
786: | return [ |
787: | 'X-Auth-Token' => $oAdmin->data->authToken, |
788: | 'X-User-Id' => $oAdmin->data->userId, |
789: | 'X-2fa-code' => hash('sha256', $aAdminCreds['AdminPass']), |
790: | 'X-2fa-method' => 'password' |
791: | ]; |
792: | } |
793: | return []; |
794: | } |
795: | |
796: | |
797: | |
798: | |
799: | |
800: | |
801: | |
802: | protected function getUserInfo($sEmail) |
803: | { |
804: | $mResult = false; |
805: | $sUserName = $this->getUserNameFromEmail($sEmail); |
806: | try { |
807: | if ($this->client) { |
808: | $res = $this->client->get('users.info', [ |
809: | 'query' => [ |
810: | 'username' => $sUserName |
811: | ], |
812: | 'headers' => $this->getAdminHeaders(), |
813: | 'http_errors' => false |
814: | ]); |
815: | if ($res->getStatusCode() === 200) { |
816: | $mResult = \json_decode($res->getBody()); |
817: | } |
818: | } |
819: | } catch (ConnectException $oException) { |
820: | \Aurora\System\Api::Log('Cannot get ' . $sUserName . ' user info. Exception is below.'); |
821: | \Aurora\System\Api::LogException($oException); |
822: | } |
823: | |
824: | return $mResult; |
825: | } |
826: | |
827: | |
828: | |
829: | |
830: | protected function getCurrentUserInfo() |
831: | { |
832: | if (!$this->curUserInfo) { |
833: | $oUser = Api::getAuthenticatedUser(); |
834: | if ($oUser) { |
835: | $this->curUserInfo = $this->getUserInfo($oUser->PublicId); |
836: | } |
837: | } |
838: | |
839: | return $this->curUserInfo; |
840: | } |
841: | |
842: | |
843: | |
844: | |
845: | |
846: | |
847: | |
848: | protected function createUser($sEmail) |
849: | { |
850: | $mResult = false; |
851: | |
852: | $oAccount = CoreModule::Decorator()->GetAccountUsedToAuthorize($sEmail); |
853: | if ($oAccount && $this->client) { |
854: | if (!$this->isDemoUser($sEmail)) { |
855: | $sPassword = $oAccount->getPassword(); |
856: | } else { |
857: | $sPassword = $this->sDemoPass; |
858: | } |
859: | |
860: | Api::AddSecret($sPassword); |
861: | |
862: | $sLogin = $this->getUserNameFromEmail($sEmail); |
863: | $sName = isset($oAccount->FriendlyName) && $oAccount->FriendlyName !== '' ? $oAccount->FriendlyName : $sLogin; |
864: | try { |
865: | $res = $this->client->post('users.create', [ |
866: | 'json' => [ |
867: | 'email' => $sEmail, |
868: | 'name' => $sName, |
869: | 'password' => $sPassword, |
870: | 'username' => $sLogin |
871: | ], |
872: | 'headers' => $this->getAdminHeaders(), |
873: | 'http_errors' => false |
874: | ]); |
875: | if ($res->getStatusCode() === 200) { |
876: | $mResult = \json_decode($res->getBody()); |
877: | } |
878: | } catch (ConnectException $oException) { |
879: | \Aurora\System\Api::Log('Cannot create ' . $sEmail . ' user. Exception is below.'); |
880: | \Aurora\System\Api::LogException($oException); |
881: | } |
882: | } |
883: | return $mResult; |
884: | } |
885: | |
886: | protected function createCurrentUser() |
887: | { |
888: | $mResult = false; |
889: | |
890: | $oUser = Api::getAuthenticatedUser(); |
891: | |
892: | if ($oUser) { |
893: | $mResult = $this->createUser($oUser->PublicId); |
894: | } |
895: | |
896: | return $mResult; |
897: | } |
898: | |
899: | protected function loginCurrentUser() |
900: | { |
901: | $mResult = false; |
902: | |
903: | $oUser = Api::getAuthenticatedUser(); |
904: | if ($oUser) { |
905: | $oAccount = CoreModule::Decorator()->GetAccountUsedToAuthorize($oUser->PublicId); |
906: | if ($oAccount && $this->client) { |
907: | if (!$this->isDemoUser($oUser->PublicId)) { |
908: | $sPassword = $oAccount->getPassword(); |
909: | } else { |
910: | $sPassword = $this->sDemoPass; |
911: | } |
912: | Api::AddSecret($sPassword); |
913: | try { |
914: | $res = $this->client->post('login', [ |
915: | 'form_params' => [ |
916: | 'user' => $this->getUserNameFromEmail($oUser->PublicId), |
917: | 'password' => $sPassword |
918: | ], |
919: | 'http_errors' => false |
920: | ]); |
921: | if ($res->getStatusCode() === 200) { |
922: | $mResult = \json_decode($res->getBody()); |
923: | $sLang = ''; |
924: | if (isset($mResult->data->me->settings->preferences->language)) { |
925: | $sLang = $mResult->data->me->settings->preferences->language; |
926: | } |
927: | $sUserLang = Utils::ConvertLanguageNameToShort($oUser->Language); |
928: | if ($sUserLang !== $sLang) { |
929: | $this->updateLanguage($mResult->data->userId, $mResult->data->authToken, $sUserLang); |
930: | } |
931: | } |
932: | } catch (ConnectException $oException) { |
933: | } |
934: | } |
935: | } |
936: | |
937: | return $mResult; |
938: | } |
939: | |
940: | protected function logout() |
941: | { |
942: | $mResult = false; |
943: | |
944: | if ($this->client) { |
945: | try { |
946: | $sAuthToken = isset($_COOKIE['RocketChatAuthToken']) ? $_COOKIE['RocketChatAuthToken'] : null; |
947: | $sUserId = isset($_COOKIE['RocketChatUserId']) ? $_COOKIE['RocketChatUserId'] : null; |
948: | if ($sAuthToken !== null && $sUserId !== null) { |
949: | $res = $this->client->post('logout', [ |
950: | 'headers' => [ |
951: | "X-Auth-Token" => $sAuthToken, |
952: | "X-User-Id" => $sUserId, |
953: | ], |
954: | 'http_errors' => false |
955: | ]); |
956: | if ($res->getStatusCode() === 200) { |
957: | $mResult = \json_decode($res->getBody()); |
958: | } |
959: | } |
960: | } catch (ConnectException $oException) { |
961: | Api::LogException($oException); |
962: | } |
963: | } |
964: | |
965: | return $mResult; |
966: | } |
967: | |
968: | protected function updateLanguage($sUserId, $sToken, $sLang) |
969: | { |
970: | if ($this->client) { |
971: | $this->client->post('users.setPreferences', [ |
972: | 'json' => [ |
973: | 'userId' => $sUserId, |
974: | 'data' => [ |
975: | "language" => $sLang |
976: | ] |
977: | ], |
978: | 'headers' => [ |
979: | "X-Auth-Token" => $sToken, |
980: | "X-User-Id" => $sUserId |
981: | ], |
982: | 'http_errors' => false |
983: | ]); |
984: | } |
985: | } |
986: | |
987: | protected function updateUserPassword($userInfo) |
988: | { |
989: | $mResult = false; |
990: | $oUser = Api::getAuthenticatedUser(); |
991: | if ($oUser) { |
992: | $oAccount = CoreModule::Decorator()->GetAccountUsedToAuthorize($oUser->PublicId); |
993: | if ($oAccount && $this->client) { |
994: | Api::AddSecret($oAccount->getPassword()); |
995: | $res = $this->client->post('users.update', [ |
996: | 'json' => [ |
997: | 'userId' => $userInfo->user->_id, |
998: | 'data' => [ |
999: | 'password' => $oAccount->getPassword() |
1000: | ] |
1001: | ], |
1002: | 'headers' => $this->getAdminHeaders(), |
1003: | 'http_errors' => false |
1004: | ]); |
1005: | $mResult = ($res->getStatusCode() === 200); |
1006: | } |
1007: | } |
1008: | |
1009: | return $mResult; |
1010: | } |
1011: | |
1012: | public function onBeforeDeleteUser(&$aArgs, &$mResult) |
1013: | { |
1014: | $client = null; |
1015: | $adminHeaders = null; |
1016: | $oAuthenticatedUser = Api::getAuthenticatedUser(); |
1017: | if ($oAuthenticatedUser && $oAuthenticatedUser->isNormalOrTenant() && |
1018: | $oAuthenticatedUser->Id === (int) $aArgs['UserId'] |
1019: | ) { |
1020: | |
1021: | $client = $this->client; |
1022: | $adminHeaders = $this->getAdminHeaders(); |
1023: | } else { |
1024: | $oUser = Api::getUserById((int) $aArgs['UserId']); |
1025: | if ($oUser) { |
1026: | if ($oAuthenticatedUser->Role === UserRole::TenantAdmin && $oUser->IdTenant === $oAuthenticatedUser->IdTenant) { |
1027: | \Aurora\System\Api::checkUserRoleIsAtLeast(UserRole::TenantAdmin); |
1028: | } elseif ($oAuthenticatedUser->Role === UserRole::SuperAdmin) { |
1029: | \Aurora\System\Api::checkUserRoleIsAtLeast(UserRole::SuperAdmin); |
1030: | } |
1031: | |
1032: | $client = $this->getClient($oUser->IdTenant); |
1033: | $adminHeaders = $this->getAdminHeaders($oUser->IdTenant); |
1034: | } |
1035: | } |
1036: | |
1037: | $sUserName = $this->getUserNameFromEmail(Api::getUserPublicIdById($aArgs['UserId'])); |
1038: | try { |
1039: | if ($client) { |
1040: | $oRes = $client->post('users.delete', [ |
1041: | 'json' => [ |
1042: | 'username' => $sUserName |
1043: | ], |
1044: | 'headers' => $adminHeaders, |
1045: | 'http_errors' => false, |
1046: | 'timeout' => 1 |
1047: | ]); |
1048: | if ($oRes->getStatusCode() === 200) { |
1049: | $mResult = true; |
1050: | } |
1051: | } |
1052: | } catch (ConnectException $oException) { |
1053: | \Aurora\System\Api::Log('Cannot delete ' . $sUserName . ' user from RocketChat. Exception is below.'); |
1054: | \Aurora\System\Api::LogException($oException); |
1055: | } |
1056: | } |
1057: | |
1058: | public function onAfterLogout($aArgs, &$mResult) |
1059: | { |
1060: | $sSameSite = CoreModule::getInstance()->oModuleSettings->CookieSameSite; |
1061: | |
1062: | \Aurora\System\Api::setCookie( |
1063: | 'RocketChatAuthToken', |
1064: | '', |
1065: | -1, |
1066: | true, |
1067: | $sSameSite |
1068: | ); |
1069: | \Aurora\System\Api::setCookie( |
1070: | 'RocketChatUserId', |
1071: | '', |
1072: | -1, |
1073: | true, |
1074: | $sSameSite |
1075: | ); |
1076: | } |
1077: | } |
1078: | |