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\TwoFactorAuth;
9:
10: use Aurora\Modules\TwoFactorAuth\Models\UsedDevice;
11:
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: class Manager extends \Aurora\System\Managers\AbstractManager
18: {
19: /**
20: * @var \Aurora\Modules\TwoFactorAuth\Module
21: */
22: protected $oModule = null;
23:
24: /**
25: * @param \Aurora\Modules\TwoFactorAuth\Module $oModule
26: */
27: public function __construct(\Aurora\Modules\TwoFactorAuth\Module $oModule = null)
28: {
29: parent::__construct($oModule);
30: }
31:
32: public function isTrustedDevicesEnabled()
33: {
34: $iTrustDevicesForDays = $this->oModule->getModuleSettings()->TrustDevicesForDays;
35: return $this->oModule->getModuleSettings()->AllowUsedDevices && is_int($iTrustDevicesForDays) && $iTrustDevicesForDays > 0;
36: }
37:
38: public function getAllDevices($iUserId)
39: {
40: return UsedDevice::where('UserId', $iUserId)
41: ->orderBy('LastUsageDateTime', 'desc')
42: ->get();
43: }
44:
45: /**
46: * @param int $iUserId
47: * @param string $sDeviceId
48: *
49: * @return UsedDevice
50: */
51: public function getDevice($iUserId, $sDeviceId)
52: {
53: return UsedDevice::where('UserId', $iUserId)
54: ->where('DeviceId', $sDeviceId)
55: ->first();
56: }
57:
58: /**
59: * @param string $sDeviceId
60: *
61: * @return UsedDevice
62: */
63: public function getDeviceByDeviceId($sDeviceId)
64: {
65: return UsedDevice::where('DeviceId', $sDeviceId)
66: ->first();
67: }
68:
69: public function getDeviceByAuthToken($iUserId, $sAuthToken)
70: {
71: return UsedDevice::where('UserId', $iUserId)
72: ->where('AuthToken', $sAuthToken)
73: ->first();
74: }
75:
76: public function checkDeviceAfterAuthenticate($oUser)
77: {
78: $bDeviceTrusted = false;
79: $sDeviceId = \Aurora\System\Api::getDeviceIdFromHeaders();
80: if ($sDeviceId && $this->oModule->getModuleSettings()->TrustDevicesForDays > 0) {
81: $oUsedDevice = $this->getDevice($oUser->Id, $sDeviceId);
82: if ($oUsedDevice) {
83: if ($oUsedDevice->TrustTillDateTime > time()) {
84: $bDeviceTrusted = true;
85: $oUsedDevice->LastUsageDateTime = time();
86: $oUsedDevice->save();
87: }
88: }
89: }
90: return $bDeviceTrusted;
91: }
92:
93: public function trustDevice($iUserId, $sDeviceId, $sDeviceName, $sAuthToken = '')
94: {
95: $oUsedDevice = $this->getDevice($iUserId, $sDeviceId);
96: if (!$oUsedDevice) {
97: if ($this->saveDevice($iUserId, $sDeviceId, $sDeviceName, $sAuthToken)) {
98: $oUsedDevice = $this->getDevice($iUserId, $sDeviceId);
99: }
100: } else {
101: $oUsedDevice->DeviceName = $sDeviceName;
102: }
103:
104: if ($this->isTrustedDevicesEnabled()) {
105: $iTrustDevicesForDays = $this->oModule->getModuleSettings()->TrustDevicesForDays;
106: $oUsedDevice->TrustTillDateTime = time() + $iTrustDevicesForDays * 24 * 60 * 60;
107: } else {
108: $oUsedDevice->TrustTillDateTime = $oUsedDevice->CreationDateTime;
109: }
110:
111: return $oUsedDevice->save();
112: }
113:
114: public function setDeviceName($iUserId, $sDeviceId, $sDeviceName)
115: {
116: $result = false;
117: $oUsedDevice = $this->getDevice($iUserId, $sDeviceId);
118: if ($oUsedDevice) {
119: $oUsedDevice->DeviceName = $sDeviceName;
120: $result = $oUsedDevice->save();
121: }
122:
123: return $result;
124: }
125:
126: public function setDeviceCustomName($iUserId, $sDeviceId, $DeviceCustomName)
127: {
128: $result = false;
129: $oUsedDevice = $this->getDevice($iUserId, $sDeviceId);
130: if ($oUsedDevice) {
131: $oUsedDevice->DeviceCustomName = $DeviceCustomName;
132: $result = $oUsedDevice->save();
133: }
134:
135: return $result;
136: }
137:
138: public function saveDevice($iUserId, $sDeviceId, $sDeviceName, $sAuthToken)
139: {
140: $oUsedDevice = $this->getDevice($iUserId, $sDeviceId);
141: if (!$oUsedDevice) {
142: $oUsedDevice = $this->_createUsedDevice($iUserId, $sDeviceId, $sDeviceName);
143: } else {
144: if (!empty($sDeviceName)) {
145: $oUsedDevice->DeviceName = $sDeviceName;
146: }
147: // $_SERVER['REMOTE_ADDR'] may not actually contain real client IP addresses, as it will give you a proxy address for clients connected through a proxy, for example.
148: // But the client can set all HTTP header information (ie. $_SERVER['HTTP_CLIENT_IP'], $_SERVER['HTTP_X_FORWARDED_FOR']) to any arbitrary value it wants, so we cannot rely on them.
149: $oUsedDevice->DeviceIP = $_SERVER['REMOTE_ADDR'];
150: }
151:
152: $oUsedDevice->AuthToken = $sAuthToken;
153: $oUsedDevice->LastUsageDateTime = time();
154:
155: return $oUsedDevice->save();
156: }
157:
158: public function deleteDeviceByID($iId)
159: {
160: return !!UsedDevice::where('Id', $iId)->delete();
161: }
162:
163: public function revokeTrustFromAllDevices($oUser)
164: {
165: $mResult = true;
166: $aTrustedDevices = $this->getAllDevices($oUser->Id);
167: foreach ($aTrustedDevices as $oUsedDevice) {
168: $oUsedDevice->TrustTillDateTime = $oUsedDevice->CreationDateTime;
169: $mResult = $mResult && $oUsedDevice->save();
170: }
171: return $mResult;
172: }
173:
174: private function _createUsedDevice($iUserId, $sDeviceId, $sDeviceName)
175: {
176: $oUsedDevice = new UsedDevice();
177: $oUsedDevice->UserId = $iUserId;
178: $oUsedDevice->DeviceId = $sDeviceId;
179: $oUsedDevice->DeviceName = $sDeviceName;
180: $oUsedDevice->CreationDateTime = time();
181: $oUsedDevice->TrustTillDateTime = $oUsedDevice->CreationDateTime;
182: $oUsedDevice->LastUsageDateTime = $oUsedDevice->CreationDateTime;
183:
184: // $_SERVER['REMOTE_ADDR'] may not actually contain real client IP addresses, as it will give you a proxy address for clients connected through a proxy, for example.
185: // But the client can set all HTTP header information (ie. $_SERVER['HTTP_CLIENT_IP'], $_SERVER['HTTP_X_FORWARDED_FOR']) to any arbitrary value it wants, so we cannot rely on them.
186: $oUsedDevice->DeviceIP = $_SERVER['REMOTE_ADDR'];
187:
188: return $oUsedDevice;
189: }
190: }
191: