store client name and last use time for tokens. show them in token management
authorChristian Weiske <cweiske@cweiske.de>
Tue, 30 Sep 2014 21:13:49 +0000 (23:13 +0200)
committerChristian Weiske <cweiske@cweiske.de>
Tue, 30 Sep 2014 21:13:49 +0000 (23:13 +0200)
appinfo/database.xml
appinfo/info.xml
appinfo/version
controller/apicontroller.php
controller/guicontroller.php
controller/oauthcontroller.php
lib/client.php [new file with mode: 0644]
lib/oauth.php
lib/token.php
lib/tokenstorage.php
templates/tokens.php

index 176f89f..7419ee7 100755 (executable)
                                <notnull>true</notnull>
                                <length>2048</length>
                        </field>
+                       <field>
+                               <name>token_client</name>
+                               <type>text</type>
+                               <notnull>true</notnull>
+                               <length>256</length>
+                       </field>
+                       <field>
+                               <name>token_lastuse</name>
+                               <type>timestamp</type>
+                               <notnull>true</notnull>
+                       </field>
                </declaration>
        </table>
 
index 2074d61..bff1ebd 100755 (executable)
@@ -3,7 +3,7 @@
        <id>grauphel</id>
        <name>Grauphel: Tomboy note server</name>
        <description>Tomboy REST API server to sync notes between devices</description>
-       <version>0.2.0</version>
+       <version>0.3.0</version>
        <licence>AGPL3 or later</licence>
        <author>Christian Weiske</author>
        <requiremin>7</requiremin>
index 0ea3a94..0d91a54 100755 (executable)
@@ -1 +1 @@
-0.2.0
+0.3.0
index ee16f80..688d0b0 100644 (file)
@@ -16,6 +16,7 @@ namespace OCA\Grauphel\Controller;
 use \OCP\AppFramework\Controller;
 use \OCP\AppFramework\Http\JSONResponse;
 
+use \OCA\Grauphel\Lib\Client;
 use \OCA\Grauphel\Lib\NoteStorage;
 use \OCA\Grauphel\Lib\OAuth;
 use \OCA\Grauphel\Lib\OAuthException;
@@ -105,10 +106,10 @@ class ApiController extends Controller
             'api-version' => '1.0',
         );
 
-        $client = $this->getClient();
+        $cl = new Client();
+        $client = $cl->getClient();
         if ($client !== false) {
-            $data['oauth_authorize_url'] .= '?client='
-                . urlencode($this->getNiceClientName($client));
+            $data['oauth_authorize_url'] .= '?client=' . urlencode($client);
         }
 
         if ($authenticated) {
@@ -333,31 +334,6 @@ class ApiController extends Controller
         return new JSONResponse($note);
     }
 
