Add backup codes

This commit is contained in:
Jeremy Benoist 2018-12-03 06:51:06 +01:00
parent 6e4fc956ab
commit dfd0a7bc5f
No known key found for this signature in database
GPG key ID: BCA73962457ACC3C
21 changed files with 97 additions and 15 deletions

View file

@ -12,11 +12,29 @@ final class Version20181202073750 extends WallabagMigration
{
public function up(Schema $schema): void
{
$this->addSql('ALTER TABLE ' . $this->getTable('user') . ' ADD googleAuthenticatorSecret VARCHAR(191) DEFAULT NULL, CHANGE twoFactorAuthentication emailTwoFactor BOOLEAN NOT NULL, DROP trusted');
$tableName = $this->getTable('annotation');
switch ($this->connection->getDatabasePlatform()->getName()) {
case 'sqlite':
break;
case 'mysql':
$this->addSql('ALTER TABLE ' . $this->getTable('user') . ' ADD googleAuthenticatorSecret VARCHAR(191) DEFAULT NULL, CHANGE twoFactorAuthentication emailTwoFactor BOOLEAN NOT NULL, DROP trusted, ADD backupCodes LONGTEXT DEFAULT NULL COMMENT \'(DC2Type:json_array)\'');
break;
case 'postgresql':
break;
}
}
public function down(Schema $schema): void
{
$this->addSql('ALTER TABLE `' . $this->getTable('user') . '` DROP googleAuthenticatorSecret, CHANGE emailtwofactor twoFactorAuthentication BOOLEAN NOT NULL, ADD trusted TEXT DEFAULT NULL');
switch ($this->connection->getDatabasePlatform()->getName()) {
case 'sqlite':
break;
case 'mysql':
$this->addSql('ALTER TABLE `' . $this->getTable('user') . '` DROP googleAuthenticatorSecret, CHANGE emailtwofactor twoFactorAuthentication BOOLEAN NOT NULL, ADD trusted TEXT DEFAULT NULL, DROP backupCodes');
break;
case 'postgresql':
break;
}
}
}

View file

@ -203,6 +203,9 @@ scheb_two_factor:
cookie_name: wllbg_trusted_computer
lifetime: 2592000
backup_codes:
enabled: "%twofactor_auth%"
google:
enabled: "%twofactor_auth%"
template: WallabagUserBundle:Authentication:form.html.twig

View file

@ -87,7 +87,8 @@
"friendsofsymfony/jsrouting-bundle": "^2.2",
"bdunogier/guzzle-site-authenticator": "^1.0.0",
"defuse/php-encryption": "^2.1",
"html2text/html2text": "^4.1"
"html2text/html2text": "^4.1",
"pragmarx/recovery": "^0.1.0"
},
"require-dev": {
"doctrine/doctrine-fixtures-bundle": "~3.0",

View file

@ -2,6 +2,7 @@
namespace Wallabag\CoreBundle\Controller;
use PragmaRX\Recovery\Recovery as BackupCodes;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\RedirectResponse;
@ -93,10 +94,12 @@ class ConfigController extends Controller
$user->setGoogleAuthenticatorSecret($secret);
$user->setEmailTwoFactor(false);
$user->setBackupCodes((new BackupCodes())->toArray());
$this->addFlash('OtpQrCode', $this->get('scheb_two_factor.security.google_authenticator')->getQRContent($user));
} elseif (false === $userForm->get('googleTwoFactor')->getData() && true === $user->isGoogleAuthenticatorEnabled()) {
$user->setGoogleAuthenticatorSecret(null);
$user->setBackupCodes(null);
}
}

View file

@ -107,6 +107,7 @@ config:
# two_factor_code_description_1: You just enabled the OTP two factor authentication, open your OTP app and use that code to get a one time password. It'll disapear after a page reload.
# two_factor_code_description_2: 'You can scan that QR Code with your app:'
# two_factor_code_description_3: 'Or use that code:'
# two_factor_code_description_4: 'Also, save these backup codes in a safe place, you can use them in case you lose access to your OTP app:'
delete:
# title: Delete my account (a.k.a danger zone)
# description: If you remove your account, ALL your articles, ALL your tags, ALL your annotations and your account will be PERMANENTLY removed (it can't be UNDONE). You'll then be logged out.

View file

@ -107,6 +107,7 @@ config:
# two_factor_code_description_1: You just enabled the OTP two factor authentication, open your OTP app and use that code to get a one time password. It'll disapear after a page reload.
# two_factor_code_description_2: 'You can scan that QR Code with your app:'
# two_factor_code_description_3: 'Or use that code:'
# two_factor_code_description_4: 'Also, save these backup codes in a safe place, you can use them in case you lose access to your OTP app:'
delete:
title: 'Lösche mein Konto (a.k.a Gefahrenzone)'
description: 'Wenn du dein Konto löschst, werden ALL deine Artikel, ALL deine Tags, ALL deine Anmerkungen und dein Konto dauerhaft gelöscht (kann NICHT RÜCKGÄNGIG gemacht werden). Du wirst anschließend ausgeloggt.'

