]> git.andy128k.dev Git - ipf.git/commitdiff
rewrite session app. no orm, two backends
authorAndrey Kutejko <andy128k@gmail.com>
Sat, 16 Aug 2014 08:08:09 +0000 (11:08 +0300)
committerAndrey Kutejko <andy128k@gmail.com>
Sat, 16 Aug 2014 08:08:09 +0000 (11:08 +0300)
12 files changed:
composer.json
composer.lock
ipf/auth/app.php
ipf/auth/middleware.php [new file with mode: 0644]
ipf/auth/models/User.php
ipf/crypto.php [new file with mode: 0644]
ipf/session/app.php
ipf/session/middleware.php
ipf/session/migrations/20140101000000_create_sessions.php [new file with mode: 0644]
ipf/session/models.yml [deleted file]
ipf/session/models/Session.php [deleted file]
ipf/session/models/_generated/BaseSession.php [deleted file]

index 21b91603ec956285335f7859013cab5e255b465d..3a7dd33fb122d9c44c834d53b2a129c055f22ad2 100644 (file)
@@ -18,6 +18,7 @@
   "require": {
     "pear/archive_tar": "1.3.*",
     "mustangostang/spyc": "0.5.*",
+    "lichtner/fluentpdo": "dev-master",
     "andy128k/missing-tools": "0.2.*@dev",
     "andy128k/migrations": "dev-master",
     "andy128k/pegp": "0.1.*@dev",
index 4bb3d9a4f01676135f846576a37094e91f93d4ea..be8ca0d08b2bb83d3989f9c1b457f125183579d1 100644 (file)
@@ -4,7 +4,7 @@
         "Read more about it at http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
         "This file is @generated automatically"
     ],
