From fb5323c2834f8268cd055f5997417a6c31440575 Mon Sep 17 00:00:00 2001 From: James Cole Date: Wed, 7 Mar 2018 20:21:36 +0100 Subject: [PATCH] Code to facilitate #1123 --- .../Controllers/System/InstallController.php | 72 ++++++++++++++++ app/Http/Kernel.php | 4 + app/Http/Middleware/Installer.php | 86 +++++++++++++++++++ database/seeds/ConfigSeeder.php | 37 ++++++++ database/seeds/DatabaseSeeder.php | 1 + resources/views/install/index.twig | 13 +++ resources/views/layout/install.twig | 33 +++++++ routes/web.php | 9 ++ 8 files changed, 255 insertions(+) create mode 100644 app/Http/Controllers/System/InstallController.php create mode 100644 app/Http/Middleware/Installer.php create mode 100644 database/seeds/ConfigSeeder.php create mode 100644 resources/views/install/index.twig create mode 100644 resources/views/layout/install.twig diff --git a/app/Http/Controllers/System/InstallController.php b/app/Http/Controllers/System/InstallController.php new file mode 100644 index 0000000000..17fcc8cd63 --- /dev/null +++ b/app/Http/Controllers/System/InstallController.php @@ -0,0 +1,72 @@ +. + */ + +declare(strict_types=1); + +namespace FireflyIII\Http\Controllers\System; + + +use Artisan; +use FireflyIII\Http\Controllers\Controller; +use Laravel\Passport\Passport; +use phpseclib\Crypt\RSA; + +/** + * Class InstallController + */ +class InstallController extends Controller +{ + /** + * InstallController constructor. + */ + public function __construct() + { + // empty on purpose. + } + + /** + * @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector + */ + public function migrate() + { + Artisan::call('migrate', ['--seed' => true]); + + // create keys manually because for some reason the passport namespace + // does not exist + $rsa = new RSA(); + $keys = $rsa->createKey(4096); + + list($publicKey, $privateKey) = [ + Passport::keyPath('oauth-public.key'), + Passport::keyPath('oauth-private.key'), + ]; + + if ((file_exists($publicKey) || file_exists($privateKey))) { + return redirect(route('index')); + } + + file_put_contents($publicKey, array_get($keys, 'publickey')); + file_put_contents($privateKey, array_get($keys, 'privatekey')); + + return redirect(route('index')); + } + +} \ No newline at end of file diff --git a/app/Http/Kernel.php b/app/Http/Kernel.php index 35d914499d..19a823a5ae 100644 --- a/app/Http/Kernel.php +++ b/app/Http/Kernel.php @@ -26,6 +26,7 @@ use FireflyIII\Http\Middleware\Authenticate; use FireflyIII\Http\Middleware\AuthenticateTwoFactor; use FireflyIII\Http\Middleware\Binder; use FireflyIII\Http\Middleware\EncryptCookies; +use FireflyIII\Http\Middleware\Installer; use FireflyIII\Http\Middleware\IsAdmin; use FireflyIII\Http\Middleware\Range; use FireflyIII\Http\Middleware\RedirectIfAuthenticated; @@ -66,6 +67,7 @@ class Kernel extends HttpKernel TrimStrings::class, ConvertEmptyStringsToNull::class, TrustProxies::class, + Installer::class ]; /** @@ -90,6 +92,7 @@ class Kernel extends HttpKernel // MUST NOT be logged in. Does not care about 2FA or confirmation. 'user-not-logged-in' => [ + Installer::class, Sandstorm::class, EncryptCookies::class, AddQueuedCookiesToResponse::class, @@ -103,6 +106,7 @@ class Kernel extends HttpKernel // MUST NOT have 2FA // don't care about confirmation: 'user-logged-in-no-2fa' => [ + Installer::class, Sandstorm::class, EncryptCookies::class, AddQueuedCookiesToResponse::class, diff --git a/app/Http/Middleware/Installer.php b/app/Http/Middleware/Installer.php new file mode 100644 index 0000000000..f1969a1e7d --- /dev/null +++ b/app/Http/Middleware/Installer.php @@ -0,0 +1,86 @@ +url(); + $strpos = stripos($url, '/install'); + if (!($strpos === false)) { + return $next($request); + } + + // no tables present? + try { + DB::table('users')->count(); + } catch (QueryException $e) { + $message = $e->getMessage(); + Log::error('Access denied: ' . $message); + if ($this->isAccessDenied($message)) { + throw new FireflyException('It seems your database configuration is not correct. Please verify the username and password in your .env file.'); + } + if ($this->noTablesExist($message)) { + // redirect to UpdateController + Log::warning('There are no Firefly III tables present. Redirect to migrate routine.'); + + return response()->redirectTo(route('installer.migrate')); + } + throw new FireflyException(sprintf('Could not access the database: %s', $message)); + } + + // older version in config than database? + $configVersion = intval(config('firefly.db_version')); + $dbVersion = intval(FireflyConfig::get('db_version', 1)->data); + if ($configVersion > $dbVersion) { + Log::warning(sprintf( + 'The current installed version (%d) is older than the required version (%d). Redirect to migrate routine.', $dbVersion, $configVersion + )); + + // redirect to migrate routine: + return response()->redirectTo(route('installer.migrate')); + } + return $next($request); + } + + /** + * @param string $message + * + * @return bool + */ + protected function isAccessDenied(string $message): bool + { + return !(stripos($message, 'Access denied') === false); + } + + /** + * @param string $message + * + * @return bool + */ + protected function noTablesExist(string $message): bool + { + return !(stripos($message, 'Base table or view not found') === false); + } +} diff --git a/database/seeds/ConfigSeeder.php b/database/seeds/ConfigSeeder.php new file mode 100644 index 0000000000..d28f066b31 --- /dev/null +++ b/database/seeds/ConfigSeeder.php @@ -0,0 +1,37 @@ +first(); + if (is_null($entry)) { + Log::warning('No database version entry is present. Database is assumed to be OLD (version 1).'); + // FF old or no version present. Put at 1: + Configuration::create( + [ + 'name' => 'db_version', + 'data' => 1, + ] + ); + } + if (!is_null($entry)) { + $version = intval(config('firefly.db_version')); + $entry->data = $version; + $entry->save(); + + Log::warning(sprintf('Database entry exists. Update to latest version (%d)', $version)); + } + } +} diff --git a/database/seeds/DatabaseSeeder.php b/database/seeds/DatabaseSeeder.php index de5a134985..32cdf152a5 100644 --- a/database/seeds/DatabaseSeeder.php +++ b/database/seeds/DatabaseSeeder.php @@ -37,5 +37,6 @@ class DatabaseSeeder extends Seeder $this->call(TransactionTypeSeeder::class); $this->call(PermissionSeeder::class); $this->call(LinkTypeSeeder::class); + $this->call(ConfigSeeder::class); } } diff --git a/resources/views/install/index.twig b/resources/views/install/index.twig new file mode 100644 index 0000000000..7c36df9e57 --- /dev/null +++ b/resources/views/install/index.twig @@ -0,0 +1,13 @@ +{% extends "./layout/install" %} + +{% block content %} +
+ +
+
+ Hello +
+
+
+{% endblock %} + diff --git a/resources/views/layout/install.twig b/resources/views/layout/install.twig new file mode 100644 index 0000000000..3d354801ac --- /dev/null +++ b/resources/views/layout/install.twig @@ -0,0 +1,33 @@ + + + + + + + Firefly III - Installation and update + + + + + + + + + {# favicons #} + {% include('partials.favicons') %} + + + +
+ + {% block content %}{% endblock %} +
+ + + diff --git a/routes/web.php b/routes/web.php index ab14b32774..232ec1667d 100755 --- a/routes/web.php +++ b/routes/web.php @@ -22,6 +22,15 @@ declare(strict_types=1); +Route::group( + ['namespace' => 'FireflyIII\Http\Controllers\System', + 'as' => 'installer.', 'prefix' => 'install'], function () { + Route::get('', ['uses' => 'InstallController@index', 'as' => 'index']); + + Route::get('migrate', ['uses' => 'InstallController@migrate', 'as' => 'migrate']); +} +); + /** * These routes only work when the user is NOT logged in. */