refs #5: reworked the installation screens to create an identical, unprotected version. Integrated SourceGuardian's license error handling to be more helpful to the end user

This commit is contained in:
Andy Heathershaw 2016-10-06 11:30:39 +01:00
parent 51b03acbcd
commit 3cb9c98035
17 changed files with 286 additions and 108 deletions

View File

@ -3,7 +3,7 @@
<component name="WebServers">
<option name="servers">
<webServer id="b14a34b0-0127-4886-964a-7be75a2281ac" name="Development" url="http://blue-twilight-dev.andys.eu">
<fileTransfer host="mickey.prod.pandy06269.uk0.bigv.io" port="22" rootFolder="/srv/www/blue-twilight-dev" accessType="SFTP">
<fileTransfer host="mickey.prod.pandy06269.uk0.bigv.io" port="22" rootFolder="/srv/www/blue-twilight-test" accessType="SFTP">
<advancedOptions>
<advancedOptions dataProtectionLevel="Private" />
</advancedOptions>

View File

@ -5,6 +5,7 @@ namespace App\Http\Middleware;
use App\Album;
use App\Facade\Theme;
use App\Facade\UserConfig;
use App\Helpers\DbHelper;
use Closure;
use Illuminate\Foundation\Application;
use Illuminate\Http\Request;
@ -55,7 +56,7 @@ class GlobalConfiguration
private function addAlbumsToView()
{
$albums = Album::all()->sortBy('name');
$albums = DbHelper::getAlbumsForCurrentUser();
View::share('albums', $albums);
}

View File

@ -16,7 +16,7 @@ return [
|
*/
'driver' => env('SESSION_DRIVER', 'database'),
'driver' => env('SESSION_DRIVER', 'file'),
/*
|--------------------------------------------------------------------------

View File

@ -4,11 +4,12 @@
</IfModule>
RewriteEngine On
RewriteBase /
# If not installed, redirect to install folder
# If not installed, redirect to install route
RewriteCond %{DOCUMENT_ROOT}/../blue-twilight.lic !-f
RewriteCond %{REQUEST_URI} !^/upload-license.php
RewriteRule .* /upload-license.php [L,R=302]
RewriteCond %{REQUEST_URI} !upload-license.php$
RewriteRule .* upload-license.php [L,R=302]
# Redirect Trailing Slashes If Not A Folder...
RewriteCond %{REQUEST_FILENAME} !-d

View File

@ -0,0 +1,75 @@
<?php
/* START EXISTING LICENSE CHECK */
/* For security reasons, don't allow use of this page if a license file already exists */
$licenseFile = sprintf('%s/blue-twilight.lic', dirname(__DIR__));
if (file_exists($licenseFile))
{
header('Location: index.php');
exit();
}
/* START LANGUAGE */
$lang = 'en';
if (isset($_GET['lang']))
{
$lang = trim(strtolower(stripslashes($_GET['lang'])));
}
$langFile = sprintf('%s/raw/lang.%s.php', __DIR__, $lang);
if (!file_exists($langFile))
{
$langFile = sprintf('%s/raw/lang.en.php', __DIR__);
}
$lang = include $langFile;
/* END LANGUAGE */
/* START UPLOAD PROCESSING */
$uploadError = null;
if (strtolower($_SERVER['REQUEST_METHOD']) == 'post' && isset($_FILES['upload-license-file']))
{
if ($_FILES['upload-license-file']['error'] != 0)
{
$uploadError = $lang['upload_errors'][$_FILES['upload-license-file']['error']];
}
elseif (!move_uploaded_file($_FILES['upload-license-file']['tmp_name'], $licenseFile))
{
$uploadError = $lang['upload_errors'][99];
}
else
{
header('Location: index.php');
exit();
}
}
/* END UPLOAD PROCESSING */
ob_start();
?>
<h1><?php echo $lang['license_required_title']; ?></h1>
<p><?php echo $lang['license_required_p1']; ?></p>
<p><?php echo str_replace(':host_name', sprintf('<b>%s</b>', $_SERVER['SERVER_NAME']), $lang['license_required_p2']); ?></p>
<hr/>
<?php if (!is_null($uploadError)): ?>
<div class="alert alert-danger">
<p><?php echo $uploadError; ?></p>
</div>
<?php endif; ?>
<form action="license-required.php" method="post" enctype="multipart/form-data">
<div class="form-group">
<label class="control-label"><?php echo $lang['upload_license_label']; ?></label>
<input type="file" name="upload-license-file"/>
</div>
<div class="form-group">
<button class="btn btn-success" type="submit"><?php echo $lang['upload_action']; ?></button>
</div>
</form>
<?php
$content = ob_get_clean();
require sprintf('%s/raw/layout.php', __DIR__);
?>

21
public/raw/lang.en.php Normal file
View File

@ -0,0 +1,21 @@
<?php
return [
'app_name' => 'Blue Twilight - Install',
'copyright' => sprintf('© %s <a href="http://www.andyheathershaw.uk/" target="_blank">Andy Heathershaw</a>.', (date('Y') == 2016 ? 2016 : '2016-' . date('Y'))),
'license_required_p1' => 'Blue Twilight requires a license to run correctly. You can generate and download a license file from the <a href="http://shop.andyheathershaw.uk/user/orders" target="_blank">My Orders</a> page.',
'license_required_p2' => 'Your license file must match the hostname: :host_name.',
'license_required_title' => 'License Required',
'powered_by' => 'Powered by <a href="http://www.andyheathershaw.uk/blue-twilight" target="_blank">Blue Twilight</a> - the self-hosted photo gallery software.',
'upload_action' => 'Upload',
'upload_errors' => [
1 => 'The uploaded file exceeds the upload_max_filesize directive in php.ini.',
2 => 'The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form.',
3 => 'The uploaded file was only partially uploaded.',
4 => 'No file was uploaded.',
6 => 'Missing a temporary folder.',
7 => 'Failed to write file to disk.',
8 => 'A PHP extension blocked the file upload - please contact your system administrator.',
99 => 'Failed to write the license file - please check file permissions in Blue Twilight\'s root directory.'
],
'upload_license_label' => 'Please locate your license file to upload:'
];

60
public/raw/layout.php Normal file
View File

@ -0,0 +1,60 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="generator" content="{{ config('app.name') }} v{{ config('app.version') }} (framework v{{ App::VERSION() }})">
<title><?php echo $lang['app_name']; ?></title>
<link href="themes/base/bootstrap/css/bootstrap.min.css" rel="stylesheet">
<link href="themes/base/font-awesome/css/font-awesome.min.css" rel="stylesheet">
<link href="themes/base/css/app.css" rel="stylesheet">
<link href="themes/bootstrap3/theme.css" rel="stylesheet">
</head>
<body>
<nav class="navbar navbar-inverse navbar-static-top">
<div class="container">
<!-- Brand and toggle get grouped for better mobile display -->
<div class="navbar-header">
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1" aria-expanded="false">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="index.php"><i class="fa fa-fw fa-photo"></i> <?php echo $lang['app_name']; ?></a>
</div>
<!-- Collect the nav links, forms, and other content for toggling -->
<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
<ul class="nav navbar-nav">
</ul>
</div><!-- /.navbar-collapse -->
</div><!-- /.container-fluid -->
</nav>
<div class="container-fluid">
<div class="container">
<?php echo $content; ?>
</div>
<div class="container" style="margin-top: 40px;">
<div class="row">
<div class="col-xs-12">
<hr/>
<p style="font-size: smaller;">
<b><?php echo $lang['powered_by']; ?></b><br/>
<?php echo $lang['copyright']; ?>
</p>
</div>
</div>
</div>
</div>
<script src="themes/base/js/jquery.min.js"></script>
<script src="themes/base/bootstrap/js/bootstrap.min.js"></script>
<script src="themes/base/js/app.js"></script>
</body>
</html>

View File

@ -0,0 +1,13 @@
<?php
function btw_license_error($code, $message)
{
header(sprintf('Location: license-required.php?licerror=%d', $code));
exit();
}
function btw_loader_error()
{
header('Location: loader-required.php');
exit();
}
?>

View File

@ -1,41 +0,0 @@
<?php
$baseDirectory = dirname(__DIR__);
$error = null;
if (strtoupper($_SERVER['REQUEST_METHOD']) == 'POST')
{
move_uploaded_file($_FILES['license-file']['tmp_name'], $baseDirectory . '/blue-twilight.lic');
try
{
$licenseInfo = (require $baseDirectory . '/verify-license.php');
if (!is_null($licenseInfo) && is_array($licenseInfo))
{
header('Location: ' . str_replace('/upload-license.php', '/', $_SERVER['REQUEST_URI']));
die();
}
}
catch (\Exception $e)
{
$error = $e->getMessage();
}
}
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- The above 3 meta tags *must* come first in the head; any other head content must come *after* these tags -->
<title>Blue Twilight - License Needed</title>
</head>
<body>
<h1>Blue Twilight - License Needed</h1>
<form action="upload-license.php" method="post" enctype="multipart/form-data">
<p><label for="license-file">Upload your <u>blue-twilight.lic</u> license file:</label></p>
<p><input type="file" id="license-file" name="license-file"></p>
<p><button type="submit" style="font-size: larger;">Upload</button></p>
</form>
</body>
</html>

View File

@ -1,14 +1,10 @@
<?php
return [
/*'app_name' => 'Blue Twilight Installer',
'license_file_label' => 'Upload your license file:',
'license_required_text' => 'Blue Twilight requires a license file to run. The license file is called "blue-twilight.lic" ' .
'and can be downloaded from the %link_start%My Orders%link_end% page on the %link2_start%Apps by Andy - Web Store%link2_end%.',
'license_required_text2' => 'The host name in the license file must be: ',
'license_required_text3' => 'Once you have your license file, please upload it using the field below.',
'licensed_to' => 'Licensed to: ',
'save_button' => 'Save',
'upload_button' => 'Upload'*/
'administrator_intro' => 'You will need an administrator account to access Blue Twilight. Complete the form below to create your administrator account.',
'administrator_title' => 'Create an administrator account',
'app_name' => 'Blue Twilight - Install',
'database_intro' => 'Please provide the connection details for an empty MySQL or MariaDB database.',
'database_title' => 'Connect to a Database',
'php_config' => [
'heading' => 'PHP configuration:',
'post_max_size' => 'Maximum POST request size:',

View File

@ -1,8 +1,8 @@
@extends('install.layout')
@section('content')
<p>You will need an administrator account to access Blue Twilight.</p>
<p>Please enter the below details to create your administrator account:</p>
<h3>@lang('installer.administrator_title')</h3>
<p>@lang('installer.administrator_intro')</p>
<div class="row" style="margin-top: 30px;">
<div class="col-md-6 col-md-offset-3">

View File

@ -59,14 +59,12 @@
</tbody>
</table>
@if ($can_continue)
<div class="text-right">
<form action="{{ route('install.check') }}" method="post">
{{ csrf_field() }}
<button type="submit" class="btn btn-success">@lang('forms.continue_action')</button>
</form>
</div>
@endif
<div class="text-right">
<form action="{{ route('install.check') }}" method="post">
{{ csrf_field() }}
<button type="submit" class="btn btn-success"@if (!$can_continue) disabled="disabled"@endif>@lang('forms.continue_action')</button>
</form>
</div>
</div>
</div>
@endsection

View File

@ -1,7 +1,8 @@
@extends('install.layout')
@section('content')
<p>Please provide the connection details to your MySQL database:</p>
<h3>@lang('installer.database_title')</h3>
<p>@lang('installer.database_intro')</p>
<div class="row" style="margin-top: 30px;">
<div class="col-md-6 col-md-offset-3">

View File

@ -1,44 +1,82 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="generator" content="{{ config('app.name') }} v{{ config('app.version') }} (framework v{{ App::VERSION() }})">
<!-- The above 3 meta tags *must* come first in the head; any other head content must come *after* these tags -->
<title>Blue Twilight - Installation</title>
<base href="{{ url('/') }}">
<title>@lang('installer.app_name')</title>
<base href="{{ route('home', [], false) }}">
<meta name="csrf-token" content="{{ csrf_token() }}">
<meta name="csrf-token" content="{{ csrf_token() }}">
<link href="themes/base/bootstrap/css/bootstrap.min.css?v={{ urlencode(config('app.version')) }}" rel="stylesheet">
<link href="themes/base/font-awesome/css/font-awesome.min.css?v={{ urlencode(config('app.version')) }}" rel="stylesheet">
<style type="text/css">
html, body {
height: 100%;
}
{{-- Cannot use $theme_url here: if a theme uses the base layout, it would also have to provide all these dependencies! --}}
{{-- As these files are shipped with core (not a theme) use the main app.version instead of the current theme's version --}}
<link href="themes/base/bootstrap/css/bootstrap.min.css?v={{ urlencode(config('app.version')) }}" rel="stylesheet">
<link href="themes/base/font-awesome/css/font-awesome.min.css?v={{ urlencode(config('app.version')) }}" rel="stylesheet">
<link href="themes/base/css/app.css?v={{ urlencode(config('app.version')) }}" rel="stylesheet">
<link href="themes/bootstrap3/theme.css?v={{ urlencode(config('app.version')) }}" rel="stylesheet">
body {
background-color: #d9edf7;
}
@stack('styles')
</head>
<body>
@include('install.navbar')
.container {
background-color: #fff;
height: 100%;
}
</style>
</head>
<body>
<div class="container">
<div class="row">
<div class="col-xs-12">
<h1>Install Blue Twilight</h1>
@yield('content')
<div class="container-fluid">
@if (isset($error))
<div class="container">
<div class="alert alert-danger">
<strong><i class="fa fa-exclamation-circle fa-fw"></i></strong> {{ $error }}
</div>
</div>
@endif
@if (isset($warning))
<div class="container">
<div class="alert alert-warning">
<strong><i class="fa fa-warning fa-fw"></i></strong> {{ $warning }}
</div>
</div>
@endif
@if (isset($success))
<div class="container">
<div class="alert alert-success">
<strong><i class="fa fa-info-circle fa-fw"></i></strong> {{ $success }}
</div>
</div>
@endif
@if (isset($info))
<div class="container">
<div class="alert alert-info">
<strong><i class="fa fa-info-circle fa-fw"></i></strong> {{ $info }}
</div>
</div>
@endif
<div class="container">
@yield('content')
</div>
@include('themes.base.partials.copyright_gallery')
</div>
</div>
</div>
<script src="themes/base/js/jquery.min.js?v={{ urlencode(config('app.version')) }}"></script>
<script src="themes/base/bootstrap/js/bootstrap.min.js?v={{ urlencode(config('app.version')) }}"></script>
</body>
</html>
{{-- Cannot use $theme_url here: if a theme uses the base layout, it would also have to provide all these dependencies! --}}
{{-- As these files are shipped with core (not a theme) use the main app.version instead of the current theme's version --}}
<script src="themes/base/js/jquery.min.js?v={{ urlencode(config('app.version')) }}"></script>
<script src="themes/base/bootstrap/js/bootstrap.min.js?v={{ urlencode(config('app.version')) }}"></script>
<script src="themes/base/js/bootbox.min.js?v={{ urlencode(config('app.version')) }}"></script>
<script src="themes/base/js/knockout.min.js?v={{ urlencode(config('app.version')) }}"></script>
<script src="themes/base/js/app.js?v={{ urlencode(config('app.version')) }}"></script>
<script type="text/javascript">
$.ajaxSetup({
headers: {
'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
}
});
</script>
@stack('scripts')
</body>
</html>

View File

@ -0,0 +1,20 @@
<nav class="navbar navbar-inverse navbar-static-top">
<div class="container">
<!-- Brand and toggle get grouped for better mobile display -->
<div class="navbar-header">
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1" aria-expanded="false">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="{{ route('install.check') }}"><i class="fa fa-fw fa-photo"></i> @lang('installer.app_name')</a>
</div>
<!-- Collect the nav links, forms, and other content for toggling -->
<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
<ul class="nav navbar-nav">
</ul>
</div><!-- /.navbar-collapse -->
</div><!-- /.container-fluid -->
</nav>

View File

@ -8,7 +8,7 @@
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="{{ route('home') }}">{{ UserConfig::get('app_name') }}</a>
<a class="navbar-brand" href="{{ route('home') }}"><i class="fa fa-fw fa-photo"></i> {{ UserConfig::get('app_name') }}</a>
</div>
<!-- Collect the nav links, forms, and other content for toggling -->

View File

@ -1,5 +0,0 @@
<?php
return [
'lic_name' => sg_get_const('lic_name'),
'lic_num' => sg_get_const('lic_num')
];