Procházet zdrojové kódy

Added active tokens to Account Area
Added search array function
Added SSL option to chat
Added /token/revoke to api

causefx před 7 roky
rodič
revize
8b6cb2856d

+ 30 - 0
api/functions/api-functions.php

@@ -1035,3 +1035,33 @@ function loadTabs()
 	}
 	return false;
 }
+
+function getActiveTokens()
+{
+	try {
+		$connect = new Dibi\Connection([
+			'driver' => 'sqlite3',
+			'database' => $GLOBALS['dbLocation'] . $GLOBALS['dbName'],
+		]);
+		$all = $connect->fetchAll('SELECT * FROM `tokens` WHERE `user_id` = ? AND `expires` > ?', $GLOBALS['organizrUser']['userID'], $GLOBALS['currentTime']);
+		return $all;
+	} catch (Dibi\Exception $e) {
+		return false;
+	}
+}
+
+function revokeToken($array)
+{
+	if ($array['data']['token']) {
+		try {
+			$connect = new Dibi\Connection([
+				'driver' => 'sqlite3',
+				'database' => $GLOBALS['dbLocation'] . $GLOBALS['dbName'],
+			]);
+			$connect->query('DELETE FROM tokens WHERE user_id = ? AND token = ?', $GLOBALS['organizrUser']['userID'], $array['data']['token']);
+			return true;
+		} catch (Dibi\Exception $e) {
+			return false;
+		}
+	}
+}

+ 9 - 0
api/functions/normal-functions.php

@@ -348,6 +348,15 @@ function array_filter_key(array $array, $callback)
 	return array_intersect_key($array, array_flip($matchedKeys));
 }
 
+function searchArray($array, $field, $value)
+{
+	foreach ($array as $key => $item) {
+		if ($item[$field] === $value)
+			return $key;
+	}
+	return false;
+}
+
 // Qualify URL
 function qualifyURL($url, $return = false)
 {

+ 1 - 1
api/functions/organizr-functions.php

@@ -62,7 +62,7 @@ function organizrSpecialSettings()
 			'maxGroup' => $GLOBALS['lockoutMaxAuth']
 		),
 		'user' => array(
-			'agent' => isset($_SERVER ['HTTP_USER_AGENT']) ? $_SERVER ['HTTP_USER_AGENT'] : null
+			'agent' => isset($_SERVER ['HTTP_USER_AGENT']) ? $_SERVER ['HTTP_USER_AGENT'] : null,
 		),
 		'misc' => array(
 			'installedPlugins' => $GLOBALS['installedPlugins'],

+ 4 - 1
api/functions/token-functions.php

@@ -109,7 +109,8 @@ function validateToken($token, $global = false)
 					'driver' => 'sqlite3',
 					'database' => $GLOBALS['dbLocation'] . $GLOBALS['dbName'],
 				]);
-				$tokenCheck = $database->fetch('SELECT * FROM tokens WHERE user_id = ? AND token = ?', $userInfo['userID'], $token);
+				$all = $database->fetchAll('SELECT * FROM `tokens` WHERE `user_id` = ? AND `expires` > ?', $userInfo['userID'], $GLOBALS['currentTime']);
+				$tokenCheck = (searchArray($all, 'token', $token) !== false);
 				if (!$tokenCheck) {
 					// Delete cookie & reload page
 					coookie('delete', $GLOBALS['cookieName']);
@@ -129,6 +130,7 @@ function validateToken($token, $global = false)
 					"userID" => $result['id'],
 					"loggedin" => true,
 					"locked" => $result['locked'],
+					"tokenList" => $all,
 					"authService" => explode('::', $result['auth_service'])[0]
 				);
 			} catch (Dibi\Exception $e) {
@@ -162,6 +164,7 @@ function getOrganizrUserToken()
 			"userID" => null,
 			"loggedin" => false,
 			"locked" => false,
+			"tokenList" => null,
 			"authService" => null
 		);
 	}

+ 13 - 0
api/index.php

@@ -1197,6 +1197,19 @@ switch ($function) {
 				break;
 		}
 		break;
+	case 'v1_token_revoke':
+		switch ($method) {
+			case 'POST':
+				$result['status'] = 'success';
+				$result['statusText'] = 'success';
+				$result['data'] = revokeToken($_POST);
+				break;
+			default:
+				$result['status'] = 'error';
+				$result['statusText'] = 'The function requested is not defined for method: ' . $method;
+				break;
+		}
+		break;
 	case 'v1_update_db_manual':
 		switch ($method) {
 			case 'GET':

+ 8 - 1
api/plugins/chat.php

@@ -74,6 +74,13 @@ function chatGetSettings()
 				'value' => $GLOBALS['CHAT-newMessageSound-include'],
 				'options' => getSounds()
 			),
