mirror of
https://github.com/wallabag/wallabag.git
synced 2024-11-26 02:51:04 +00:00
Merge remote-tracking branch 'origin/2.6' into port/2.6.7
Signed-off-by: Kevin Decherf <kevin@kdecherf.com>
This commit is contained in:
commit
4a5f769428
15 changed files with 192 additions and 128 deletions
11
CHANGELOG.md
11
CHANGELOG.md
|
@ -1,5 +1,16 @@
|
||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## [2.6.7](https://github.com/wallabag/wallabag/tree/2.6.7)
|
||||||
|
[Full Changelog](https://github.com/wallabag/wallabag/compare/2.6.6...2.6.7)
|
||||||
|
|
||||||
|
### Security fix
|
||||||
|
* A user can disable her 2FA unintentionally by @kdecherf in https://github.com/wallabag/wallabag/commit/0cfdddc2eb0aee5ffb69bf499d377d75655ba157
|
||||||
|
|
||||||
|
### Fixes
|
||||||
|
* Fix deprecated null tag parameter by @Simounet in https://github.com/wallabag/wallabag/pull/6985
|
||||||
|
* Full clickable card on mass action by @Simounet in https://github.com/wallabag/wallabag/pull/6991
|
||||||
|
* Add tag form submit button always displayed by @Simounet in https://github.com/wallabag/wallabag/pull/6986
|
||||||
|
|
||||||
## [2.6.6](https://github.com/wallabag/wallabag/tree/2.6.6)
|
## [2.6.6](https://github.com/wallabag/wallabag/tree/2.6.6)
|
||||||
[Full Changelog](https://github.com/wallabag/wallabag/compare/2.6.5...2.6.6)
|
[Full Changelog](https://github.com/wallabag/wallabag/compare/2.6.5...2.6.6)
|
||||||
|
|
||||||
|
|
|
@ -235,6 +235,12 @@
|
||||||
z-index: 9999;
|
z-index: 9999;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.tags-add-form {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
@media only screen and (max-width: 640px) {
|
@media only screen and (max-width: 640px) {
|
||||||
.entry-info {
|
.entry-info {
|
||||||
margin-bottom: 20px;
|
margin-bottom: 20px;
|
||||||
|
@ -258,4 +264,12 @@
|
||||||
#article .entry-info .chip-action {
|
#article .entry-info .chip-action {
|
||||||
min-width: 40px;
|
min-width: 40px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.tags-add-form {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tags-add-form-submit {
|
||||||
|
margin-top: 10px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,25 +38,29 @@
|
||||||
border-radius: 2px 0 0 2px;
|
border-radius: 2px 0 0 2px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.entry-checkbox {
|
.card-stacked .entry-checkbox {
|
||||||
margin: 10px 15px 10px 5px;
|
margin: 10px 15px 10px 5px;
|
||||||
|
}
|
||||||
|
|
||||||
.card & {
|
.card .entry-checkbox {
|
||||||
float: right;
|
position: absolute;
|
||||||
margin-right: 0;
|
display: flex;
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
}
|
inset: 0;
|
||||||
|
justify-content: flex-end;
|
||||||
|
align-items: start;
|
||||||
|
background-color: rgb(0 172 193 / 20%);
|
||||||
|
cursor: pointer;
|
||||||
|
z-index: 10;
|
||||||
}
|
}
|
||||||
|
|
||||||
.entries .entry-checkbox-input,
|
.entries .entry-checkbox-input,
|
||||||
.mass-action .entry-checkbox-input {
|
.mass-action .entry-checkbox-input {
|
||||||
position: relative;
|
position: relative;
|
||||||
left: 0;
|
|
||||||
width: 20px;
|
width: 20px;
|
||||||
min-height: 25px;
|
min-height: 25px;
|
||||||
height: 100%;
|
|
||||||
vertical-align: middle;
|
|
||||||
opacity: initial;
|
opacity: initial;
|
||||||
|
cursor: pointer;
|
||||||
z-index: 10;
|
z-index: 10;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
wallabag_core:
|
wallabag_core:
|
||||||
version: 2.6.6
|
version: 2.6.7
|
||||||
paypal_url: "https://liberapay.com/wallabag/donate"
|
paypal_url: "https://liberapay.com/wallabag/donate"
|
||||||
languages:
|
languages:
|
||||||
en: 'English'
|
en: 'English'
|
||||||
|
|
12
composer.lock
generated
12
composer.lock
generated
|
@ -4604,16 +4604,16 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "j0k3r/graby-site-config",
|
"name": "j0k3r/graby-site-config",
|
||||||
"version": "1.0.173",
|
"version": "1.0.177",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/j0k3r/graby-site-config.git",
|
"url": "https://github.com/j0k3r/graby-site-config.git",
|
||||||
"reference": "e54353732d257639039d358972e8947b5d7f05d2"
|
"reference": "cce11a0d0ec6fc06cebda65c340fcfb7c63ce78a"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/j0k3r/graby-site-config/zipball/e54353732d257639039d358972e8947b5d7f05d2",
|
"url": "https://api.github.com/repos/j0k3r/graby-site-config/zipball/cce11a0d0ec6fc06cebda65c340fcfb7c63ce78a",
|
||||||
"reference": "e54353732d257639039d358972e8947b5d7f05d2",
|
"reference": "cce11a0d0ec6fc06cebda65c340fcfb7c63ce78a",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
|
@ -4642,9 +4642,9 @@
|
||||||
"description": "Graby site config files",
|
"description": "Graby site config files",
|
||||||
"support": {
|
"support": {
|
||||||
"issues": "https://github.com/j0k3r/graby-site-config/issues",
|
"issues": "https://github.com/j0k3r/graby-site-config/issues",
|
||||||
"source": "https://github.com/j0k3r/graby-site-config/tree/1.0.173"
|
"source": "https://github.com/j0k3r/graby-site-config/tree/1.0.177"
|
||||||
},
|
},
|
||||||
"time": "2023-08-21T09:46:59+00:00"
|
"time": "2023-10-01T02:12:17+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "j0k3r/httplug-ssrf-plugin",
|
"name": "j0k3r/httplug-ssrf-plugin",
|
||||||
|
|
|
@ -17,7 +17,7 @@ parameters:
|
||||||
|
|
||||||
-
|
-
|
||||||
message: "#^Method FOS\\\\UserBundle\\\\Model\\\\UserManagerInterface\\:\\:updateUser\\(\\) invoked with 2 parameters, 1 required\\.$#"
|
message: "#^Method FOS\\\\UserBundle\\\\Model\\\\UserManagerInterface\\:\\:updateUser\\(\\) invoked with 2 parameters, 1 required\\.$#"
|
||||||
count: 7
|
count: 6
|
||||||
path: src/Wallabag/CoreBundle/Controller/ConfigController.php
|
path: src/Wallabag/CoreBundle/Controller/ConfigController.php
|
||||||
|
|
||||||
-
|
-
|
||||||
|
@ -74,3 +74,8 @@ parameters:
|
||||||
message: "#^Call to an undefined method Wallabag\\\\ImportBundle\\\\Import\\\\ImportInterface\\:\\:setFilepath\\(\\)\\.$#"
|
message: "#^Call to an undefined method Wallabag\\\\ImportBundle\\\\Import\\\\ImportInterface\\:\\:setFilepath\\(\\)\\.$#"
|
||||||
count: 1
|
count: 1
|
||||||
path: src/Wallabag/ImportBundle/Controller/HtmlController.php
|
path: src/Wallabag/ImportBundle/Controller/HtmlController.php
|
||||||
|
|
||||||
|
-
|
||||||
|
message: "#^Method Symfony\\\\Contracts\\\\EventDispatcher\\\\EventDispatcherInterface\\:\\:dispatch()#"
|
||||||
|
count: 16
|
||||||
|
path: src/*
|
||||||
|
|
|
@ -14,6 +14,3 @@ parameters:
|
||||||
- vendor/bin/.phpunit/phpunit-8.5-0/vendor/autoload.php
|
- vendor/bin/.phpunit/phpunit-8.5-0/vendor/autoload.php
|
||||||
|
|
||||||
inferPrivatePropertyTypeFromConstructor: true
|
inferPrivatePropertyTypeFromConstructor: true
|
||||||
|
|
||||||
ignoreErrors:
|
|
||||||
- "#^Method Symfony\\\\Contracts\\\\EventDispatcher\\\\EventDispatcherInterface\\:\\:dispatch\\(\\) invoked with 2 parameters, 1 required\\.$#"
|
|
||||||
|
|
|
@ -262,10 +262,14 @@ class ConfigController extends AbstractController
|
||||||
/**
|
/**
|
||||||
* Disable 2FA using email.
|
* Disable 2FA using email.
|
||||||
*
|
*
|
||||||
* @Route("/config/otp/email/disable", name="disable_otp_email")
|
* @Route("/config/otp/email/disable", name="disable_otp_email", methods={"POST"})
|
||||||
*/
|
*/
|
||||||
public function disableOtpEmailAction()
|
public function disableOtpEmailAction(Request $request)
|
||||||
{
|
{
|
||||||
|
if (!$this->isCsrfTokenValid('otp', $request->request->get('token'))) {
|
||||||
|
throw $this->createAccessDeniedException('Bad CSRF token.');
|
||||||
|
}
|
||||||
|
|
||||||
$user = $this->getUser();
|
$user = $this->getUser();
|
||||||
$user->setEmailTwoFactor(false);
|
$user->setEmailTwoFactor(false);
|
||||||
|
|
||||||
|
@ -282,10 +286,14 @@ class ConfigController extends AbstractController
|
||||||
/**
|
/**
|
||||||
* Enable 2FA using email.
|
* Enable 2FA using email.
|
||||||
*
|
*
|
||||||
* @Route("/config/otp/email", name="config_otp_email")
|
* @Route("/config/otp/email", name="config_otp_email", methods={"POST"})
|
||||||
*/
|
*/
|
||||||
public function otpEmailAction()
|
public function otpEmailAction(Request $request)
|
||||||
{
|
{
|
||||||
|
if (!$this->isCsrfTokenValid('otp', $request->request->get('token'))) {
|
||||||
|
throw $this->createAccessDeniedException('Bad CSRF token.');
|
||||||
|
}
|
||||||
|
|
||||||
$user = $this->getUser();
|
$user = $this->getUser();
|
||||||
|
|
||||||
$user->setGoogleAuthenticatorSecret(null);
|
$user->setGoogleAuthenticatorSecret(null);
|
||||||
|
@ -305,10 +313,14 @@ class ConfigController extends AbstractController
|
||||||
/**
|
/**
|
||||||
* Disable 2FA using OTP app.
|
* Disable 2FA using OTP app.
|
||||||
*
|
*
|
||||||
* @Route("/config/otp/app/disable", name="disable_otp_app")
|
* @Route("/config/otp/app/disable", name="disable_otp_app", methods={"POST"})
|
||||||
*/
|
*/
|
||||||
public function disableOtpAppAction()
|
public function disableOtpAppAction(Request $request)
|
||||||
{
|
{
|
||||||
|
if (!$this->isCsrfTokenValid('otp', $request->request->get('token'))) {
|
||||||
|
throw $this->createAccessDeniedException('Bad CSRF token.');
|
||||||
|
}
|
||||||
|
|
||||||
$user = $this->getUser();
|
$user = $this->getUser();
|
||||||
|
|
||||||
$user->setGoogleAuthenticatorSecret('');
|
$user->setGoogleAuthenticatorSecret('');
|
||||||
|
@ -327,10 +339,14 @@ class ConfigController extends AbstractController
|
||||||
/**
|
/**
|
||||||
* Enable 2FA using OTP app, user will need to confirm the generated code from the app.
|
* Enable 2FA using OTP app, user will need to confirm the generated code from the app.
|
||||||
*
|
*
|
||||||
* @Route("/config/otp/app", name="config_otp_app")
|
* @Route("/config/otp/app", name="config_otp_app", methods={"POST"})
|
||||||
*/
|
*/
|
||||||
public function otpAppAction(GoogleAuthenticatorInterface $googleAuthenticator)
|
public function otpAppAction(Request $request, GoogleAuthenticatorInterface $googleAuthenticator)
|
||||||
{
|
{
|
||||||
|
if (!$this->isCsrfTokenValid('otp', $request->request->get('token'))) {
|
||||||
|
throw $this->createAccessDeniedException('Bad CSRF token.');
|
||||||
|
}
|
||||||
|
|
||||||
$user = $this->getUser();
|
$user = $this->getUser();
|
||||||
$secret = $googleAuthenticator->generateSecret();
|
$secret = $googleAuthenticator->generateSecret();
|
||||||
|
|
||||||
|
@ -365,8 +381,10 @@ class ConfigController extends AbstractController
|
||||||
* Cancelling 2FA using OTP app.
|
* Cancelling 2FA using OTP app.
|
||||||
*
|
*
|
||||||
* @Route("/config/otp/app/cancel", name="config_otp_app_cancel")
|
* @Route("/config/otp/app/cancel", name="config_otp_app_cancel")
|
||||||
|
*
|
||||||
|
* XXX: commented until we rewrite 2fa with a real two-steps activation
|
||||||
*/
|
*/
|
||||||
public function otpAppCancelAction()
|
/*public function otpAppCancelAction()
|
||||||
{
|
{
|
||||||
$user = $this->getUser();
|
$user = $this->getUser();
|
||||||
$user->setGoogleAuthenticatorSecret(null);
|
$user->setGoogleAuthenticatorSecret(null);
|
||||||
|
@ -375,15 +393,19 @@ class ConfigController extends AbstractController
|
||||||
$this->userManager->updateUser($user, true);
|
$this->userManager->updateUser($user, true);
|
||||||
|
|
||||||
return $this->redirect($this->generateUrl('config') . '#set3');
|
return $this->redirect($this->generateUrl('config') . '#set3');
|
||||||
}
|
}*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Validate OTP code.
|
* Validate OTP code.
|
||||||
*
|
*
|
||||||
* @Route("/config/otp/app/check", name="config_otp_app_check")
|
* @Route("/config/otp/app/check", name="config_otp_app_check", methods={"POST"})
|
||||||
*/
|
*/
|
||||||
public function otpAppCheckAction(Request $request, GoogleAuthenticatorInterface $googleAuthenticator)
|
public function otpAppCheckAction(Request $request, GoogleAuthenticatorInterface $googleAuthenticator)
|
||||||
{
|
{
|
||||||
|
if (!$this->isCsrfTokenValid('otp', $request->request->get('token'))) {
|
||||||
|
throw $this->createAccessDeniedException('Bad CSRF token.');
|
||||||
|
}
|
||||||
|
|
||||||
$isValid = $googleAuthenticator->checkCode(
|
$isValid = $googleAuthenticator->checkCode(
|
||||||
$this->getUser(),
|
$this->getUser(),
|
||||||
$request->get('_auth_code')
|
$request->get('_auth_code')
|
||||||
|
@ -403,7 +425,12 @@ class ConfigController extends AbstractController
|
||||||
'scheb_two_factor.code_invalid'
|
'scheb_two_factor.code_invalid'
|
||||||
);
|
);
|
||||||
|
|
||||||
return $this->redirect($this->generateUrl('config_otp_app'));
|
$this->addFlash(
|
||||||
|
'notice',
|
||||||
|
'scheb_two_factor.code_invalid'
|
||||||
|
);
|
||||||
|
|
||||||
|
return $this->redirect($this->generateUrl('config') . '#set3');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -4,7 +4,6 @@ namespace Wallabag\CoreBundle\Form\Type;
|
||||||
|
|
||||||
use FOS\UserBundle\Form\Type\RegistrationFormType;
|
use FOS\UserBundle\Form\Type\RegistrationFormType;
|
||||||
use Symfony\Component\Form\AbstractType;
|
use Symfony\Component\Form\AbstractType;
|
||||||
use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
|
|
||||||
use Symfony\Component\Form\Extension\Core\Type\EmailType;
|
use Symfony\Component\Form\Extension\Core\Type\EmailType;
|
||||||
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
|
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
|
||||||
use Symfony\Component\Form\Extension\Core\Type\TextType;
|
use Symfony\Component\Form\Extension\Core\Type\TextType;
|
||||||
|
@ -23,15 +22,6 @@ class UserInformationType extends AbstractType
|
||||||
->add('email', EmailType::class, [
|
->add('email', EmailType::class, [
|
||||||
'label' => 'config.form_user.email_label',
|
'label' => 'config.form_user.email_label',
|
||||||
])
|
])
|
||||||
->add('emailTwoFactor', CheckboxType::class, [
|
|
||||||
'required' => false,
|
|
||||||
'label' => 'config.form_user.emailTwoFactor_label',
|
|
||||||
])
|
|
||||||
->add('googleTwoFactor', CheckboxType::class, [
|
|
||||||
'required' => false,
|
|
||||||
'label' => 'config.form_user.googleTwoFactor_label',
|
|
||||||
'mapped' => false,
|
|
||||||
])
|
|
||||||
->add('save', SubmitType::class, [
|
->add('save', SubmitType::class, [
|
||||||
'label' => 'config.form.save',
|
'label' => 'config.form.save',
|
||||||
])
|
])
|
||||||
|
|
|
@ -269,38 +269,66 @@
|
||||||
|
|
||||||
{{ form_widget(form.user.save, {'attr': {'class': 'btn waves-effect waves-light'}}) }}
|
{{ form_widget(form.user.save, {'attr': {'class': 'btn waves-effect waves-light'}}) }}
|
||||||
|
|
||||||
<br/>
|
|
||||||
<br/>
|
|
||||||
<div class="row">
|
|
||||||
<h5>{{ 'config.otp.page_title'|trans }}</h5>
|
|
||||||
|
|
||||||
<p>{{ 'config.form_user.two_factor_description'|trans }}</p>
|
|
||||||
|
|
||||||
<table>
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th>{{ 'config.form_user.two_factor.table_method'|trans }}</th>
|
|
||||||
<th>{{ 'config.form_user.two_factor.table_state'|trans }}</th>
|
|
||||||
<th>{{ 'config.form_user.two_factor.table_action'|trans }}</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
|
|
||||||
<tbody>
|
|
||||||
<tr>
|
|
||||||
<td>{{ 'config.form_user.two_factor.emailTwoFactor_label'|trans }}</td>
|
|
||||||
<td>{% if app.user.isEmailTwoFactor %}<b>{{ 'config.form_user.two_factor.state_enabled'|trans }}</b>{% else %}{{ 'config.form_user.two_factor.state_disabled'|trans }}{% endif %}</td>
|
|
||||||
<td><a href="{{ path('config_otp_email') }}" class="waves-effect waves-light btn{% if app.user.isEmailTwoFactor %} disabled{% endif %}">{{ 'config.form_user.two_factor.action_email'|trans }}</a> {% if app.user.isEmailTwoFactor %}<a href="{{ path('disable_otp_email') }}" class="waves-effect waves-light btn red">Disable</a>{% endif %}</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>{{ 'config.form_user.two_factor.googleTwoFactor_label'|trans }}</td>
|
|
||||||
<td>{% if app.user.isGoogleTwoFactor %}<b>{{ 'config.form_user.two_factor.state_enabled'|trans }}</b>{% else %}{{ 'config.form_user.two_factor.state_disabled'|trans }}{% endif %}</td>
|
|
||||||
<td><a href="{{ path('config_otp_app') }}" class="waves-effect waves-light btn{% if app.user.isGoogleTwoFactor %} disabled{% endif %}">{{ 'config.form_user.two_factor.action_app'|trans }}</a> {% if app.user.isGoogleTwoFactor %}<a href="{{ path('disable_otp_app') }}" class="waves-effect waves-light btn red">Disable</a>{% endif %}</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
{{ form_widget(form.user._token) }}
|
{{ form_widget(form.user._token) }}
|
||||||
</form>
|
|
||||||
|
{{ form_end(form.user) }}
|
||||||
|
|
||||||
|
<br/>
|
||||||
|
<br/>
|
||||||
|
<div class="row">
|
||||||
|
<h5>{{ 'config.otp.page_title'|trans }}</h5>
|
||||||
|
|
||||||
|
<p>{{ 'config.form_user.two_factor_description'|trans }}</p>
|
||||||
|
|
||||||
|
<table>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>{{ 'config.form_user.two_factor.table_method'|trans }}</th>
|
||||||
|
<th>{{ 'config.form_user.two_factor.table_state'|trans }}</th>
|
||||||
|
<th>{{ 'config.form_user.two_factor.table_action'|trans }}</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td>{{ 'config.form_user.two_factor.emailTwoFactor_label'|trans }}</td>
|
||||||
|
<td>{% if app.user.isEmailTwoFactor %}<b>{{ 'config.form_user.two_factor.state_enabled'|trans }}</b>{% else %}{{ 'config.form_user.two_factor.state_disabled'|trans }}{% endif %}</td>
|
||||||
|
<td>
|
||||||
|
<form action="{{ path('config_otp_email') }}" method="post" name="config_otp_email">
|
||||||
|
<input type="hidden" name="token" value="{{ csrf_token('otp') }}" />
|
||||||
|
|
||||||
|
<button class="waves-effect waves-light btn{% if app.user.isEmailTwoFactor %} disabled{% endif %}" type="submit">{{ 'config.form_user.two_factor.action_email'|trans }}</button>
|
||||||
|
</form>
|
||||||
|
{% if app.user.isEmailTwoFactor %}
|
||||||
|
<form action="{{ path('disable_otp_email') }}" method="post" name="disable_otp_email">
|
||||||
|
<input type="hidden" name="token" value="{{ csrf_token('otp') }}" />
|
||||||
|
|
||||||
|
<button class="waves-effect waves-light btn red" type="submit">Disable</button>
|
||||||
|
</form>
|
||||||
|
{% endif %}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>{{ 'config.form_user.two_factor.googleTwoFactor_label'|trans }}</td>
|
||||||
|
<td>{% if app.user.isGoogleTwoFactor %}<b>{{ 'config.form_user.two_factor.state_enabled'|trans }}</b>{% else %}{{ 'config.form_user.two_factor.state_disabled'|trans }}{% endif %}</td>
|
||||||
|
<td>
|
||||||
|
<form action="{{ path('config_otp_app') }}" method="post" name="config_otp_app">
|
||||||
|
<input type="hidden" name="token" value="{{ csrf_token('otp') }}" />
|
||||||
|
|
||||||
|
<button class="waves-effect waves-light btn{% if app.user.isGoogleTwoFactor %} disabled{% endif %}" type="submit">{{ 'config.form_user.two_factor.action_app'|trans }}</button>
|
||||||
|
</form>
|
||||||
|
{% if app.user.isGoogleTwoFactor %}
|
||||||
|
<form action="{{ path('disable_otp_app') }}" method="post" name="disable_otp_app">
|
||||||
|
<input type="hidden" name="token" value="{{ csrf_token('otp') }}" />
|
||||||
|
|
||||||
|
<button class="waves-effect waves-light btn red" type="submit">Disable</button>
|
||||||
|
</form>
|
||||||
|
{% endif %}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="set4" class="col s12">
|
<div id="set4" class="col s12">
|
||||||
|
|
|
@ -40,6 +40,7 @@
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|
||||||
<form class="form" action="{{ path("config_otp_app_check") }}" method="post">
|
<form class="form" action="{{ path("config_otp_app_check") }}" method="post">
|
||||||
|
<input type="hidden" name="token" value="{{ csrf_token('otp') }}" />
|
||||||
<div class="card-content">
|
<div class="card-content">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="input-field col s12">
|
<div class="input-field col s12">
|
||||||
|
@ -49,9 +50,6 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="card-action">
|
<div class="card-action">
|
||||||
<a href="{{ path('config_otp_app_cancel') }}" class="waves-effect waves-light grey btn">
|
|
||||||
{{ 'config.otp.app.cancel'|trans }}
|
|
||||||
</a>
|
|
||||||
<button class="btn waves-effect waves-light" type="submit" name="send">
|
<button class="btn waves-effect waves-light" type="submit" name="send">
|
||||||
{{ 'config.otp.app.enable'|trans }}
|
{{ 'config.otp.app.enable'|trans }}
|
||||||
<i class="material-icons right">send</i>
|
<i class="material-icons right">send</i>
|
||||||
|
|
|
@ -1,3 +1,3 @@
|
||||||
<div class="entry-checkbox">
|
<label class="entry-checkbox">
|
||||||
<input type="checkbox" class="entry-checkbox-input" data-js="entry-checkbox" name="entry-checkbox[]" value="{{ entry.id }}" />
|
<input type="checkbox" class="entry-checkbox-input" data-js="entry-checkbox" name="entry-checkbox[]" value="{{ entry.id }}" />
|
||||||
</div>
|
</label>
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<div class="card entry-card{% if currentRoute in routes and entry.isArchived %} archived{% endif %}">
|
<div class="card entry-card{% if currentRoute in routes and entry.isArchived %} archived{% endif %}">
|
||||||
|
{% include "@WallabagCore/Entry/Card/_mass_checkbox.html.twig" with {'entry': entry} only %}
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<div class="{% if app.user.config.displayThumbnails %}card-image{% endif %} waves-effect waves-block waves-light">
|
<div class="{% if app.user.config.displayThumbnails %}card-image{% endif %} waves-effect waves-block waves-light">
|
||||||
{% include "@WallabagCore/Entry/Card/_mass_checkbox.html.twig" with {'entry': entry} only %}
|
|
||||||
<ul class="card-entry-labels">
|
<ul class="card-entry-labels">
|
||||||
{% for tag in entry.tags|slice(0, 3) %}
|
{% for tag in entry.tags|slice(0, 3) %}
|
||||||
<li title="{{ tag.label }}"><a href="{{ path('tag_entries', {'slug': tag.slug}) }}">{{ tag.label }}</a></li>
|
<li title="{{ tag.label }}"><a href="{{ path('tag_entries', {'slug': tag.slug}) }}">{{ tag.label }}</a></li>
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
<form name="tag" method="post" action="{{ path('new_tag', {'entry': entry.id}) }}">
|
<form class="tags-add-form" name="tag" method="post" action="{{ path('new_tag', {'entry': entry.id}) }}">
|
||||||
{% if form_errors(form) %}
|
{% if form_errors(form) %}
|
||||||
<span class="black-text">{{ form_errors(form) }}</span>
|
<span class="black-text">{{ form_errors(form) }}</span>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
@ -9,6 +9,6 @@
|
||||||
|
|
||||||
{{ form_widget(form.label, {'attr': {'autocomplete': 'off'}}) }}
|
{{ form_widget(form.label, {'attr': {'autocomplete': 'off'}}) }}
|
||||||
|
|
||||||
{{ form_widget(form.add, {'attr': {'class': 'btn waves-effect waves-light hide-on-large-only'}}) }}
|
{{ form_widget(form.add, {'attr': {'class': 'btn waves-effect waves-light tags-add-form-submit'}}) }}
|
||||||
{{ form_widget(form._token) }}
|
{{ form_widget(form._token) }}
|
||||||
</form>
|
</form>
|
||||||
|
|
|
@ -1143,14 +1143,13 @@ class ConfigControllerTest extends WallabagCoreTestCase
|
||||||
$this->logInAs('admin');
|
$this->logInAs('admin');
|
||||||
$client = $this->getTestClient();
|
$client = $this->getTestClient();
|
||||||
|
|
||||||
$crawler = $client->request('GET', '/config/otp/email');
|
$crawler = $client->request('GET', '/config');
|
||||||
|
|
||||||
|
$form = $crawler->filter('form[name=config_otp_email]')->form();
|
||||||
|
$client->submit($form);
|
||||||
|
|
||||||
$this->assertSame(302, $client->getResponse()->getStatusCode());
|
$this->assertSame(302, $client->getResponse()->getStatusCode());
|
||||||
|
$this->assertStringContainsString('flashes.config.notice.otp_enabled', $client->getContainer()->get(SessionInterface::class)->getFlashBag()->get('notice')[0]);
|
||||||
$crawler = $client->followRedirect();
|
|
||||||
|
|
||||||
$this->assertGreaterThan(1, $alert = $crawler->filter('body')->extract(['_text']));
|
|
||||||
$this->assertStringContainsString('flashes.config.notice.otp_enabled', $alert[0]);
|
|
||||||
|
|
||||||
// restore user
|
// restore user
|
||||||
$em = $this->getEntityManager();
|
$em = $this->getEntityManager();
|
||||||
|
@ -1170,14 +1169,23 @@ class ConfigControllerTest extends WallabagCoreTestCase
|
||||||
$this->logInAs('admin');
|
$this->logInAs('admin');
|
||||||
$client = $this->getTestClient();
|
$client = $this->getTestClient();
|
||||||
|
|
||||||
$crawler = $client->request('GET', '/config/otp/email/disable');
|
$em = $this->getEntityManager();
|
||||||
|
$user = $em
|
||||||
|
->getRepository(User::class)
|
||||||
|
->findOneByUsername('admin');
|
||||||
|
|
||||||
|
$user->setEmailTwoFactor(true);
|
||||||
|
$em->persist($user);
|
||||||
|
$em->flush();
|
||||||
|
|
||||||
|
$crawler = $client->request('GET', '/config');
|
||||||
|
|
||||||
|
$form = $crawler->filter('form[name=disable_otp_email]')->form();
|
||||||
|
$client->submit($form);
|
||||||
|
|
||||||
$this->assertSame(302, $client->getResponse()->getStatusCode());
|
$this->assertSame(302, $client->getResponse()->getStatusCode());
|
||||||
|
|
||||||
$crawler = $client->followRedirect();
|
$this->assertStringContainsString('flashes.config.notice.otp_disabled', $client->getContainer()->get(SessionInterface::class)->getFlashBag()->get('notice')[0]);
|
||||||
|
|
||||||
$this->assertGreaterThan(1, $alert = $crawler->filter('body')->extract(['_text']));
|
|
||||||
$this->assertStringContainsString('flashes.config.notice.otp_disabled', $alert[0]);
|
|
||||||
|
|
||||||
// restore user
|
// restore user
|
||||||
$em = $this->getEntityManager();
|
$em = $this->getEntityManager();
|
||||||
|
@ -1193,7 +1201,10 @@ class ConfigControllerTest extends WallabagCoreTestCase
|
||||||
$this->logInAs('admin');
|
$this->logInAs('admin');
|
||||||
$client = $this->getTestClient();
|
$client = $this->getTestClient();
|
||||||
|
|
||||||
$crawler = $client->request('GET', '/config/otp/app');
|
$crawler = $client->request('GET', '/config');
|
||||||
|
|
||||||
|
$form = $crawler->filter('form[name=config_otp_app]')->form();
|
||||||
|
$client->submit($form);
|
||||||
|
|
||||||
$this->assertSame(200, $client->getResponse()->getStatusCode());
|
$this->assertSame(200, $client->getResponse()->getStatusCode());
|
||||||
|
|
||||||
|
@ -1212,49 +1223,28 @@ class ConfigControllerTest extends WallabagCoreTestCase
|
||||||
$em->flush();
|
$em->flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testUserEnable2faGoogleCancel()
|
|
||||||
{
|
|
||||||
$this->logInAs('admin');
|
|
||||||
$client = $this->getTestClient();
|
|
||||||
|
|
||||||
$crawler = $client->request('GET', '/config/otp/app');
|
|
||||||
|
|
||||||
$this->assertSame(200, $client->getResponse()->getStatusCode());
|
|
||||||
|
|
||||||
// restore user
|
|
||||||
$em = $this->getEntityManager();
|
|
||||||
$user = $em
|
|
||||||
->getRepository(User::class)
|
|
||||||
->findOneByUsername('admin');
|
|
||||||
|
|
||||||
$this->assertTrue($user->isGoogleTwoFactor());
|
|
||||||
$this->assertGreaterThan(0, $user->getBackupCodes());
|
|
||||||
|
|
||||||
$crawler = $client->request('GET', '/config/otp/app/cancel');
|
|
||||||
|
|
||||||
$this->assertSame(302, $client->getResponse()->getStatusCode());
|
|
||||||
|
|
||||||
$user = $em
|
|
||||||
->getRepository(User::class)
|
|
||||||
->findOneByUsername('admin');
|
|
||||||
|
|
||||||
$this->assertFalse($user->isGoogleTwoFactor());
|
|
||||||
$this->assertEmpty($user->getBackupCodes());
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testUserDisable2faGoogle()
|
public function testUserDisable2faGoogle()
|
||||||
{
|
{
|
||||||
$this->logInAs('admin');
|
$this->logInAs('admin');
|
||||||
$client = $this->getTestClient();
|
$client = $this->getTestClient();
|
||||||
|
|
||||||
$crawler = $client->request('GET', '/config/otp/app/disable');
|
$em = $this->getEntityManager();
|
||||||
|
$user = $em
|
||||||
|
->getRepository(User::class)
|
||||||
|
->findOneByUsername('admin');
|
||||||
|
|
||||||
|
$user->setGoogleAuthenticatorSecret('Google2FA');
|
||||||
|
$em->persist($user);
|
||||||
|
$em->flush();
|
||||||
|
|
||||||
|
$crawler = $client->request('GET', '/config');
|
||||||
|
|
||||||
|
$form = $crawler->filter('form[name=disable_otp_app]')->form();
|
||||||
|
$client->submit($form);
|
||||||
|
|
||||||
$this->assertSame(302, $client->getResponse()->getStatusCode());
|
$this->assertSame(302, $client->getResponse()->getStatusCode());
|
||||||
|
|
||||||
$crawler = $client->followRedirect();
|
$this->assertStringContainsString('flashes.config.notice.otp_disabled', $client->getContainer()->get(SessionInterface::class)->getFlashBag()->get('notice')[0]);
|
||||||
|
|
||||||
$this->assertGreaterThan(1, $alert = $crawler->filter('body')->extract(['_text']));
|
|
||||||
$this->assertStringContainsString('flashes.config.notice.otp_disabled', $alert[0]);
|
|
||||||
|
|
||||||
// restore user
|
// restore user
|
||||||
$em = $this->getEntityManager();
|
$em = $this->getEntityManager();
|
||||||
|
|
Loading…
Reference in a new issue