-    "hash": "85f0406cc02d8f1f4650eb652d1cc65b",
+    "hash": "7132f66df1bb9071ac21329f579f6132",
     "packages": [
         {
             "name": "andy128k/ipf-template",
             "description": "Route expression",
             "time": "2013-08-02 19:17:54"
         },
+        {
+            "name": "lichtner/fluentpdo",
+            "version": "dev-master",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/lichtner/fluentpdo.git",
+                "reference": "26d6a5b9dda8a94d14b2ac037caf10362f92b487"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/lichtner/fluentpdo/zipball/26d6a5b9dda8a94d14b2ac037caf10362f92b487",
+                "reference": "26d6a5b9dda8a94d14b2ac037caf10362f92b487",
+                "shasum": ""
+            },
+            "type": "library",
+            "autoload": {
+                "files": [
+                    "FluentPDO/FluentPDO.php"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "Apache-2.0",
+                "GPL-2.0+"
+            ],
+            "authors": [
+                {
+                    "name": "Marek Lichtner",
+                    "homepage": "http://licht.sk/"
+                }
+            ],
+            "description": "FluentPDO is small PHP library for rapid query building. Killer feature is smart join builder which generates joins automatically.",
+            "homepage": "http://fluentpdo.com/",
+            "keywords": [
+                "database",
+                "dbal",
+                "pdo"
+            ],
+            "time": "2014-01-09 20:25:56"
+        },
         {
             "name": "mustangostang/spyc",
             "version": "0.5.1",
     "aliases": [],
     "minimum-stability": "stable",
     "stability-flags": {
+        "lichtner/fluentpdo": 20,
         "andy128k/missing-tools": 20,
         "andy128k/migrations": 20,
         "andy128k/pegp": 20,
index a727b07cb9429d8a3a459386a132ce87bc71c9f7..e0f5034e7e8567073bcddf375402e24b522dd45c 100644 (file)
@@ -23,8 +23,9 @@ class IPF_Auth_App extends IPF_Application
     static function login($request, $user)
     {
         $request->user = $user;
-        $request->session->clear();
-        $request->session->setData('login_time', gmdate('Y-m-d H:i:s'));
+        $request->session->data = array(
+            'login_time' => gmdate('Y-m-d H:i:s')
+        );
         $user->save();
     }
 
@@ -35,9 +36,10 @@ class IPF_Auth_App extends IPF_Application
 
     static function logout($request)
     {
-        $request->user = new User();
-        $request->session->clear();
-        $request->session->setData('logout_time', gmdate('Y-m-d H:i:s'));
+        $request->user = new User;
+        $request->session->data = array(
+            'login_time' => gmdate('Y-m-d H:i:s')
+        );
     }
 
     static function createPermissionsFromModels()
diff --git a/ipf/auth/middleware.php b/ipf/auth/middleware.php
new file mode 100644 (file)
index 0000000..6f6f676
--- /dev/null
@@ -0,0 +1,32 @@
+<?php
+
+class IPF_Auth_Middleware
+{
+    const SessionKey = 'IPF_User_auth';
+
+    function processRequest($request)
+    {
+        $request->user = null;
+    
+        $user_id = \PFF\Arr::get($request->session->data, self::SessionKey, 0);
+        if ($user_id > 0) {
+            $request->user = User::table()->find($user_id);
+            if ($request->user && 43200 < IPF_Utils::dateCompare($request->user->last_login)) {
+                $request->user->last_login = gmdate('Y-m-d H:i:s');
+                $request->user->save();
+            }
+        }
+
+        if (!$request->user)
+            $request->user = new User;
+
+        return false;
+    }
+
+    function processResponse($request, $response)
+    {
+        $request->session->data[self::SessionKey] = $request->user->id;
+        return $response;
+    }
+}
+
index 461ba318d342234e6611d6bde1504585b8aea52f..e8151e30f99332155ccc699d6b3968049eb73b69 100644 (file)
@@ -206,7 +206,6 @@ class AdminUser extends IPF_Admin_Model
 class User extends BaseUser
 {
     const UNUSABLE_PASSWORD = '!';
-    public $session_key = 'IPF_User_auth';
     private $profile = null;
 
     public function __toString()
diff --git a/ipf/crypto.php b/ipf/crypto.php
new file mode 100644 (file)
index 0000000..6b150a9
--- /dev/null
@@ -0,0 +1,46 @@
+<?php
+
+class IPF_Crypto
+{
+    public static function encrypt($string)
+    {
+        $string = mcrypt_encrypt(MCRYPT_RIJNDAEL_256, self::get_key(), $string, MCRYPT_MODE_CBC, self::get_iv());
+        $string = base64_encode($string);
+        return $string;
+    }
+
+    public static function decrypt($string)
+    {
+        $string = base64_decode($string);
+        $string = mcrypt_decrypt(MCRYPT_RIJNDAEL_256, self::get_key(), $string, MCRYPT_MODE_CBC, self::get_iv());
+        $string = rtrim($string, "\0");
+        return $string;
+    }
+
+    public static function sign($string)
+    {
+        return hash_hmac('sha1', $string, self::get_key());
+    }
+
+    private static function get_key()
+    {
+        $secret = self::secretKey();
+        return sha1($secret.$secret);
+    }
+
+    private static function get_iv()
+    {
+        $secret = self::secretKey();
+        return sha1(sha1($secret));
+    }
+
+    private static function secretKey()
+    {
+        $secret_key = IPF::get('secret_key');
+        if ($secret_key)
+            return $secret_key;
+        else
+            throw new Exception('Security error: "secret_key" is not set in the configuration file.');
+    }
+}
+
index 3a0db0513e5b014381631cab6642b28403350cb7..31e5d504a35089eb9a73943a72e877588f77a01a 100644 (file)
 
 class IPF_Session_App extends IPF_Application
 {
-    public function __construct()
+}
+
+
+abstract class Session
+{
+    public static $backends = array(
+        'CookieSession',
+        'DBSession',
+    );
+
+    public static function get($key)
+    {
+        if (!$key)
+            return null;
+
+        list($backend, $data) = self::detectBackend($key);
+        if (!$backend)
+            return null;
+        
+        $session = new $backend($key, $data);
+
+        if ($session->expired()) {
+            $session->delete();
+            return null;
+        }
+
+        return $session;
+    }
+
+    private static function detectBackend($key)
+    {
+        foreach (self::$backends as $backend) {
+            $data = $backend::getData($key);
+            if ($data)
+                return array($backend, $data);
+        }
+        return null;
+    }
+
+    public static function create()
+    {
+        $backend = self::$backends[0];
+        return new $backend;
+    }
+
+
+    protected $key = null;
+    public $data = array();
+
+    public function __construct($key, $data)
+    {
+        $this->key = $key;
+        $this->data = $data;
+    }
+
+    public function delete()
+    {
+    }
+
+    public function cookie()
+    {
+        $this->data['updated_at'] = time();
+        $this->save();
+        return $this->key;
+    }
+
+    protected abstract function save();
+
+    public function updatedAt()
+    {
+        return $this->data['updated_at'];
+    }
+
+    public function expired()
+    {
+        return time() - $this->updatedAt() > 60 * 60 * 24 * 7;
+    }
+}
+
+
+class CookieSession extends Session
+{
+    public static function getData($key)
+    {
+        $key = explode('|', $key, 2);
+        if (count($key) !== 2)
+            return null;
+        list($data, $sign) = $key;
+        if (IPF_Crypto::sign($data) !== $sign)
+            return null;
+
+        return unserialize(base64_decode($data));
+    }
+
+    protected function save()
+    {
+        $data = base64_encode(serialize($this->data));
+        $this->key = $data.'|'.IPF_Crypto::sign($data);
+    }
+}
+
+
+class DBSession extends Session
+{
+    private static function query()
+    {
+        $connection = \PFF\Container::databaseConnection();
+        return new FluentPDO($connection);
+    }
+
+    public static function getData($key)
+    {
+        $data = self::query()
+            ->from('session')
+            ->where('session_key', $key)
+            ->fetch('data');
+        if ($data)
+            return unserialize($data);
+        else
+            return null;
+    }
+
+    public function delete()
+    {
+        self::query()
+            ->deleteFrom('session')
+            ->where('session_key', $key)
+            ->execute();
+
+        $this->key = null;
+    }
+
+    protected function save()
+    {
+        $params = array(
+            'data' => serialize($this->data),
+            'updated_at' => gmdate('Y-m-d H:i:s', $this->updatedAt()),
+        );
+
+        if ($this->key) {
+            self::query()
+                ->update('session')
+                ->where('session_key', $this->key)
+                ->set($params)
+                ->execute();
+        } else {
+            $params['session_key'] = $this->key = self::getNewSessionKey();
+            self::query()
+                ->insertInto('session', $params)
+                ->execute();
+        }
+    }
+
+    private static function getNewSessionKey($secret_key=null)
     {
-        parent::__construct(array(
-            'models' => array('Session')
-        ));
+        if (!$secret_key)
+            $secret_key = IPF::get('secret_key');
+        return md5(microtime().rand(0, 123456789).rand(0, 123456789).$secret_key);
     }
 }
 
index 65840edfc0a72acaf1a8ea487a9483e4f0990a02..8c5497bc9315760bff87a1a380ebf0a84e94bf15 100644 (file)
@@ -4,93 +4,20 @@ class IPF_Session_Middleware
 {
     function processRequest(&$request)
     {
-        $session = new Session();
-        $user = new User();
-        if (!isset($request->COOKIE[IPF::get('session_cookie_id')])) {
-            $request->user = $user;
-            $request->session = $session;
-            return false;
-        }
-        try {
-            $data = $this->_decodeData($request->COOKIE[IPF::get('session_cookie_id')]);
-        } catch (Exception $e) {
-            $request->user = $user;
-            $request->session = $session;
-            return false;
-        }
-        if (isset($data[$user->session_key])) {
-            $found_user = $user->getTable()->find($data[$user->session_key]);
-            if ($found_user) {
-                $request->user = $found_user;
-                if (43200 < IPF_Utils::dateCompare($request->user->last_login)) {
-                    $request->user->last_login = gmdate('Y-m-d H:i:s');
-                    $request->user->save();
-                }
-            } else
-                $request->user = $user;
-        } else
-            $request->user = $user;
+        $session_cookie = \PFF\Arr::get($request->COOKIE, IPF::get('session_cookie_id'));
+
+        $request->session = Session::get($session_cookie);
+        if (!$request->session)
+            $request->session = Session::create();
 
-        if (isset($data['IPF_SESSION_KEY'])) {
-            $found_session = $session->getTable()->findOneBySession_key($data['IPF_SESSION_KEY']);
-            if ($found_session)
-                $request->session = $found_session;
-            else
-                $request->session = $session;
-        } else {
-            $request->session = $session;
-        }
         return false;
     }
 
     function processResponse($request, $response)
     {
-        if ($request->session->touched) {
-            $request->session->save();
-            $data = array();
-            if ($request->user->id > 0) {
-                $data[$request->user->session_key] = $request->user->id;
-            }
-            $data['IPF_SESSION_KEY'] = $request->session->session_key;
-            $response->cookies[IPF::get('session_cookie_id')] = $this->_encodeData($data);
-        }
+        $session_cookie = $request->session->cookie();
+        $response->cookies[IPF::get('session_cookie_id')] = $session_cookie;
         return $response;
     }
-
-    protected function _encodeData($data)
-    {
-        if ('' == ($key = IPF::get('secret_key'))) {
-            throw new IPF_Exception('Security error: "secret_key" is not set in the configuration file.');
-        }
-        $data = serialize($data);
-        return base64_encode($data).md5(base64_encode($data).$key);
-    }
-
-    protected function _decodeData($encoded_data)
-    {
-        $check = substr($encoded_data, -32);
-        $base64_data = substr($encoded_data, 0, strlen($encoded_data)-32);
-        if (md5($base64_data.IPF::get('secret_key')) != $check) {
-            throw new IPF_Exception('The session data may have been tampered.');
-        }
-        return unserialize(base64_decode($base64_data));
-    }
-
-    /*
-    public static function processContext($signal, &$params)
-    {
-        $params['context'] = array_merge($params['context'],
-            IPF_Session_Middleware_ContextPreProcessor($params['request']));
-    }
-    */
-}
-
-/*
-function IPF_Session_Middleware_ContextPreProcessor($request)
-{
-    return array('user' => $request->user);
 }
 
-Pluf_Signal::connect('Pluf_Template_Context_Request::construct',
-                     array('Pluf_Middleware_Session', 'processContext'));
-*/
diff --git a/ipf/session/migrations/20140101000000_create_sessions.php b/ipf/session/migrations/20140101000000_create_sessions.php
new file mode 100644 (file)
index 0000000..9d59e5c
--- /dev/null
@@ -0,0 +1,10 @@
+<?php
+
+class Migration_20140101000000 extends \PFF\Migrations\Migration
+{
+    function migrate()
+    {
+        $this->connection->exec('CREATE TABLE session (session_key VARCHAR(40), data TEXT, updated_at TIMESTAMP, PRIMARY KEY(session_key)) ENGINE = INNODB');
+    }
+}
+
diff --git a/ipf/session/models.yml b/ipf/session/models.yml
deleted file mode 100644 (file)
index 7574c05..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
----
-Session:
-  columns:
-    session_key:
-      primary: true
-      type: string(40)
-    session_data: string
-    expire_data: timestamp
-
diff --git a/ipf/session/models/Session.php b/ipf/session/models/Session.php
deleted file mode 100644 (file)
index 5054e42..0000000
+++ /dev/null
@@ -1,64 +0,0 @@
-<?php
-
-class Session extends BaseSession
-{
-    public $data = array();
-    public $touched = false;
-
-    function clear()
-    {
-        $this->data = array();
-        $this->touched = true;
-    }
-
-    function getSessionData()
-    {
-        return unserialize($this->session_data);
-    }
-
-    private function unserializeData()
-    {
-        if (!$this->data)
-            $this->data = $this->getSessionData();
-    }
-
-    function setData($key, $value=null)
-    {
-        $this->unserializeData();
-        if (is_null($value)) {
-            unset($this->data[$key]);
-        } else {
-            $this->data[$key] = $value;
-        }
-        $this->touched = true;
-    }
-
-    function getData($key=null, $default='')
-    {
-        if (is_null($key))
-            return parent::getData();
-
-        $this->unserializeData();
-        if (isset($this->data[$key])) {
-            return $this->data[$key];
-        } else {
-            return $default;
-        }
-    }
-
-    function getNewSessionKey()
-    {
-        $key = md5(microtime().rand(0, 123456789).rand(0, 123456789).IPF::get('secret_key'));
-        return $key;
-    }
-
-    function preSave($event)
-    {
-        $this->session_data = serialize($this->data);
-        if ($this->session_key == '') {
-            $this->session_key = $this->getNewSessionKey();
-        }
-        $this->expire_data = gmdate('Y-m-d H:i:s', time()+31536000);
-    }
-}
-
diff --git a/ipf/session/models/_generated/BaseSession.php b/ipf/session/models/_generated/BaseSession.php
deleted file mode 100644 (file)
index 98eb6e4..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-<?php
-
-/**
- * This class has been auto-generated by the IPF_ORM Framework.
- * Changes to this file may cause incorrect behavior
- * and will be lost if the code is regenerated.
- */
-
-abstract class BaseSession extends IPF_ORM_Record
-{
-  public static function setTableDefinition(IPF_ORM_Table $table)
-  {
-    $table->setTableName('session');
-    $table->setColumn('session_key', 'string', 40, array('primary' => true, 'type' => 'string', 'length' => '40'));
-    $table->setColumn('session_data', 'string', null, array('type' => 'string'));
-    $table->setColumn('expire_data', 'timestamp', null, array('type' => 'timestamp'));
-  }
-
-
-  public static function table()
-  {
-    return IPF_ORM::getTable('Session');
-  }
-
-  public static function query($alias='')
-  {
-    return IPF_ORM::getTable('Session')->createQuery($alias);
-  }
-}
\ No newline at end of file