+			array(
+				'type' => 'switch',
+				'name' => 'CHAT-useSSL',
+				'label' => 'Use Pusher SSL',
+				'help' => 'If messages get stuck sending, please turn this option off.',
+				'value' => $GLOBALS['CHAT-useSSL']
+			)
 		),
 		'Connection' => array(
 			array(
@@ -126,7 +133,7 @@ function sendChatMessage($array)
 		$connect->query('INSERT INTO [chatroom]', $newMessage);
 		$options = array(
 			'cluster' => $GLOBALS['CHAT-cluster-include'],
-			'useTLS' => true
+			'useTLS' => $GLOBALS['CHAT-useSSL']
 		);
 		$pusher = new Pusher\Pusher(
 			$GLOBALS['CHAT-authKey-include'],

+ 1 - 0
api/plugins/config/chat.php

@@ -9,4 +9,5 @@ return array(
 	'CHAT-messageLoadLimit' => '200',
 	'CHAT-userRefreshTimeout' => '60000',
 	'CHAT-newMessageSound-include' => 'plugins/sounds/default/newmessage.mp3',
+	'CHAT-useSSL' => false
 );

+ 66 - 3
js/functions.js

@@ -1687,6 +1687,68 @@ function buildTwoFA(current){
 
     return element;
 }
+function revokeToken(token,id){
+    organizrAPI('POST','api/?v1/token/revoke',{token:token}).success(function(data) {
+        var response = JSON.parse(data);
+        if(response.data == true){
+            $('#token-'+id).fadeOut();
+            message(window.lang.translate('Removed Token'),"",activeInfo.settings.notifications.position,"#FFF","success","3500");
+        }else{
+            message(window.lang.translate('Error: Removing Token'),"",activeInfo.settings.notifications.position,"#FFF","error","3500");
+        }
+    }).fail(function(xhr) {
+        ajaxloader();
+        console.error("Organizr Function: API Connection Failed");
+    });
+}
+function buildActiveTokens(array) {
+    console.log(array);
+    var tokens = '';
+    $.each(array, function(i,v) {
+        var className = (activeInfo.user.token == v.token) ? 'bg-success text-inverse' : '';
+        var extraText = (activeInfo.user.token == v.token) ? '<span class="tooltip-info" data-toggle="tooltip" data-placement="right" title="" data-original-title="Current Token">...'+v.token.substr(-10, 10)+'</span>' : v.token.substr(-10, 10);
+        tokens += `
+            <tr id="token-`+v.id+`" class="`+className+`">
+                <td>`+v.id+`</td>
+                <td>`+extraText+`</td>
+                <td>`+moment(v.created).format('LLL')+`</td>
+                <td>`+moment(v.expires).format('LLL')+`</td>
+                <td>
+                    <button class="btn btn-danger waves-effect waves-light" type="button" onclick="revokeToken('`+v.token+`', '`+v.id+`');"><i class="fa fa-ban"></i></button>
+                </td>
+            </tr>
+        `;
+    });
+    return `
+        <div class="col-lg-12">
+            <div class="panel panel-info">
+                <div class="panel-heading"> <span lang="en">Active Tokens</span>
+                    <div class="pull-right"><a href="#" data-perform="panel-collapse"><i class="ti-plus"></i></a> </div>
+                </div>
+                <div class="panel-wrapper collapse" aria-expanded="true">
+                    <div class="panel-body bg-org p-0">
+                        <div class="table-responsive">
+                            <table class="table color-table info-table">
+                                <thead>
+                                    <tr>
+                                        <th>#</th>
+                                        <th>Token</th>
+                                        <th>Created</th>
+                                        <th>Expires</th>
+                                        <th>Action</th>
+                                    </tr>
+                                </thead>
+                                <tbody>
+                                    `+tokens+`
+                                </tbody>
+                            </table>
+                        </div>
+                    </div>
+                </div>
+            </div>
+        </div>
+    `;
+}
 function accountManager(user){
     var passwordMessage = '';
     switch(activeInfo.settings.misc.authBackend){
@@ -1695,9 +1757,9 @@ function accountManager(user){
                 <div class="col-lg-12">
                     <div class="panel panel-info">
                         <div class="panel-heading"> <span lang="en">Password Notice</span>
-                            <div class="pull-right"><a href="#" data-perform="panel-collapse"><i class="ti-minus"></i></a> <a href="#" data-perform="panel-dismiss"><i class="ti-close"></i></a> </div>
+                            <div class="pull-right"><a href="#" data-perform="panel-collapse"><i class="ti-plus"></i></a> </div>
                         </div>
-                        <div class="panel-wrapper collapse in" aria-expanded="true">
+                        <div class="panel-wrapper collapse" aria-expanded="true">
                             <div class="panel-body bg-org">
                                 <p lang="en">If you signed in with a Plex Acct... Please use the following link to change your password there:</p><br>
                                 <p><a href="https://app.plex.tv/auth#?resetPassword" target="_blank">Change Password on Plex Website</a></p>
@@ -1729,6 +1791,7 @@ function accountManager(user){
             break;
     }
 	if (user.data.user.loggedin === true) {
+	    var activeTokens = buildActiveTokens(user.data.user.tokenList);
 		var accountDiv = `
         <!-- 2fa modal content -->
         <div id="twofa-modal" class="modal fade" tabindex="-1" role="dialog" aria-labelledby="twofa-modal-label" aria-hidden="true">
@@ -1801,7 +1864,7 @@ function accountManager(user){
 													<label class="control-label" lang="en">Verify Password</label>
 													<input type="password" id="accountPassword2" class="form-control"></div>
 											</div>
-											`+passwordMessage+`
+											`+activeTokens+passwordMessage+`
 										</div>
 										<!--/row-->
 									</div>