View file

@ -107,6 +107,7 @@ config:
two_factor_code_description_1: You just enabled the OTP two factor authentication, open your OTP app and use that code to get a one time password. It'll disapear after a page reload.
two_factor_code_description_2: 'You can scan that QR Code with your app:'
two_factor_code_description_3: 'Or use that code:'
two_factor_code_description_4: 'Also, save these backup codes in a safe place, you can use them in case you lose access to your OTP app:'
delete:
title: Delete my account (a.k.a danger zone)
description: If you remove your account, ALL your articles, ALL your tags, ALL your annotations and your account will be PERMANENTLY removed (it can't be UNDONE). You'll then be logged out.

View file

@ -107,6 +107,7 @@ config:
# two_factor_code_description_1: You just enabled the OTP two factor authentication, open your OTP app and use that code to get a one time password. It'll disapear after a page reload.
# two_factor_code_description_2: 'You can scan that QR Code with your app:'
# two_factor_code_description_3: 'Or use that code:'
# two_factor_code_description_4: 'Also, save these backup codes in a safe place, you can use them in case you lose access to your OTP app:'
delete:
title: Eliminar mi cuenta (Zona peligrosa)
description: Si eliminas tu cuenta, TODOS tus artículos, TODAS tus etiquetas, TODAS tus anotaciones y tu cuenta serán eliminadas de forma PERMANENTE (no se puede deshacer). Después serás desconectado.

View file

@ -107,6 +107,7 @@ config:
# two_factor_code_description_1: You just enabled the OTP two factor authentication, open your OTP app and use that code to get a one time password. It'll disapear after a page reload.
# two_factor_code_description_2: 'You can scan that QR Code with your app:'
# two_factor_code_description_3: 'Or use that code:'
# two_factor_code_description_4: 'Also, save these backup codes in a safe place, you can use them in case you lose access to your OTP app:'
delete:
# title: Delete my account (a.k.a danger zone)
# description: If you remove your account, ALL your articles, ALL your tags, ALL your annotations and your account will be PERMANENTLY removed (it can't be UNDONE). You'll then be logged out.

View file

@ -107,6 +107,7 @@ config:
two_factor_code_description_1: Vous venez dactiver lauthentification double-facteur, ouvrez votre application OTP pour configurer la génération du mot de passe à usage unique. Ces informations disparaîtront après un rechargement de la page.
two_factor_code_description_2: 'Vous pouvez scanner le QR code avec votre application :'
two_factor_code_description_3: 'Ou utiliser le code suivant :'
two_factor_code_description_4: 'Noubliez pas de sauvegarder ces codes de secours dans un endroit sûr, vous pourrez les utiliser si vous ne pouvez plus accéder à votre application OTP :'
delete:
title: "Supprimer mon compte (attention danger !)"
description: "Si vous confirmez la suppression de votre compte, TOUS les articles, TOUS les tags, TOUTES les annotations et votre compte seront DÉFINITIVEMENT supprimé (cest IRRÉVERSIBLE). Vous serez ensuite déconnecté."

View file

@ -107,6 +107,7 @@ config:
# two_factor_code_description_1: You just enabled the OTP two factor authentication, open your OTP app and use that code to get a one time password. It'll disapear after a page reload.
# two_factor_code_description_2: 'You can scan that QR Code with your app:'
# two_factor_code_description_3: 'Or use that code:'
# two_factor_code_description_4: 'Also, save these backup codes in a safe place, you can use them in case you lose access to your OTP app:'
delete:
title: Cancella il mio account (zona pericolosa)
description: Rimuovendo il tuo account, TUTTI i tuoi articoli, TUTTE le tue etichette, TUTTE le tue annotazioni ed il tuo account verranno rimossi PERMANENTEMENTE (impossibile da ANNULLARE). Verrai poi disconnesso.

View file

@ -107,6 +107,7 @@ config:
# two_factor_code_description_1: You just enabled the OTP two factor authentication, open your OTP app and use that code to get a one time password. It'll disapear after a page reload.
# two_factor_code_description_2: 'You can scan that QR Code with your app:'
# two_factor_code_description_3: 'Or use that code:'
# two_factor_code_description_4: 'Also, save these backup codes in a safe place, you can use them in case you lose access to your OTP app:'
delete:
title: Suprimir mon compte (Mèfi zòna perilhosa)
description: Se confirmatz la supression de vòstre compte, TOTES vòstres articles, TOTAS vòstras etiquetas, TOTAS vòstras anotacions e vòstre compte seràn suprimits per totjorn. E aquò es IRREVERSIBLE. Puèi seretz desconnectat.

View file

@ -107,6 +107,7 @@ config:
# two_factor_code_description_1: You just enabled the OTP two factor authentication, open your OTP app and use that code to get a one time password. It'll disapear after a page reload.
# two_factor_code_description_2: 'You can scan that QR Code with your app:'
# two_factor_code_description_3: 'Or use that code:'
# two_factor_code_description_4: 'Also, save these backup codes in a safe place, you can use them in case you lose access to your OTP app:'
delete:
title: Usuń moje konto (niebezpieczna strefa !)
description: Jeżeli usuniesz swoje konto, wszystkie twoje artykuły, tagi, adnotacje, oraz konto zostaną trwale usunięte (operacja jest NIEODWRACALNA). Następnie zostaniesz wylogowany.

View file

@ -107,6 +107,7 @@ config:
# two_factor_code_description_1: You just enabled the OTP two factor authentication, open your OTP app and use that code to get a one time password. It'll disapear after a page reload.
# two_factor_code_description_2: 'You can scan that QR Code with your app:'
# two_factor_code_description_3: 'Or use that code:'
# two_factor_code_description_4: 'Also, save these backup codes in a safe place, you can use them in case you lose access to your OTP app:'
delete:
# title: Delete my account (a.k.a danger zone)
# description: If you remove your account, ALL your articles, ALL your tags, ALL your annotations and your account will be PERMANENTLY removed (it can't be UNDONE). You'll then be logged out.

View file

@ -107,6 +107,7 @@ config:
# two_factor_code_description_1: You just enabled the OTP two factor authentication, open your OTP app and use that code to get a one time password. It'll disapear after a page reload.
# two_factor_code_description_2: 'You can scan that QR Code with your app:'
# two_factor_code_description_3: 'Or use that code:'
# two_factor_code_description_4: 'Also, save these backup codes in a safe place, you can use them in case you lose access to your OTP app:'
delete:
# title: Delete my account (a.k.a danger zone)
# description: If you remove your account, ALL your articles, ALL your tags, ALL your annotations and your account will be PERMANENTLY removed (it can't be UNDONE). You'll then be logged out.

View file

@ -104,6 +104,7 @@ config:
# two_factor_code_description_1: You just enabled the OTP two factor authentication, open your OTP app and use that code to get a one time password. It'll disapear after a page reload.
# two_factor_code_description_2: 'You can scan that QR Code with your app:'
# two_factor_code_description_3: 'Or use that code:'
# two_factor_code_description_4: 'Also, save these backup codes in a safe place, you can use them in case you lose access to your OTP app:'
delete:
title: "Удалить мой аккаунт (или опасная зона)"
description: "Если Вы удалите ваш аккаунт, ВСЕ ваши записи, теги и другие данные, будут БЕЗВОЗВРАТНО удалены (операция не может быть отменена после). Затем Вы выйдете из системы."

View file

@ -107,6 +107,7 @@ config:
# two_factor_code_description_1: You just enabled the OTP two factor authentication, open your OTP app and use that code to get a one time password. It'll disapear after a page reload.
# two_factor_code_description_2: 'You can scan that QR Code with your app:'
# two_factor_code_description_3: 'Or use that code:'
# two_factor_code_description_4: 'Also, save these backup codes in a safe place, you can use them in case you lose access to your OTP app:'
delete:
title: ลบบัญชีของฉัน (โซนที่เป็นภัย!)
description: ถ้าคุณลบบัญชีของคุณIf , รายการทั้งหมดของคุณ, แท็กทั้งหมดของคุณ, หมายเหตุทั้งหมดของคุณและบัญชีของคุณจะถูกลบอย่างถาวร (มันไม่สามารถยกเลิกได้) คุณจะต้องลงชื่อออก

View file

@ -107,6 +107,7 @@ config:
# two_factor_code_description_1: You just enabled the OTP two factor authentication, open your OTP app and use that code to get a one time password. It'll disapear after a page reload.
# two_factor_code_description_2: 'You can scan that QR Code with your app:'
# two_factor_code_description_3: 'Or use that code:'
# two_factor_code_description_4: 'Also, save these backup codes in a safe place, you can use them in case you lose access to your OTP app:'
delete:
# title: Delete my account (a.k.a danger zone)
# description: If you remove your account, ALL your articles, ALL your tags, ALL your annotations and your account will be PERMANENTLY removed (it can't be UNDONE). You'll then be logged out.

View file

@ -187,19 +187,22 @@
</div>
{% for OtpQrCode in app.session.flashbag.get('OtpQrCode') %}
<div class="row">
You just enabled the OTP two factor authentication, open your OTP app and use that code to get a one time password.
{{ 'config.form_user.two_factor_code_description_1'|trans }}
<br/>
That code will disapear after a page reload.
{{ 'config.form_user.two_factor_code_description_2'|trans }}
<br/><br/>
<img id="2faQrcode" class="hide-on-med-and-down" />
<script>
document.getElementById('2faQrcode').src = jrQrcode.getQrBase64('{{ OtpQrCode }}');
</script>
<br/><br/>
{{ 'config.form_user.two_factor_code_description_3'|trans }}
<br/><br/>
<strong>{{ app.user.getGoogleAuthenticatorSecret }}</strong>
<br/><br/>
Or you can scan that QR Code with your app:
<br/>
<img id="2faQrcode" class="hide-on-med-and-down" />
<script>
document.getElementById('2faQrcode').src = jrQrcode.getQrBase64('{{ OtpQrCode }}');;
</script>
{{ 'config.form_user.two_factor_code_description_4'|trans }}
<br/><br/>
<strong>{{ app.user.getBackupCodes|join("\n")|nl2br }}</strong>
</div>
{% endfor %}
</fieldset>

View file

@ -112,7 +112,7 @@
<img id="androidQrcode" class="hide-on-med-and-down" />
</div>
<script>
document.getElementById('androidQrcode').src = jrQrcode.getQrBase64('wallabag://{{ app.user.username }}@{{ wallabag_url }}');;
document.getElementById('androidQrcode').src = jrQrcode.getQrBase64('wallabag://{{ app.user.username }}@{{ wallabag_url }}');
</script>
</div>
@ -220,12 +220,16 @@
<br/><br/>
<img id="2faQrcode" class="hide-on-med-and-down" />
<script>
document.getElementById('2faQrcode').src = jrQrcode.getQrBase64('{{ OtpQrCode }}');;
document.getElementById('2faQrcode').src = jrQrcode.getQrBase64('{{ OtpQrCode }}');
</script>
<br/><br/>
{{ 'config.form_user.two_factor_code_description_3'|trans }}
<br/><br/>
<strong>{{ app.user.getGoogleAuthenticatorSecret }}</strong>
<br/><br/>
{{ 'config.form_user.two_factor_code_description_4'|trans }}
<br/><br/>
<strong>{{ app.user.getBackupCodes|join("\n")|nl2br }}</strong>
</div>
{% endfor %}
{% endif %}

View file

@ -8,6 +8,7 @@ use FOS\UserBundle\Model\User as BaseUser;
use JMS\Serializer\Annotation\Accessor;
use JMS\Serializer\Annotation\Groups;
use JMS\Serializer\Annotation\XmlRoot;
use Scheb\TwoFactorBundle\Model\BackupCodeInterface;
use Scheb\TwoFactorBundle\Model\Email\TwoFactorInterface as EmailTwoFactorInterface;
use Scheb\TwoFactorBundle\Model\Google\TwoFactorInterface as GoogleTwoFactorInterface;
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
@ -28,7 +29,7 @@ use Wallabag\CoreBundle\Helper\EntityTimestampsTrait;
* @UniqueEntity("email")
* @UniqueEntity("username")
*/
class User extends BaseUser implements EmailTwoFactorInterface, GoogleTwoFactorInterface
class User extends BaseUser implements EmailTwoFactorInterface, GoogleTwoFactorInterface, BackupCodeInterface
{
use EntityTimestampsTrait;
@ -127,6 +128,11 @@ class User extends BaseUser implements EmailTwoFactorInterface, GoogleTwoFactorI
*/
private $googleAuthenticatorSecret;
/**
* @ORM\Column(type="json_array", nullable=true)
*/
private $backupCodes;
/**
* @var bool
*
@ -318,6 +324,36 @@ class User extends BaseUser implements EmailTwoFactorInterface, GoogleTwoFactorI
$this->googleAuthenticatorSecret = $googleAuthenticatorSecret;
}
public function setBackupCodes(array $codes = null)
{
$this->backupCodes = $codes;
}
public function getBackupCodes()
{
return $this->backupCodes;
}
/**
* {@inheritdoc}
*/
public function isBackupCode(string $code): bool
{
return \in_array($code, $this->backupCodes, true);
}
/**
* {@inheritdoc}
*/
public function invalidateBackupCode(string $code): void
{
$key = array_search($code, $this->backupCodes, true);
if (false !== $key) {
unset($this->backupCodes[$key]);
}
}
/**
* @param Client $client
*