1: | <?php |
2: | |
3: | |
4: | |
5: | |
6: | |
7: | |
8: | namespace Aurora\System; |
9: | |
10: | use Aurora\System\Models\AuthToken; |
11: | |
12: | |
13: | |
14: | |
15: | |
16: | |
17: | |
18: | |
19: | class UserSession |
20: | { |
21: | public const TOKEN_VERSION = '3.1'; |
22: | |
23: | public static $aTokensCache = []; |
24: | |
25: | public static function getTokenData($oAccount, $bSignMe = true) |
26: | { |
27: | return [ |
28: | 'token' => 'auth', |
29: | 'sign-me' => $bSignMe, |
30: | 'id' => $oAccount->IdUser, |
31: | 'account' => $oAccount->Id, |
32: | 'account_type' => get_class($oAccount) |
33: | ]; |
34: | } |
35: | |
36: | |
37: | public function Set($aData, $iTime = 0, $iExpire = 0) |
38: | { |
39: | $aData['@time'] = $iTime; |
40: | $aData['@expire'] = $iExpire; |
41: | $aData['@ver'] = self::TOKEN_VERSION; |
42: | if ($iExpire > 0) { |
43: | $aData['@expire'] = $iExpire; |
44: | } |
45: | $sAuthToken = Api::EncodeKeyValues( |
46: | $aData |
47: | ); |
48: | |
49: | if (\Aurora\Api::GetSettings()->GetValue('StoreAuthTokenInDB', false)) { |
50: | |
51: | $account = $aData['account'] ?? 0; |
52: | $account_type = $aData['account_type'] ?? ''; |
53: | |
54: | $this->SetToDB($aData['id'], $account, $account_type, $sAuthToken); |
55: | } |
56: | |
57: | return $sAuthToken; |
58: | } |
59: | |
60: | public function UpdateTimestamp($sAuthToken, $iTime = 0) |
61: | { |
62: | $aData = $this->Get($sAuthToken); |
63: | return $this->Set($aData, $iTime); |
64: | } |
65: | |
66: | public function Get($sAuthToken) |
67: | { |
68: | $mAuthTokenData = false; |
69: | $mResult = true; |
70: | |
71: | if (is_string($sAuthToken) && strlen($sAuthToken) !== 0) { |
72: | $bStoreAuthTokenInDB = \Aurora\Api::GetSettings()->GetValue('StoreAuthTokenInDB', false); |
73: | |
74: | |
75: | if ($bStoreAuthTokenInDB && !$this->GetFromDB($sAuthToken)) { |
76: | return false; |
77: | } |
78: | |
79: | $mAuthTokenData = Api::DecodeKeyValues($sAuthToken); |
80: | |
81: | |
82: | if ($mAuthTokenData && isset($mAuthTokenData['id'])) { |
83: | $oUser = Api::getUserById((int) $mAuthTokenData['id']); |
84: | |
85: | |
86: | if ($oUser && $oUser->IsDisabled) { |
87: | $mResult = false; |
88: | } |
89: | |
90: | |
91: | if ($mResult) { |
92: | if ((isset($mAuthTokenData['@ver']) && $mAuthTokenData['@ver'] !== self::TOKEN_VERSION) || !isset($mAuthTokenData['@ver'])) { |
93: | $mResult = false; |
94: | } |
95: | } |
96: | |
97: | |
98: | if ($mResult) { |
99: | $iExpireTime = (int) isset($mAuthTokenData['@expire']) ? $mAuthTokenData['@expire'] : 0; |
100: | if ($iExpireTime > 0 && $iExpireTime < time()) { |
101: | $mResult = false; |
102: | } |
103: | } |
104: | |
105: | |
106: | if ($mResult && isset($mAuthTokenData['account'], $mAuthTokenData['account_type']) && class_exists($mAuthTokenData['account_type'])) { |
107: | $iTime = (int) $mAuthTokenData['@time']; |
108: | $oAccount = $mAuthTokenData['account_type']::where('Id', $mAuthTokenData['account'])->first(); |
109: | if ($oAccount && $iTime !== 0 && (int) $oAccount->getExtendedProp('TokensValidFromTimestamp') > $iTime) { |
110: | $mResult = false; |
111: | } |
112: | } |
113: | |
114: | |
115: | if ($mResult) { |
116: | if ((isset($mAuthTokenData['sign-me']) && !((bool) $mAuthTokenData['sign-me'])) || (!isset($mAuthTokenData['sign-me']))) { |
117: | $iTime = 0; |
118: | if (isset($mAuthTokenData['@time'])) { |
119: | $iTime = (int) $mAuthTokenData['@time']; |
120: | } |
121: | $iExpireUserSessionsBeforeTimestamp = \Aurora\System\Api::GetSettings()->GetValue("ExpireUserSessionsBeforeTimestamp", 0); |
122: | if ($iExpireUserSessionsBeforeTimestamp > $iTime && $iTime > 0) { |
123: | $mResult = false; |
124: | } |
125: | } |
126: | } |
127: | } else { |
128: | $mResult = false; |
129: | } |
130: | |
131: | if (!$mResult) { |
132: | $this->Delete($sAuthToken); |
133: | $mAuthTokenData = $mResult; |
134: | |
135: | \Aurora\System\Api::Log('User session expired: '); |
136: | \Aurora\System\Api::LogObject($mAuthTokenData); |
137: | } |
138: | } |
139: | |
140: | return $mAuthTokenData; |
141: | } |
142: | |
143: | public function Delete($sAuthToken) |
144: | { |
145: | if (is_string($sAuthToken) && \Aurora\Api::GetSettings()->GetValue('StoreAuthTokenInDB', false)) { |
146: | try { |
147: | $this->DeleteFromDB($sAuthToken); |
148: | } catch (\Aurora\System\Exceptions\DbException $oEx) { |
149: | |
150: | } |
151: | } |
152: | } |
153: | |
154: | public function DeleteAllUserSessions($iUserId) |
155: | { |
156: | return AuthToken::where('UserId', $iUserId)->delete(); |
157: | } |
158: | |
159: | public function DeleteAllAccountSessions($oAccount) |
160: | { |
161: | if ($oAccount instanceof \Aurora\System\Classes\Account) { |
162: | $iAccountId = $oAccount->Id; |
163: | $sAccountType = get_class($oAccount); |
164: | if (\Aurora\Api::GetSettings()->GetValue('StoreAuthTokenInDB', false)) { |
165: | try { |
166: | AuthToken::where('AccountId', $iAccountId)->where('AccountType', $sAccountType)->delete(); |
167: | } catch (\Aurora\System\Exceptions\DbException $oEx) { |
168: | |
169: | } |
170: | } else { |
171: | if (class_exists($sAccountType)) { |
172: | $oAccount = $sAccountType::where('Id', $iAccountId)->first(); |
173: | if ($oAccount) { |
174: | $oAccount->setExtendedProp('TokensValidFromTimestamp', time()); |
175: | $oAccount->save(); |
176: | } |
177: | } |
178: | } |
179: | } |
180: | } |
181: | |
182: | public function SetToDB($iUserId, $iAccountId, $sAccountType, $sAuthToken) |
183: | { |
184: | $oAuthToken = AuthToken::where('UserId', $iUserId) |
185: | ->where('AccountId', $iAccountId) |
186: | ->where('AccountType', $sAccountType) |
187: | ->where('Token', $sAuthToken) |
188: | ->first(); |
189: | |
190: | if (!$oAuthToken) { |
191: | $oAuthToken = new AuthToken(); |
192: | } |
193: | $oAuthToken->UserId = $iUserId; |
194: | $oAuthToken->AccountId = $iAccountId; |
195: | $oAuthToken->AccountType = $sAccountType; |
196: | $oAuthToken->Token = $sAuthToken; |
197: | $oAuthToken->LastUsageDateTime = time(); |
198: | |
199: | try { |
200: | $oAuthToken->save(); |
201: | } catch (\Aurora\System\Exceptions\DbException $oEx) { |
202: | |
203: | } |
204: | } |
205: | |
206: | public function GetFromDB($sAuthToken) |
207: | { |
208: | if (!isset(self::$aTokensCache[$sAuthToken])) { |
209: | try { |
210: | $oAuthToken = AuthToken::firstWhere('Token', $sAuthToken); |
211: | if ($oAuthToken) { |
212: | $oAuthToken->LastUsageDateTime = time(); |
213: | $oAuthToken->save(); |
214: | self::$aTokensCache[$sAuthToken] = $oAuthToken; |
215: | } |
216: | } catch (\Aurora\System\Exceptions\DbException $oEx) { |
217: | \Aurora\Api::LogException($oEx); |
218: | } |
219: | } |
220: | return isset(self::$aTokensCache[$sAuthToken]) ? self::$aTokensCache[$sAuthToken] : false; |
221: | } |
222: | |
223: | public function DeleteFromDB($sAuthToken) |
224: | { |
225: | AuthToken::where('Token', $sAuthToken)->delete(); |
226: | } |
227: | |
228: | public function GetExpiredAuthTokens($iDays) |
229: | { |
230: | $iTime = $iDays * 86400; |
231: | return AuthToken::query()->whereRaw('(LastUsageDateTime + ' . $iTime . ') < UNIX_TIMESTAMP()')->get(); |
232: | } |
233: | |
234: | public function DeleteExpiredAuthTokens($iDays) |
235: | { |
236: | $iTime = $iDays * 86400; |
237: | return AuthToken::query()->whereRaw('(LastUsageDateTime + ' . $iTime . ') < UNIX_TIMESTAMP()')->delete(); |
238: | } |
239: | |
240: | public function GetUserSessionsFromDB($iUserId) |
241: | { |
242: | return AuthToken::where('UserId', $iUserId)->get(); |
243: | } |
244: | } |
245: | |