diff --git a/database/2018_02_10_222914_create_sessions_table.php b/database/2018_02_10_222914_create_sessions_table.php new file mode 100644 index 00000000..8572f73c --- /dev/null +++ b/database/2018_02_10_222914_create_sessions_table.php @@ -0,0 +1,65 @@ +getSchemaBuilder(); + $schema->create('sessions', function (Blueprint $table) { + $table->increments('session_id'); + + $table->integer('user_id') + ->unsigned(); + + $table->string('session_key', 255); + + $table->binary('session_ip'); + + $table->string('user_agent', 255) + ->nullable() + ->default(null); + + $table->timestamp('expires_on') + ->nullable(); + + $table->timestamps(); + + $table->foreign('user_id') + ->references('user_id') + ->on('users') + ->onUpdate('cascade') + ->onDelete('cascade'); + }); + + $schema->table('users', function (Blueprint $table) { + $table->dropColumn('user_registered'); + $table->timestamps(); + $table->softDeletes(); + }); + } + + /** + * @SuppressWarnings(PHPMD) + */ + public function down() + { + $schema = Database::connection()->getSchemaBuilder(); + $schema->drop('sessions'); + + $schema->table('users', function (Blueprint $table) { + $table->integer('user_registered') + ->unsigned() + ->default(0); + + $table->dropSoftDeletes(); + $table->dropTimestamps(); + }); + } +} diff --git a/misuzu_migrate.php b/misuzu_migrate.php index 49efbf8d..7f6df615 100644 --- a/misuzu_migrate.php +++ b/misuzu_migrate.php @@ -23,6 +23,7 @@ if (!$migrator->repositoryExists()) { } $migrator->run(__DIR__ . '/database'); +//$migrator->rollback(__DIR__ . '/database'); foreach ($migrator->getNotes() as $note) { echo strip_tags($note) . PHP_EOL; diff --git a/public/index.php b/public/index.php index 3376ef1c..81d346b8 100644 --- a/public/index.php +++ b/public/index.php @@ -5,11 +5,15 @@ use Aitemu\RouterRequest; require_once __DIR__ . '/../misuzu.php'; -ob_start('ob_gzhandler'); +//ob_start('ob_gzhandler'); $app = Application::getInstance(); -$app->startRouter(include_once __DIR__ . '/../routes.php'); +if (isset($_COOKIE['msz_uid'], $_COOKIE['msz_sid'])) { + $app->startSession((int)$_COOKIE['msz_uid'], $_COOKIE['msz_sid']); +} + +$app->startRouter(include __DIR__ . '/../routes.php'); $app->startTemplating(); echo $app->router->resolve( diff --git a/src/Application.php b/src/Application.php index 77640cce..e1399ade 100644 --- a/src/Application.php +++ b/src/Application.php @@ -3,6 +3,7 @@ namespace Misuzu; use Aitemu\RouteCollection; use Misuzu\Config\ConfigManager; +use Misuzu\Users\Session; use UnexpectedValueException; use InvalidArgumentException; @@ -22,9 +23,14 @@ class Application extends ApplicationBase */ private const DATABASE_CONNECTIONS = [ 'mysql-main', - //'mysql-ayase', ]; + /** + * Session instance. + * @var \Misuzu\Users\Session + */ + public $session = null; + /** * Constructor, called by ApplicationBase::start() which also passes the arguments through. * @param ?string $configFile @@ -36,9 +42,6 @@ class Application extends ApplicationBase ExceptionHandler::register(); ExceptionHandler::debug($this->debugMode); $this->addModule('config', new ConfigManager($configFile)); - - // temporary session system - session_start(); } public function __destruct() @@ -46,6 +49,15 @@ class Application extends ApplicationBase ExceptionHandler::unregister(); } + public function startSession(int $user_id, string $session_key): void + { + $session = Session::where('session_key', $session_key)->where('user_id', $user_id)->first(); + + if ($session !== null) { + $this->session = $session; + } + } + /** * Sets up the database module. */ @@ -68,7 +80,7 @@ class Application extends ApplicationBase $database = $this->database; foreach (self::DATABASE_CONNECTIONS as $name) { - $section = 'Database.' . $name; + $section = "Database.{$name}"; if (!$config->contains($section)) { throw new InvalidArgumentException("Database {$name} is not configured."); @@ -100,7 +112,7 @@ class Application extends ApplicationBase $twig->addFunction('git_hash', [Application::class, 'gitCommitHash']); $twig->addFunction('git_branch', [Application::class, 'gitBranch']); - $twig->vars(['app' => $this, 'tsession' => $_SESSION]); + $twig->var('app', $this); $twig->addPath('nova', __DIR__ . '/../views/nova'); } diff --git a/src/Controllers/AuthController.php b/src/Controllers/AuthController.php index 961d6a99..10e879bb 100644 --- a/src/Controllers/AuthController.php +++ b/src/Controllers/AuthController.php @@ -2,11 +2,13 @@ namespace Misuzu\Controllers; use Aitemu\RouterResponse; +use Carbon\Carbon; use Illuminate\Database\Eloquent\ModelNotFoundException; use Misuzu\Application; use Misuzu\Database; use Misuzu\Net\IP; use Misuzu\Users\User; +use Misuzu\Users\Session; class AuthController extends Controller { @@ -36,23 +38,48 @@ class AuthController extends Controller return ['error' => 'Invalid username or password!']; } - $_SESSION['user_id'] = $user->user_id; - $_SESSION['username'] = $user->username; + $session = new Session; + $session->user_id = $user->user_id; + $session->session_ip = IP::unpack(IP::remote()); + $session->user_agent = 'Misuzu Testing 1'; + $session->expires_on = Carbon::now()->addMonth(); + $session->session_key = bin2hex(random_bytes(32)); + $session->save(); - $user->user_chat_key = $_SESSION['chat_key'] = bin2hex(random_bytes(16)); + Application::getInstance()->session = $session; + $this->setCookie('uid', $session->user_id, 604800); + $this->setCookie('sid', $session->session_key, 604800); + + // Temporary key generation for chat login. + // Should eventually be replaced with a callback login system. + // Also uses different cookies since $httponly is required to be false for these. + $user->user_chat_key = bin2hex(random_bytes(16)); $user->save(); - setcookie('msz_tmp_id', $_SESSION['user_id'], time() + 604800, '/', '.flashii.net'); - setcookie('msz_tmp_key', $_SESSION['chat_key'], time() + 604800, '/', '.flashii.net'); + setcookie('msz_tmp_id', $user->user_id, time() + 604800, '/', '.flashii.net'); + setcookie('msz_tmp_key', $user->user_chat_key, time() + 604800, '/', '.flashii.net'); return ['error' => 'You are now logged in!', 'next' => '/']; } + private function setCookie(string $name, string $value, int $expires): void + { + setcookie( + "msz_{$name}", + $value, + time() + $expires, + '/', + '', + !empty($_SERVER['HTTPS']), + true + ); + } + private function hasRegistrations(?string $ipAddr = null): bool { $ipAddr = IP::unpack($ipAddr ?? IP::remote()); - if (User::where('register_ip', $ipAddr)->orWhere('last_ip', $ipAddr)->count()) { + if (User::withTrashed()->where('register_ip', $ipAddr)->orWhere('last_ip', $ipAddr)->count()) { return true; } @@ -137,7 +164,6 @@ class AuthController extends Controller $user->register_ip = IP::unpack(IP::remote()); $user->last_ip = IP::unpack(IP::remote()); $user->user_country = get_country_code(IP::remote()); - $user->user_registered = time(); $user->save(); return ['error' => 'Welcome to Flashii! You may now log in.', 'next' => '/auth/login']; @@ -145,8 +171,19 @@ class AuthController extends Controller public function logout() { - session_destroy(); - return 'Logged out.'; + $app = Application::getInstance(); + + if ($app->session === null) { + echo "You aren't logged in."; + } else { + echo "You've been logged out."; + $this->setCookie('uid', '', -3600); + $this->setCookie('sid', '', -3600); + $app->session->delete(); + $app->session = null; + } + + return ''; } private function validateUsername(string $username): string diff --git a/src/TemplateEngine.php b/src/TemplateEngine.php index e5f547d4..7e005768 100644 --- a/src/TemplateEngine.php +++ b/src/TemplateEngine.php @@ -113,6 +113,16 @@ class TemplateEngine $this->loader->addPath($path, $name); } + /** + * Sets a render var. + * @param string $name + * @param mixed $value + */ + public function var(string $name, $value): void + { + $this->vars[$name] = $value; + } + /** * Sets render vars. * @param array $vars diff --git a/src/Users/Session.php b/src/Users/Session.php new file mode 100644 index 00000000..41b43dce --- /dev/null +++ b/src/Users/Session.php @@ -0,0 +1,14 @@ +belongsTo(User::class, 'user_id'); + } +} diff --git a/src/Users/User.php b/src/Users/User.php index f85db400..b1ff383d 100644 --- a/src/Users/User.php +++ b/src/Users/User.php @@ -6,5 +6,9 @@ use Misuzu\Model; class User extends Model { protected $primaryKey = 'user_id'; - public $timestamps = false; + + public function sessions() + { + return $this->hasMany(Session::class, 'user_id'); + } } diff --git a/views/nova/master.twig b/views/nova/master.twig index 5d40ba9d..536a8fb5 100644 --- a/views/nova/master.twig +++ b/views/nova/master.twig @@ -16,10 +16,13 @@
- -