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\OpenPgpWebclient;
9:
10: use Aurora\Modules\Contacts\Enums\StorageType;
11: use Aurora\Modules\Contacts\Classes\Contact;
12: use Aurora\Modules\Contacts\Enums\Access;
13: use Aurora\Modules\Contacts\Models\ContactCard;
14: use Aurora\System\Api;
15: use Aurora\System\Enums\UserRole;
16: use Aurora\System\Exceptions\ApiException;
17: use Aurora\System\Notifications;
18:
19: /**
20: * @license https://www.gnu.org/licenses/agpl-3.0.html AGPL-3.0
21: * @license https://afterlogic.com/products/common-licensing Afterlogic Software License
22: * @copyright Copyright (c) 2023, Afterlogic Corp.
23: *
24: * @property Settings $oModuleSettings
25: *
26: * @package Modules
27: */
28: class Module extends \Aurora\System\Module\AbstractWebclientModule
29: {
30: /**
31: * @return Module
32: */
33: public static function getInstance()
34: {
35: return parent::getInstance();
36: }
37:
38: /**
39: * @return Module
40: */
41: public static function Decorator()
42: {
43: return parent::Decorator();
44: }
45:
46: /**
47: * @return Settings
48: */
49: public function getModuleSettings()
50: {
51: return $this->oModuleSettings;
52: }
53:
54: public function init()
55: {
56: $this->subscribeEvent('Files::PopulateFileItem::after', array($this, 'onAfterPopulateFileItem'));
57: $this->subscribeEvent('Mail::GetBodyStructureParts', array($this, 'onGetBodyStructureParts'));
58: $this->subscribeEvent('Mail::ExtendMessageData', array($this, 'onExtendMessageData'));
59: $this->subscribeEvent('Contacts::CreateContact::after', array($this, 'onAfterCreateOrUpdateContact'));
60: $this->subscribeEvent('Contacts::UpdateContact::after', array($this, 'onAfterCreateOrUpdateContact'));
61: $this->subscribeEvent('Contacts::GetContacts::after', array($this, 'onAfterGetContacts'));
62: $this->subscribeEvent('Contacts::GetContactsByUids::after', array($this, 'onAfterGetContactsByUids'));
63: $this->subscribeEvent('System::CastExtendedProp', array($this, 'onCastExtendedProp'));
64: }
65:
66: /**
67: * @ignore
68: * @todo not used
69: * @param array $aArgs
70: * @param object $oItem
71: */
72: public function onAfterPopulateFileItem($aArgs, &$oItem)
73: {
74: if ($oItem && '.asc' === \strtolower(\substr(\trim($oItem->Name), -4))) {
75: if (class_exists('\Aurora\Modules\Files\Module')) {
76: $oFilesDecorator = \Aurora\Modules\Files\Module::Decorator();
77: if ($oFilesDecorator) {
78: $mResult = $oFilesDecorator->GetFileContent($aArgs['UserId'], $oItem->TypeStr, $oItem->Path, $oItem->Name);
79: if (isset($mResult)) {
80: $oItem->Content = $mResult;
81: }
82: }
83: }
84: }
85: }
86:
87: public function onGetBodyStructureParts($aParts, &$aResultParts)
88: {
89: foreach ($aParts as $oPart) {
90: if ($oPart instanceof \MailSo\Imap\BodyStructure && $oPart->ContentType() === 'text/plain' && '.asc' === \strtolower(\substr(\trim($oPart->FileName()), -4))) {
91: $aResultParts[] = $oPart;
92: }
93: }
94: }
95:
96: public function onExtendMessageData($aData, &$oMessage)
97: {
98: foreach ($aData as $aDataItem) {
99: $oPart = $aDataItem['Part'];
100: $bAsc = $oPart instanceof \MailSo\Imap\BodyStructure && $oPart->ContentType() === 'text/plain' && '.asc' === \strtolower(\substr(\trim($oPart->FileName()), -4));
101: $sData = $aDataItem['Data'];
102: if ($bAsc) {
103: $iMimeIndex = $oPart->PartID();
104: foreach ($oMessage->getAttachments()->GetAsArray() as $oAttachment) {
105: if ($iMimeIndex === $oAttachment->getMimeIndex()) {
106: $oAttachment->setContent($sData);
107: }
108: }
109: }
110: }
111: }
112:
113: public function onAfterCreateOrUpdateContact($aArgs, &$mResult)
114: {
115: if (isset($mResult['UUID']) && isset($aArgs['Contact']['PublicPgpKey'])) {
116: $sPublicPgpKey = $aArgs['Contact']['PublicPgpKey'];
117: if (empty(\trim($sPublicPgpKey))) {
118: $sPublicPgpKey = null;
119: }
120: $oContact = \Aurora\Modules\Contacts\Module::Decorator()->GetContact($mResult['UUID'], $aArgs['UserId']);
121: if ($oContact instanceof Contact) {
122: $needsToUpdate = false;
123: if (isset($sPublicPgpKey)) {
124: $oContact->setExtendedProp($this->GetName() . '::PgpKey', $sPublicPgpKey);
125: $needsToUpdate = true;
126: } elseif ($oContact->getExtendedProp($this->GetName() . '::PgpKey')) {
127: $oContact->unsetExtendedProp($this->GetName() . '::PgpKey');
128: $needsToUpdate = true;
129: }
130: if (isset($aArgs['Contact']['PgpEncryptMessages']) && is_bool($aArgs['Contact']['PgpEncryptMessages'])) {
131: if ($aArgs['Contact']['Storage'] !== StorageType::Team) {
132: if ($oContact->getExtendedProp($this->GetName() . '::PgpEncryptMessages') !== $aArgs['Contact']['PgpEncryptMessages']) {
133: $oContact->setExtendedProp($this->GetName() . '::PgpEncryptMessages', $aArgs['Contact']['PgpEncryptMessages']);
134: $needsToUpdate = true;
135: }
136: } elseif ($oContact->getExtendedProp($this->GetName() . '::PgpEncryptMessages_' . $aArgs['UserId']) !== $aArgs['Contact']['PgpEncryptMessages']) {
137: $oContact->setExtendedProp($this->GetName() . '::PgpEncryptMessages_' . $aArgs['UserId'], $aArgs['Contact']['PgpEncryptMessages']);
138: $needsToUpdate = true;
139: }
140: }
141: if (isset($aArgs['Contact']['PgpSignMessages']) && is_bool($aArgs['Contact']['PgpSignMessages'])) {
142: if ($aArgs['Contact']['Storage'] !== StorageType::Team) {
143: if ($oContact->getExtendedProp($this->GetName() . '::PgpSignMessages') !== $aArgs['Contact']['PgpSignMessages']) {
144: $oContact->setExtendedProp($this->GetName() . '::PgpSignMessages', $aArgs['Contact']['PgpSignMessages']);
145: $needsToUpdate = true;
146: }
147: } elseif ($oContact->getExtendedProp($this->GetName() . '::PgpSignMessages_' . $aArgs['UserId']) !== $aArgs['Contact']['PgpSignMessages']) {
148: $oContact->setExtendedProp($this->GetName() . '::PgpSignMessages_' . $aArgs['UserId'], $aArgs['Contact']['PgpSignMessages']);
149: $needsToUpdate = true;
150: }
151: }
152: if ($needsToUpdate) {
153: $oContact->saveExtendedProps();
154: }
155: if (is_array($mResult) && isset($mResult['ETag'])) {
156: $mResult['ETag'] = $oContact->ETag;
157: }
158: }
159: }
160: }
161:
162: /**
163: * The function copies values of user-related properties to the properties with original names.
164: * Then it removes the user-related flags cause they should be exposed to a user.
165: */
166: public function onAfterGetContacts($aArgs, &$mResult)
167: {
168: if (isset($aArgs['UserId']) && isset($mResult['List']) && count($mResult['List']) > 0) {
169: $aContactUUIDs = array_map(function ($aValue) { return $aValue['UUID']; }, $mResult['List']);
170: $aContactCards = ContactCard::whereIn('CardId', $aContactUUIDs)->whereNotNull('Properties->' . $this->GetName() . '::PgpKey')->get();
171: $aContactCardsSorted = array();
172: $sEncryptPropName = $this->GetName() . '::PgpEncryptMessages';
173: $sSignPropName = $this->GetName() . '::PgpSignMessages';
174:
175: foreach ($aContactCards as $oContactCard) {
176: if ($oContactCard->getExtendedProp($this->GetName() . '::PgpKey') !== '') {
177: $aContactCardsSorted[$oContactCard->CardId] = $oContactCard;
178: }
179: }
180:
181: foreach ($mResult['List'] as &$aContact) {
182: $aContact['HasPgpPublicKey'] = false;
183: $aContact['PgpEncryptMessages'] = false;
184: $aContact['PgpSignMessages'] = false;
185:
186: if (isset($aContactCardsSorted[$aContact['UUID']])) {
187: $oContactCard = $aContactCardsSorted[$aContact['UUID']];
188: $aContact['HasPgpPublicKey'] = true;
189:
190: if (!empty($aContact['IsTeam'])) {
191: $aContact['PgpEncryptMessages'] = (bool) $oContactCard->getExtendedProp($sEncryptPropName . '_' . $aArgs['UserId'], false);
192: $aContact['PgpSignMessages'] = (bool) $oContactCard->getExtendedProp($sSignPropName . '_' . $aArgs['UserId'], false);
193: } else {
194: $aContact['PgpEncryptMessages'] = (bool) $oContactCard->getExtendedProp($sEncryptPropName, false);
195: $aContact['PgpSignMessages'] = (bool) $oContactCard->getExtendedProp($sSignPropName, false);
196: }
197: }
198:
199: // remove OpenPGPWebclient properties
200: if (isset($aContact['Properties'])) {
201: foreach ($aContact['Properties'] as $sPropName => $sPropValue) {
202: if (strpos($sPropName, $this->GetName() . '::') !== false) {
203: unset($aContact['Properties'][$sPropName]);
204: }
205: }
206: }
207: }
208: }
209: }
210:
211: /**
212: * The function copies values of user-related properties to the properties with original names.
213: * Then it removes the user-related flags cause they should be exposed to a user.
214: */
215: public function onAfterGetContactsByUids($aArgs, &$mResult)
216: {
217: if (isset($aArgs['UserId']) && isset($mResult)) {
218: foreach ($mResult as $oContact) {
219: if ($oContact instanceof Contact) {
220: // add a srting property if it's missing or null
221: if (!$oContact->getExtendedProp($this->GetName() . '::PgpKey')) {
222: $oContact->setExtendedProp($this->GetName() . '::PgpKey', '');
223: }
224:
225: if ($oContact->Storage === StorageType::Team) {
226: $sEncryptPropName = $this->GetName() . '::PgpEncryptMessages';
227: $sSignPropName = $this->GetName() . '::PgpSignMessages';
228:
229: // copy user-related values to main properties
230: $oContact->setExtendedProp($sEncryptPropName, $oContact->getExtendedProp($sEncryptPropName . '_' . $aArgs['UserId']) || false);
231: $oContact->setExtendedProp($sSignPropName, $oContact->getExtendedProp($sSignPropName . '_' . $aArgs['UserId']) || false);
232:
233: // remove user-related values from properties
234: foreach ($oContact->Properties as $sPropName => $sPropValue) {
235: if (strpos($sPropName, $sEncryptPropName . '_') !== false || strpos($sPropName, $sSignPropName . '_') !== false) {
236: $oContact->unsetExtendedProp($sPropName);
237: }
238: }
239: }
240: }
241: }
242: }
243: }
244:
245: public function onCastExtendedProp($aArgs, &$mValue)
246: {
247: if ($aArgs['Model'] instanceof ContactCard &&
248: ($aArgs['PropertyName'] === $this->GetName() . '::PgpEncryptMessages' ||
249: $aArgs['PropertyName'] === $this->GetName() . '::PgpSignMessages')) {
250: $mValue = (bool) $mValue;
251: }
252: }
253:
254: /***** public functions might be called with web API *****/
255: /**
256: * Obtains list of module settings for authenticated user.
257: *
258: * @return array
259: */
260: public function GetSettings()
261: {
262: Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::Anonymous);
263:
264: $aSettings = [
265: 'EnableModule' => false,
266: 'RememberPassphrase' => false
267: ];
268: $oUser = Api::getAuthenticatedUser();
269: if ($oUser && $oUser->isNormalOrTenant()) {
270: if (null !== $oUser->getExtendedProp(self::GetName() . '::EnableModule')) {
271: $aSettings['EnableModule'] = $oUser->getExtendedProp(self::GetName() . '::EnableModule');
272: }
273: if (null !== $oUser->getExtendedProp(self::GetName() . '::RememberPassphrase')) {
274: $aSettings['RememberPassphrase'] = $oUser->getExtendedProp(self::GetName() . '::RememberPassphrase');
275: }
276: }
277: return $aSettings;
278: }
279:
280: public function UpdateSettings($EnableModule, $RememberPassphrase)
281: {
282: Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::NormalUser);
283:
284: $oUser = Api::getAuthenticatedUser();
285: if ($oUser) {
286: if ($oUser->isNormalOrTenant()) {
287: $oCoreDecorator = \Aurora\Modules\Core\Module::Decorator();
288: $oUser->setExtendedProp(self::GetName() . '::EnableModule', $EnableModule);
289: if (isset($RememberPassphrase)) {
290: $oUser->setExtendedProp(self::GetName() . '::RememberPassphrase', $RememberPassphrase);
291: }
292: return $oCoreDecorator->UpdateUserObject($oUser);
293: }
294: if ($oUser->Role === \Aurora\System\Enums\UserRole::SuperAdmin) {
295: return true;
296: }
297: }
298:
299: return false;
300: }
301:
302: /**
303: * Summary of AddPublicKeyToContactWithUUID
304: * @param int $UserId
305: * @param mixed $UUID
306: * @param string $Key
307: * @throws \Aurora\System\Exceptions\ApiException
308: * @return bool
309: */
310: public function AddPublicKeyToContactWithUUID($UserId, $UUID, $Key)
311: {
312: Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::NormalUser);
313:
314: $contact = \Aurora\Modules\Contacts\Module::Decorator()->GetContact($UUID, $UserId);
315: if ($contact instanceof Contact) {
316: $user = Api::getUserById($UserId);
317:
318: if (!\Aurora\Modules\Contacts\Module::Decorator()->CheckAccessToObject($user, $contact, Access::Write)) {
319: throw new \Aurora\System\Exceptions\ApiException(\Aurora\System\Notifications::AccessDenied);
320: }
321:
322: if (\Aurora\Modules\Contacts\Module::Decorator()->UpdateContactObject($contact)) {
323: $contact->setExtendedProp($this->GetName() . '::PgpKey', $Key);
324: return !!$contact->saveExtendedProps();
325: }
326: }
327:
328: return false;
329: }
330:
331: public function AddPublicKeyToContact($UserId, $Email, $Key, $UserName = '')
332: {
333: Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::NormalUser);
334:
335: $bResult = false;
336: $aUpdatedContactIds = [];
337: if (\MailSo\Base\Validator::SimpleEmailString($Email)) {
338: $aContacts = \Aurora\Modules\Contacts\Module::Decorator()->GetContactsByEmails(
339: $UserId,
340: StorageType::Personal,
341: [$Email]
342: );
343: if (count($aContacts) === 0) {
344: $mResult = \Aurora\Modules\Contacts\Module::Decorator()->CreateContact(
345: [
346: 'PersonalEmail' => $Email,
347: 'FullName' => $UserName,
348: 'Storage' => StorageType::Personal
349: ],
350: $UserId
351: );
352: if (isset($mResult['UUID'])) {
353: $oContact = \Aurora\Modules\Contacts\Module::Decorator()->GetContact($mResult['UUID'], $UserId);
354: if ($oContact instanceof Contact) {
355: $aContacts = [$oContact];
356: }
357: }
358: }
359:
360: if ($aContacts && count($aContacts) > 0) {
361: foreach ($aContacts as $oContact) {
362: $properties = $oContact->getExtendedProps();
363: $properties[$this->GetName() . '::PgpKey'] = $Key;
364: ContactCard::where('CardId', $oContact->Id)->update(['Properties' => $properties]);
365: $aUpdatedContactIds[] = $oContact->Id;
366: }
367: }
368: }
369:
370: return $aUpdatedContactIds;
371: }
372:
373: public function AddPublicKeysToContacts($UserId, $Keys)
374: {
375: $mResult = false;
376: $aUpdatedContactIds = [];
377:
378: foreach ($Keys as $aKey) {
379: if (isset($aKey['Email'], $aKey['Key'])) {
380: $sUserName = isset($aKey['Name']) ? $aKey['Name'] : '';
381: $mResult = $this->AddPublicKeyToContact($UserId, $aKey['Email'], $aKey['Key'], $sUserName);
382: if (is_array($mResult)) {
383: $aUpdatedContactIds = array_merge($aUpdatedContactIds, $mResult);
384: }
385: }
386: }
387:
388: return $aUpdatedContactIds;
389: }
390:
391: public function RemovePublicKeyFromContact($UserId, $Email)
392: {
393: Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::NormalUser);
394:
395: $bResult = false;
396:
397: if (\MailSo\Base\Validator::SimpleEmailString($Email)) {
398: $aContacts = \Aurora\Modules\Contacts\Module::Decorator()->GetContactsByEmails(
399: $UserId,
400: StorageType::All,
401: [$Email]
402: );
403: if ($aContacts && count($aContacts) > 0) {
404: foreach ($aContacts as $oContact) {
405: if ($oContact instanceof ContactCard && !$oContact->IsTeam && !$oContact->Shared) {
406:
407: $properties = $oContact->getExtendedProps();
408: $properties[$this->GetName() . '::PgpKey'] = null;
409:
410: ContactCard::where('CardId', $oContact->Id)->update(['Properties' => $properties]);
411: }
412: }
413:
414: $bResult = true;
415: }
416: }
417:
418: return $bResult;
419: }
420:
421: /**
422: * The method returns list of PGP public keys with their ViewEmails for specified contacts.
423: *
424: * @param int $UserId User ID. Provided automatically by WebAPI wrapper.
425: * @param array $ContactUUIDs List of contact IDs.
426: *
427: * @return array
428: */
429: public function GetPublicKeysByCountactUUIDs($UserId, $ContactUUIDs)
430: {
431: Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::NormalUser);
432:
433: $aResult = [];
434:
435: if (count($ContactUUIDs)) {
436: $aContacts = \Aurora\Modules\Contacts\Module::Decorator()->GetContactsByUids($UserId, $ContactUUIDs);
437: if (is_array($aContacts) && count($aContacts) > 0) {
438: foreach ($aContacts as $oContact) {
439: $aResult[] = [
440: 'Email' => $oContact->ViewEmail,
441: 'PublicPgpKey' => $oContact->getExtendedProp($this->GetName() . '::PgpKey')
442: ];
443: }
444: }
445: }
446:
447: return $aResult;
448: }
449:
450: public function GetPublicKeysFromContacts($UserId)
451: {
452: Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::NormalUser);
453:
454: $aResult = [];
455:
456: $aContactsInfo = \Aurora\Modules\Contacts\Module::Decorator()->GetContactsInfo(
457: StorageType::All,
458: $UserId,
459: ContactCard::whereNotNull('Properties->' . $this->GetName() . '::PgpKey')
460: );
461:
462: $aContactUUIDs = [];
463: if (is_array($aContactsInfo['Info']) && count($aContactsInfo['Info']) > 0) {
464: $aContactUUIDs = array_map(function ($aValue) {
465: if (!$aValue['IsTeam'] && !$aValue['Shared']) {
466: return $aValue['UUID'];
467: }
468: }, $aContactsInfo['Info']);
469: }
470: $aResult = $this->Decorator()->GetPublicKeysByCountactUUIDs($UserId, $aContactUUIDs);
471:
472: return $aResult;
473: }
474:
475: protected function updatePublicKeyFlags($UserId, $oContact, $PgpEncryptMessages = false, $PgpSignMessages = false)
476: {
477: $mResult = false;
478:
479: if (class_exists('\Aurora\Modules\TeamContacts\Module')) {
480: $oTeamContactsDecorator = \Aurora\Modules\TeamContacts\Module::Decorator();
481: if ($oTeamContactsDecorator && $oContact instanceof Contact) {
482: $properties = $oContact->getExtendedProps();
483:
484: $addressbook = $oTeamContactsDecorator->GetTeamAddressbook($UserId);
485: if ($addressbook && $oContact->AddressBookId == $addressbook['id']) {
486: $properties[$this->GetName() . '::PgpEncryptMessages_' . $UserId] = $PgpEncryptMessages;
487: $properties[$this->GetName() . '::PgpSignMessages_' . $UserId] = $PgpSignMessages;
488: } else {
489: $properties[$this->GetName() . '::PgpEncryptMessages'] = $PgpEncryptMessages;
490: $properties[$this->GetName() . '::PgpSignMessages'] = $PgpSignMessages;
491: }
492:
493: ContactCard::where('CardId', $oContact->Id)->update(['Properties' => $properties]);
494:
495: $mResult = true;
496: }
497: }
498:
499: return $mResult;
500: }
501:
502: public function UpdateContactPublicKeyFlags($UserId, $UUID, $PgpEncryptMessages = false, $PgpSignMessages = false)
503: {
504: $oContact = \Aurora\Modules\Contacts\Module::Decorator()->GetContact($UUID, $UserId);
505: $mResult = $this->updatePublicKeyFlags($UserId, $oContact, $PgpEncryptMessages, $PgpSignMessages);
506:
507: return $mResult;
508: }
509:
510: protected function getTeamContactByUser($oUser)
511: {
512: $mResult = false;
513:
514: if (Api::GetModuleManager()->IsAllowedModule('TeamContacts')) {
515: $aContacts = \Aurora\Modules\Contacts\Module::Decorator()->GetContactsByEmails(
516: $oUser->Id,
517: \Aurora\Modules\Contacts\Enums\StorageType::Team,
518: [$oUser->PublicId]
519: );
520: if ($aContacts && count($aContacts) > 0) {
521: $oContact = $aContacts[0];
522: if ($oContact instanceof ContactCard) {
523: $mResult = $oContact;
524: }
525: }
526: }
527:
528: return $mResult;
529: }
530:
531: public function UpdateOwnContactPublicKey($UserId, $PublicPgpKey = '')
532: {
533: $mResult = false;
534:
535: Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::NormalUser);
536: $oUser = Api::getAuthenticatedUser();
537: if ($oUser) {
538: if ($oUser->Id === $UserId) {
539: $oContactCard = $this->getTeamContactByUser($oUser);
540: if ($oContactCard instanceof ContactCard) {
541: $properties = $oContactCard->Properties;
542: if (!empty($PublicPgpKey)) {
543: $properties[$this->GetName() . '::PgpKey'] = $PublicPgpKey;
544:
545: } else {
546: unset($properties[$this->GetName() . '::PgpKey']);
547: }
548: $mResult = !!ContactCard::where('CardId', $oContactCard->Id)->update(['Properties' => $properties]);
549: }
550: }
551: }
552:
553: return $mResult;
554: }
555:
556: public function GetOwnContactPublicKey($UserId)
557: {
558: $mResult = false;
559:
560: Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::NormalUser);
561:
562: $oUser = Api::getAuthenticatedUser();
563: if ($oUser) {
564: if ($oUser->Id === $UserId) {
565: $oContactCard = $this->getTeamContactByUser($oUser);
566: if ($oContactCard instanceof ContactCard) {
567: $mResult = $oContactCard->getExtendedProp($this->GetName() . '::PgpKey', false);
568: }
569: }
570: }
571:
572: return $mResult;
573: }
574:
575: /**
576: *
577: * @param int $UserId
578: * @param string $Content
579: * @param string $FileName
580: * @return array|bool
581: * @throws ApiException
582: */
583: public function SaveKeyAsTempFile($UserId, $Content, $FileName)
584: {
585: $mResult = false;
586: Api::checkUserRoleIsAtLeast(UserRole::NormalUser);
587:
588: $ext = '';
589: $fileInfo = pathinfo($FileName);
590: if (isset($fileInfo['extension'])) {
591: $ext = strtolower($fileInfo['extension']);
592: }
593:
594: if ($ext !== 'asc') {
595: throw new ApiException(Notifications::FilesNotAllowed);
596: }
597:
598: $sUUID = Api::getUserUUIDById($UserId);
599: try {
600: $sTempName = md5($sUUID . $Content . $FileName);
601: $oApiFileCache = new \Aurora\System\Managers\Filecache();
602:
603: if (!$oApiFileCache->isFileExists($sUUID, $sTempName)) {
604: $oApiFileCache->put($sUUID, $sTempName, $Content);
605: }
606:
607: if ($oApiFileCache->isFileExists($sUUID, $sTempName)) {
608: $mResult = \Aurora\System\Utils::GetClientFileResponse(
609: null,
610: $UserId,
611: $FileName,
612: $sTempName,
613: $oApiFileCache->fileSize($sUUID, $sTempName)
614: );
615: }
616: } catch (\Exception $oException) {
617: throw new ApiException(Notifications::FilesNotAllowed, $oException, $oException->getMessage());
618: }
619:
620: return $mResult;
621: }
622: /***** public functions might be called with web API *****/
623: }
624: