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\System;
9:
10: use Aurora\System\Models\AuthToken;
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) 2019, Afterlogic Corp.
16: *
17: * @package Api
18: */
19: class UserSession
20: {
21: public const TOKEN_VERSION = '2.4';
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: $this->SetToDB($aData['id'], $sAuthToken);
51: }
52:
53: return $sAuthToken;
54: }
55:
56: public function UpdateTimestamp($sAuthToken, $iTime = 0)
57: {
58: $aData = $this->Get($sAuthToken);
59: return $this->Set($aData, $iTime);
60: }
61:
62: public function Get($sAuthToken)
63: {
64: $mResult = false;
65:
66: if (strlen($sAuthToken) !== 0) {
67: $bStoreAuthTokenInDB = \Aurora\Api::GetSettings()->GetValue('StoreAuthTokenInDB', false);
68: if ($bStoreAuthTokenInDB && !$this->GetFromDB($sAuthToken)) {
69: return false;
70: }
71:
72: $mResult = Api::DecodeKeyValues($sAuthToken);
73:
74: if ($mResult !== false && isset($mResult['id'])) {
75: if ((isset($mResult['@ver']) && $mResult['@ver'] !== self::TOKEN_VERSION) || !isset($mResult['@ver'])) {
76: $mResult = false;
77: } else {
78: $iExpireTime = (int) isset($mResult['@expire']) ? $mResult['@expire'] : 0;
79: if ($iExpireTime > 0 && $iExpireTime < time()) {
80: $mResult = false;
81: } else {
82: $oUser = \Aurora\System\Managers\Integrator::getInstance()->getAuthenticatedUserByIdHelper($mResult['id']);
83: $iTime = (int) $mResult['@time']; // 0 means that signMe was true when user logged in, so there is no need to check it in that case
84: if ($oUser && $iTime !== 0 && (int) $oUser->TokensValidFromTimestamp > $iTime) {
85: $mResult = false;
86: } elseif ((isset($mResult['sign-me']) && !((bool) $mResult['sign-me'])) || (!isset($mResult['sign-me']))) {
87: $iTime = 0;
88: if (isset($mResult['@time'])) {
89: $iTime = (int) $mResult['@time'];
90: }
91: $iExpireUserSessionsBeforeTimestamp = \Aurora\System\Api::GetSettings()->GetValue("ExpireUserSessionsBeforeTimestamp", 0);
92: if ($iExpireUserSessionsBeforeTimestamp > $iTime && $iTime > 0) {
93: \Aurora\System\Api::Log('User session expired: ');
94: \Aurora\System\Api::LogObject($mResult);
95: $mResult = false;
96: }
97: }
98: }
99: }
100: }
101: if ($mResult === false) {
102: $this->Delete($sAuthToken);
103: }
104: }
105:
106: return $mResult;
107: }
108:
109: public function Delete($sAuthToken)
110: {
111: if (\Aurora\Api::GetSettings()->GetValue('StoreAuthTokenInDB', false)) {
112: try {
113: $this->DeleteFromDB($sAuthToken);
114: } catch (\Aurora\System\Exceptions\DbException $oEx) {
115: // DB is not configured
116: }
117: }
118: }
119:
120: public function DeleteAllUserSessions($iUserId)
121: {
122: return AuthToken::where('UserId', $iUserId)->delete();
123: }
124:
125: public function SetToDB($iUserId, $sAuthToken)
126: {
127: $oAuthToken = AuthToken::where('UserId', $iUserId)->where('Token', $sAuthToken)->first();
128:
129: if (!$oAuthToken) {
130: $oAuthToken = new AuthToken();
131: }
132: $oAuthToken->UserId = $iUserId;
133: $oAuthToken->Token = $sAuthToken;
134: $oAuthToken->LastUsageDateTime = time();
135:
136: try {
137: $oAuthToken->save();
138: } catch (\Aurora\System\Exceptions\DbException $oEx) {
139: // DB is not configured
140: }
141: }
142:
143: public function GetFromDB($sAuthToken)
144: {
145: if (!isset(self::$aTokensCache[$sAuthToken])) {
146: try {
147: $oAuthToken = AuthToken::firstWhere('Token', $sAuthToken);
148: if ($oAuthToken) {
149: $oAuthToken->LastUsageDateTime = time();
150: $oAuthToken->save();
151: self::$aTokensCache[$sAuthToken] = $oAuthToken;
152: }
153: } catch (\Aurora\System\Exceptions\DbException $oEx) {
154: \Aurora\Api::LogException($oEx);
155: }
156: }
157: return isset(self::$aTokensCache[$sAuthToken]) ? self::$aTokensCache[$sAuthToken] : false;
158: }
159:
160: public function DeleteFromDB($sAuthToken)
161: {
162: AuthToken::where('Token', $sAuthToken)->delete();
163: }
164:
165: public function GetExpiredAuthTokens($iDays)
166: {
167: $iTime = $iDays * 86400;
168: return AuthToken::whereRaw('(LastUsageDateTime + ' . $iTime . ') < UNIX_TIMESTAMP()')->get();
169: }
170:
171: public function DeleteExpiredAuthTokens($iDays)
172: {
173: $iTime = $iDays * 86400;
174: return AuthToken::whereRaw('(LastUsageDateTime + ' . $iTime . ') < UNIX_TIMESTAMP()')->delete();
175: }
176:
177: public function GetUserSessionsFromDB($iUserId)
178: {
179: return AuthToken::where('UserId', $iUserId)->get();
180: }
181: }
182: