First version of routine #732

This commit is contained in:
James Cole 2017-08-04 15:46:52 +02:00
parent 1878b5287b
commit 5d10a19bfa
No known key found for this signature in database
GPG Key ID: C16961E655E74B5E
11 changed files with 165 additions and 197 deletions

View File

@ -42,6 +42,7 @@ SHOW_INCOMPLETE_TRANSLATIONS=false
CACHE_PREFIX=firefly
EXCHANGE_RATE_SERVICE=fixerio
PASSWORD_SERVICE=false
GOOGLE_MAPS_API_KEY=
ANALYTICS_ID=

View File

@ -17,6 +17,7 @@ use Config;
use FireflyConfig;
use FireflyIII\Events\RegisteredUser;
use FireflyIII\Http\Controllers\Controller;
use FireflyIII\Http\Requests\UserRegistrationRequest;
use FireflyIII\User;
use Illuminate\Foundation\Auth\RegistersUsers;
use Illuminate\Http\Request;
@ -56,7 +57,7 @@ class RegisterController extends Controller
*
* @return \Illuminate\Contracts\View\Factory|\Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector|\Illuminate\View\View
*/
public function register(Request $request)
public function register(UserRegistrationRequest $request)
{
// is allowed to?
$singleUserMode = FireflyConfig::get('single_user_mode', Config::get('firefly.configuration.single_user_mode'))->data;

View File

@ -37,7 +37,7 @@ class ProfileFormRequest extends Request
{
return [
'current_password' => 'required',
'new_password' => 'required|confirmed',
'new_password' => 'required|confirmed|secure_password',
'new_password_confirmation' => 'required',
];
}

View File

@ -0,0 +1,53 @@
<?php
/**
* UserRegistrationRequest.php
* Copyright (c) 2017 thegrumpydictator@gmail.com
* This software may be modified and distributed under the terms of the Creative Commons Attribution-ShareAlike 4.0 International License.
*
* See the LICENSE file for details.
*/
declare(strict_types=1);
namespace FireflyIII\Http\Requests;
/**
* Class UserRegistrationRequest
*
*
* @package FireflyIII\Http\Requests
*/
class UserRegistrationRequest extends Request
{
/**
* @return bool
*/
public function authorize()
{
// Only everybody
return true;
}
/**
* @return array
*/
public function getUserData(): array
{
return [
'email' => $this->string('email'),
'password' => $this->string('password'),
];
}
/**
* @return array
*/
public function rules()
{
return [
'email' => 'email|required',
'password' => 'confirmed|secure_password',
];
}
}

View File

@ -39,6 +39,8 @@ use FireflyIII\Support\Amount;
use FireflyIII\Support\ExpandedForm;
use FireflyIII\Support\FireflyConfig;
use FireflyIII\Support\Navigation;
use FireflyIII\Support\Password\PwndVerifier;
use FireflyIII\Support\Password\Verifier;
use FireflyIII\Support\Preferences;
use FireflyIII\Support\Steam;
use FireflyIII\Support\Twig\AmountFormat;
@ -147,6 +149,9 @@ class FireflyServiceProvider extends ServiceProvider
$this->app->bind(FiscalHelperInterface::class, FiscalHelper::class);
$this->app->bind(BalanceReportHelperInterface::class, BalanceReportHelper::class);
$this->app->bind(BudgetReportHelperInterface::class, BudgetReportHelper::class);
// password verifier thing
$this->app->bind(Verifier::class, PwndVerifier::class);
}
}

View File

@ -0,0 +1,51 @@
<?php
/**
* PwndVerifier.php
* Copyright (c) 2017 thegrumpydictator@gmail.com
* This software may be modified and distributed under the terms of the Creative Commons Attribution-ShareAlike 4.0 International License.
*
* See the LICENSE file for details.
*/
declare(strict_types=1);
namespace FireflyIII\Support\Password;
use Log;
use Requests;
use Requests_Exception;
/**
* Class PwndVerifier
*
* @package FireflyIII\Support\Password
*/
class PwndVerifier implements Verifier
{
/**
* Verify the given password against (some) service.
*
* @param string $password
*
* @return bool
*/
public function validPassword(string $password): bool
{
$hash = sha1($password);
$uri = sprintf('https://haveibeenpwned.com/api/v2/pwnedpassword/%s', $hash);
$opt = ['useragent' => 'Firefly III v' . config('firefly.version'), 'timeout' => 2];
try {
$result = Requests::get($uri, ['originalPasswordIsAHash' => 'true'], $opt);
} catch (Requests_Exception $e) {
return true;
}
Log::debug(sprintf('Status code returned is %d', $result->status_code));
if ($result->status_code === 404) {
return true;
}
return false;
}
}

View File

@ -0,0 +1,29 @@
<?php
/**
* Verifier.php
* Copyright (c) 2017 thegrumpydictator@gmail.com
* This software may be modified and distributed under the terms of the Creative Commons Attribution-ShareAlike 4.0 International License.
*
* See the LICENSE file for details.
*/
declare(strict_types=1);
namespace FireflyIII\Support\Password;
/**
* Interface Verifier
*
* @package FireflyIII\Support\Password
*/
interface Verifier
{
/**
* Verify the given password against (some) service.
* @param string $password
*
* @return bool
*/
public function validPassword(string $password): bool;
}

View File

@ -24,11 +24,15 @@ use FireflyIII\Models\PiggyBank;
use FireflyIII\Models\TransactionType;
use FireflyIII\Repositories\Budget\BudgetRepositoryInterface;
use FireflyIII\Rules\Triggers\TriggerInterface;
use FireflyIII\Support\Password\Verifier;
use FireflyIII\User;
use Google2FA;
use Illuminate\Contracts\Encryption\DecryptException;
use Illuminate\Contracts\Translation\Translator;
use Illuminate\Validation\Validator;
use Log;
use Requests;
use Requests_Exception;
/**
* Class FireflyValidator
@ -274,6 +278,24 @@ class FireflyValidator extends Validator
return false;
}
/**
* @param $attribute
* @param $value
* @param $parameters
*
* @return bool
*/
public function validateSecurePassword($attribute, $value, $parameters): bool
{
$enabled = env('PASSWORD_SERVICE');
if (!$enabled) {
return true;
}
/** @var Verifier $service */
$service = app(Verifier::class);
return $service->validPassword($value);
}
/**
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
* @param $attribute

View File

@ -88,4 +88,5 @@ return [
'in_array' => 'The :attribute field does not exist in :other.',
'present' => 'The :attribute field must be present.',
'amount_zero' => 'The total amount cannot be zero',
'secure_password' => 'This is not a secure password. Please try again. For more information, visit https://goo.gl/NCh2tN',
];

View File

@ -1,38 +0,0 @@
{% extends "./layout/default" %}
{% block breadcrumbs %}
{{ Breadcrumbs.renderIfExists }}
{% endblock %}
{% block content %}
<div class="row">
<div class="col-lg-12 col-md-12 col-sm-12">
<div class="box box-default">
<div class="box-header with-border">
<h3 class="box-title">{{ 'import_finished'|_ }}</h3>
</div>
<div class="box-body">
<p>
{{ 'import_finished_intro'|_ }}
</p>
{% if tagId > 0 %}
<p>
{{ trans('firefly.import_finished_text_with_link', {tag: tagId})|raw }}
</p>
{% else %}
<p>
{{ 'import_finished_text_without_link'|_ }}
</p>
{% endif %}
<p>
{{ 'import_share_configuration'|_ }}
</p>
</div>
</div>
</div>
</div>
{% endblock %}
{% block scripts %}
{% endblock %}
{% block styles %}
{% endblock %}

View File

@ -1,157 +0,0 @@
{% extends "./layout/default" %}
{% block breadcrumbs %}
{{ Breadcrumbs.renderIfExists }}
{% endblock %}
{% block content %}
{# Initial display. Will refresh (and disappear almost immediately. #}
<div class="row status_initial statusbox">
<div class="col-lg-8 col-lg-offset-2 col-md-12 col-sm-12">
<div class="box box-primary">
<div class="box-header with-border">
<h3 class="box-title">{{ 'import_status_wait_title'|_ }}</h3>
</div>
<div class="box-body">
<p>
{{ 'import_status_wait_text'|_ }}
</p>
</div>
</div>
</div>
</div>
{# Fatal error display. Will be shown (duh) when something goes horribly wrong. #}
<div class="row fatal_error" style="display:none;">
<div class="col-lg-8 col-lg-offset-2 col-md-12 col-sm-12">
<div class="box box-danger">
<div class="box-header with-border">
<h3 class="box-title">{{ 'import_status_fatal_title'|_ }}</h3>
</div>
<div class="box-body">
<p>
{{ 'import_status_fatal_text'|_ }}
</p>
<p class="text-danger fatal_error_txt">
</p>
<p>
{{ 'import_status_fatal_more'|_ }}
</p>
</div>
</div>
</div>
</div>
{# Box for when the job is ready to start #}
<div class="row status_configured statusbox" style="display:none;">
<div class="col-lg-8 col-lg-offset-2 col-md-12 col-sm-12">
<div class="box box-primary">
<div class="box-header with-border">
<h3 class="box-title">{{ 'import_status_ready_title'|_ }}</h3>
</div>
<div class="box-body">
<p>
{{ 'import_status_ready_text'|_ }}
</p>
<p>
<code>php artisan firefly:start-import {{ job.key }}</code>
</p>
<div class="row">
<div class="col-lg-4">
<a href="{{ route('import.download', [job.key]) }}" class="btn btn-default"><i
class="fa fa-fw fa-download"></i> {{ 'import_status_ready_config'|_ }}</a>
</div>
<div class="col-lg-4">
<button class="btn btn-success start-job"><i class="fa fa-fw fa-gears"></i> {{ 'import_status_ready_start'|_ }}</button>
</div>
</div>
<p>
&nbsp;
</p>
<p class="text-info">
{{ 'import_status_ready_share'|_ }}
</p>
</div>
</div>
</div>
</div>
{# Box for when the job is running! #}
<div class="row status_running statusbox" style="display: none;">
<div class="col-lg-8 col-lg-offset-2 col-md-12 col-sm-12">
<div class="box box-primary">
<div class="box-header with-border">
<h3 class="box-title" id="import-status-title">{{ 'import_status_running_title'|_ }}</h3>
</div>
<div class="box-body">
<div id="import-status-holder">
<div class="progress" id="import-status-holder">
<div id="import-status-bar" class="progress-bar progress-bar-info active progress-bar-striped" role="progressbar"
aria-valuenow="100" aria-valuemin="0"
aria-valuemax="100" style="width: 100%;min-width:40px;">
</div>
</div>
<p id="import-status-txt">{{ 'import_status_running_placeholder'|_ }}</p>
</div>
</div>
</div>
</div>
</div>
{# displays the finished status of the import. #}
<div class="row status_finished statusbox" style="display:none;">
<div class="col-lg-8 col-lg-offset-2 col-md-12 col-sm-12">
<div class="box box-default">
<div class="box-header with-border">
<h3 class="box-title">{{ 'import_status_finished_title'|_ }}</h3>
</div>
<div class="box-body">
<p id="import-status-intro">
{{ 'import_status_finished_text'|_ }}
</p>
<p id="import-status-more-info"></p>
</div>
</div>
</div>
</div>
{# box to show error information. #}
<div class="row info_errors" style="display:none;">
<div class="col-lg-8 col-lg-offset-2 col-md-12 col-sm-12">
<div class="box box-danger">
<div class="box-header with-border">
<h3 class="box-title">{{ 'import_status_errors_title'|_ }}</h3>
</div>
<div class="box-body">
<p id="import-status-error-intro">
</p>
<div id="import-status-error-list"></div>
</div>
</div>
</div>
</div>
{% endblock %}
{% block scripts %}
<script type="text/javascript">
// some useful translations.
var langImportSingleError = '{{ 'import_status_errors_single'|_|escape }}';
var langImportMultiError = '{{ 'import_status_errors_multi'|_|escape }}';
//var langImportFatalError = '{{ 'import_error_fatal'|_|escape }}';
//var langImportTimeOutError = '{{ 'import_error_timeout'|_|escape }}';
//var langImportFinished = '{{ 'import_finished_all'|_|escape }}';
var jobKey = '{{ job.key }}';
var jobImportUrl = '{{ route('import.json', [job.key]) }}';
var jobStartUrl = '{{ route('import.start', [job.key]) }}';
var token = '{{ csrf_token() }}';
</script>
<script type="text/javascript" src="js/ff/import/status.js"></script>
{% endblock %}
{% block styles %}
{% endblock %}