-    protected function getClient()
-    {
-        if (isset($_SERVER['HTTP_X_TOMBOY_CLIENT'])) {
-            $client = $_SERVER['HTTP_X_TOMBOY_CLIENT'];
-            $doublepos = strpos($client, ', org.tomdroid');
-            if ($doublepos !== false) {
-                //https://bugs.launchpad.net/tomdroid/+bug/1375436
-                //X-Tomboy-Client header is sent twice
-                $client = substr($client, 0, $doublepos);
-            }
-            return $client;
-        }
-
-        return false;
-    }
-
-    protected function getNiceClientName($client)
-    {
-        if (substr($client, 0, 12) == 'org.tomdroid') {
-            //org.tomdroid v0.7.5, build 14, Android v4.4.2, innotek GmbH/VirtualBox
-            return 'Tomdroid';
-        }
-        return $client;
-    }
-
     /**
      * Checks if the given user is authorized (by oauth token or normal login)
      *
index 947e23e..6d59fd5 100644 (file)
@@ -15,6 +15,7 @@ namespace OCA\Grauphel\Controller;
 
 use \OCP\AppFramework\Controller;
 use \OCP\AppFramework\Http\TemplateResponse;
+use \OCA\Grauphel\Lib\Client;
 use \OCA\Grauphel\Lib\TokenStorage;
 
 /**
@@ -108,7 +109,8 @@ class GuiController extends Controller
             array(
                 'tokens' => $tokens->loadForUser(
                     $this->user->getUid(), 'access'
-                )
+                ),
+                'client' => new Client(),
             )
         );
         $this->addNavigation($res, null);
index 6ab17d2..bc66de4 100644 (file)
@@ -18,6 +18,7 @@ use \OCP\AppFramework\Http;
 use \OCP\AppFramework\Http\RedirectResponse;
 use \OCP\AppFramework\Http\TemplateResponse;
 
+use \OCA\Grauphel\Lib\Client;
 use \OCA\Grauphel\Lib\Token;
 use \OCA\Grauphel\Lib\OAuth;
 use \OCA\Grauphel\Lib\Dependencies;
@@ -87,6 +88,7 @@ class OauthController extends Controller
             $newToken->tokenKey = 'a' . bin2hex($provider->generateToken(8));
             $newToken->secret   = 's' . bin2hex($provider->generateToken(8));
             $newToken->user     = $token->user;
+            $newToken->client   = $token->client;
             $this->deps->tokens->store($newToken);
 
             return new FormResponse(
@@ -118,19 +120,22 @@ class OauthController extends Controller
             return $token;
         }
 
-        $client = 'unknown';
+        $clientTitle = 'unknown';
+        $clientAgent = '';
         if (isset($_GET['client'])) {
-            $client = $_GET['client'];
+            $clientAgent = $_GET['client'];
+            $cl = new Client();
+            $clientTitle = $cl->getNiceName($clientAgent);
         }
 
         $res = new TemplateResponse('grauphel', 'oauthAuthorize');
         $res->setParams(
             array(
                 'oauth_token' => $token->tokenKey,
-                'client'      => $client,
+                'client'      => $clientTitle,
                 'formaction'  => $this->deps->urlGen->linkToRoute(
                     'grauphel.oauth.confirm'
-                ),
+                ) . '?client=' . urlencode($clientAgent),
             )
         );
         return $res;
@@ -172,6 +177,11 @@ class OauthController extends Controller
             return $res;
         }
 
+        $clientAgent = '';
+        if (isset($_GET['client'])) {
+            $clientAgent = $_GET['client'];
+        }
+
         //the user is logged in and authorized
         $provider = OAuth::getProvider();
 
@@ -180,6 +190,7 @@ class OauthController extends Controller
         $newToken->secret   = $token->secret;
         $newToken->verifier = 'v' . bin2hex($provider->generateToken(8));
         $newToken->user     = $this->user->getUID();
+        $newToken->client   = $clientAgent;
 
         $this->deps->tokens->store($newToken);
 
diff --git a/lib/client.php b/lib/client.php
new file mode 100644 (file)
index 0000000..358e60b
--- /dev/null
@@ -0,0 +1,55 @@
+<?php
+/**
+ * Part of grauphel
+ *
+ * PHP version 5
+ *
+ * @category  Tools
+ * @package   Grauphel
+ * @author    Christian Weiske <cweiske@cweiske.de>
+ * @copyright 2014 Christian Weiske
+ * @license   http://www.gnu.org/licenses/agpl.html GNU AGPL v3
+ * @link      http://cweiske.de/grauphel.htm
+ */
+namespace OCA\Grauphel\Lib;
+
+/**
+ * Client identification helper
+ *
+ * @category  Tools
+ * @package   Grauphel
+ * @author    Christian Weiske <cweiske@cweiske.de>
+ * @copyright 2014 Christian Weiske
+ * @license   http://www.gnu.org/licenses/agpl.html GNU AGPL v3
+ * @version   Release: @package_version@
+ * @link      http://cweiske.de/grauphel.htm
+ */
+class Client
+{
+    public function getClient()
+    {
+        if (isset($_SERVER['HTTP_X_TOMBOY_CLIENT'])) {
+            $client = $_SERVER['HTTP_X_TOMBOY_CLIENT'];
+            $doublepos = strpos($client, ', org.tomdroid');
+            if ($doublepos !== false) {
+                //https://bugs.launchpad.net/tomdroid/+bug/1375436
+                //X-Tomboy-Client header is sent twice
+                $client = substr($client, 0, $doublepos);
+            }
+            return $client;
+        }
+
+        return false;
+    }
+
+    public function getNiceName($client)
+    {
+        if (substr($client, 0, 12) == 'org.tomdroid') {
+            //org.tomdroid v0.7.5, build 14, Android v4.4.2, innotek GmbH/VirtualBox
+            return 'Tomdroid';
+        }
+        return $client;
+    }
+
+}
+?>
\ No newline at end of file
index 5f84e7e..231a177 100644 (file)
@@ -111,6 +111,12 @@ class OAuth
             }
             throw $e;
         }
