Code to facilitate #1123

This commit is contained in:
James Cole 2018-03-07 20:21:36 +01:00
parent e2d1de94b7
commit fb5323c283
No known key found for this signature in database
GPG Key ID: C16961E655E74B5E
8 changed files with 255 additions and 0 deletions

View File

@ -0,0 +1,72 @@
<?php
/**
* InstallController.php
* Copyright (c) 2018 thegrumpydictator@gmail.com
*
* This file is part of Firefly III.
*
* Firefly III is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Firefly III is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Firefly III. If not, see <http://www.gnu.org/licenses/>.
*/
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'));
}
}

View File

@ -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,

View File

@ -0,0 +1,86 @@
<?php
namespace FireflyIII\Http\Middleware;
use Closure;
use DB;
use FireflyConfig;
use FireflyIII\Exceptions\FireflyException;
use Illuminate\Database\QueryException;
use Log;
/**
* Class Installer
*/
class Installer
{
/**
* Handle an incoming request.
*
* @throws FireflyException
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
*
* @return mixed
*/
public function handle($request, Closure $next)
{
$url = $request->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);
}
}

View File

@ -0,0 +1,37 @@
<?php
use FireflyIII\Models\Configuration;
use Illuminate\Database\Seeder;
/**
* Class ConfigSeeder
*/
class ConfigSeeder extends Seeder
{
/**
* Run the database seeds.
*
* @return void
*/
public function run()
{
$entry = Configuration::where('name', 'db_version')->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));
}
}
}

View File

@ -37,5 +37,6 @@ class DatabaseSeeder extends Seeder
$this->call(TransactionTypeSeeder::class);
$this->call(PermissionSeeder::class);
$this->call(LinkTypeSeeder::class);
$this->call(ConfigSeeder::class);
}
}

View File

@ -0,0 +1,13 @@
{% extends "./layout/install" %}
{% block content %}
<div class="login-box-body">
<p class="login-box-msg">Please wait...</p>
<div class="row">
<div class="col-xs-8">
Hello
</div>
</div>
</div>
{% endblock %}

View File

@ -0,0 +1,33 @@
<!DOCTYPE html>
<html lang="en">
<head>
<base href="{{ route('index') }}/">
<meta charset="UTF-8">
<meta name="robots" content="noindex, nofollow, noarchive, noodp, NoImageIndex, noydir">
<title>Firefly III - Installation and update</title>
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta content='width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no' name='viewport'>
<link href="css/app.css?v={{ FF_VERSION }}" rel="stylesheet" type="text/css"/>
<link href="lib/adminlte/css/AdminLTE.min.css?v={{ FF_VERSION }}" rel="stylesheet" type="text/css"/>
<link href="css/firefly.css?v={{ FF_VERSION }}" rel="stylesheet" type="text/css"/>
<!--[if lt IE 9]>
<script src="js/lib/html5shiv.min.js?v={{ FF_VERSION }}"></script>
<script src="js/lib/respond.min.js?v={{ FF_VERSION }}"></script>
<![endif]-->
{# favicons #}
{% include('partials.favicons') %}
</head>
<body class="login-page">
<div class="login-box">
<div class="login-logo">
<b>Firefly</b>III<br />
<span style="font-family: monospace;font-size:16pt;">installation and upgrade</span>
</div>
{% block content %}{% endblock %}
</div>
<script src="js/app.js?v={{ FF_VERSION }}" type="text/javascript"></script>
</body>
</html>

View File

@ -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.
*/