+
+        if (time() - $token->lastuse > 60) {
+            //time to update lastuse after at least a minute
+            $this->tokens->updateLastUse($token->tokenKey);
+        }
+
         $provider->token_secret = $token->secret;
         return OAUTH_OK;
     }
@@ -147,7 +153,7 @@ class OAuth
     /**
      * Get a new oauth provider instance.
      * Used to work around the fastcgi bug in oauthprovider.
-     * 
+     *
      * @return \OAuthProvider
      */
     public static function getProvider()
index ebb0783..2cf6580 100644 (file)
@@ -69,6 +69,20 @@ class Token
      */
     public $callback;
 
+    /**
+     * Client name/identifier (user agent)
+     *
+     * @var string
+     */
+    public $client;
+
+    /**
+     * Unix timestamp when the token was used last
+     *
+     * @var integer
+     */
+    public $lastuse;
+
     public function __construct($type = null)
     {
         $this->type = $type;
index b9689ab..cdbce11 100644 (file)
@@ -37,15 +37,17 @@ class TokenStorage
     {
         \OC_DB::executeAudited(
             'INSERT INTO `*PREFIX*grauphel_oauth_tokens`'
-            . '(`token_user`, `token_type`, `token_key`, `token_secret`, `token_verifier`, `token_callback`)'
-            . ' VALUES(?, ?, ?, ?, ?, ?)',
+            . '(`token_user`, `token_type`, `token_key`, `token_secret`, `token_verifier`, `token_callback`, `token_client`, `token_lastuse`)'
+            . ' VALUES(?, ?, ?, ?, ?, ?, ?, ?)',
             array(
                 $token->user,
                 $token->type,
                 $token->tokenKey,
                 (string) $token->secret,
                 (string) $token->verifier,
-                (string) $token->callback
+                (string) $token->callback,
+                (string) $token->client,
+                (string) date('c'),
             )
         );
     }
@@ -133,6 +135,25 @@ class TokenStorage
         return $tokens;
     }
 
+    /**
+     * Update the "last use" field of a token
+     *
+     * @param string $tokenKey Random token string to load
+     *
+     * @return void
+     */
+    public function updateLastUse($tokenKey)
+    {
+        \OC_DB::executeAudited(
+            'UPDATE `*PREFIX*grauphel_oauth_tokens`'
+            . ' SET `token_lastuse` = ? WHERE `token_key` = ?',
+            array(
+                (string) date('c'),
+                $tokenKey,
+            )
+        );
+    }
+
     protected function fromDb($tokenRow)
     {
         $token = new Token();
@@ -142,6 +163,8 @@ class TokenStorage
         $token->user     = $tokenRow['token_user'];
         $token->verifier = $tokenRow['token_verifier'];
         $token->callback = $tokenRow['token_callback'];
+        $token->client   = $tokenRow['token_client'];
+        $token->lastuse  = \strtotime($tokenRow['token_lastuse']);
         return $token;
     }
 }
index 4a578f5..7707516 100644 (file)
@@ -18,8 +18,8 @@
     <?php foreach ($_['tokens'] as $token) { ?>
       <tr>
        <td><?php p($token->tokenKey); ?></td>
-       <td></td>
-       <td></td>
+       <td title="<?php p($token->client); ?>"><?php p($_['client']->getNiceName($token->client)); ?></td>
+       <td><?php p(\OCP\Util::formatDate($token->lastuse)); ?></td>
        <td>Disable Delete</td>
       </tr>
     <?php } ?>