use JMS\Serializer\Annotation\Accessor;
use JMS\Serializer\Annotation\Groups;
use JMS\Serializer\Annotation\XmlRoot;
-use Scheb\TwoFactorBundle\Model\Email\TwoFactorInterface;
-use Scheb\TwoFactorBundle\Model\TrustedComputerInterface;
+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;
use Symfony\Component\Security\Core\User\UserInterface;
use Wallabag\ApiBundle\Entity\Client;
use Wallabag\CoreBundle\Entity\Config;
use Wallabag\CoreBundle\Entity\Entry;
+use Wallabag\CoreBundle\Helper\EntityTimestampsTrait;
/**
* User.
* @UniqueEntity("email")
* @UniqueEntity("username")
*/
-class User extends BaseUser implements TwoFactorInterface, TrustedComputerInterface
+class User extends BaseUser implements EmailTwoFactorInterface, GoogleTwoFactorInterface, BackupCodeInterface
{
+ use EntityTimestampsTrait;
+
/** @Serializer\XmlAttribute */
/**
* @var int
*/
protected $config;
+ /**
+ * @var ArrayCollection
+ *
+ * @ORM\OneToMany(targetEntity="Wallabag\CoreBundle\Entity\SiteCredential", mappedBy="user", cascade={"remove"})
+ */
+ protected $siteCredentials;
+
/**
* @var ArrayCollection
*
private $authCode;
/**
- * @var bool
- *
- * @ORM\Column(type="boolean")
+ * @ORM\Column(name="googleAuthenticatorSecret", type="string", nullable=true)
*/
- private $twoFactorAuthentication = false;
+ private $googleAuthenticatorSecret;
/**
* @ORM\Column(type="json_array", nullable=true)
*/
- private $trusted;
+ private $backupCodes;
+
+ /**
+ * @var bool
+ *
+ * @ORM\Column(type="boolean")
+ */
+ private $emailTwoFactor = false;
public function __construct()
{
$this->roles = ['ROLE_USER'];
}
- /**
- * @ORM\PrePersist
- * @ORM\PreUpdate
- */
- public function timestamps()
- {
- if (null === $this->createdAt) {
- $this->createdAt = new \DateTime();
- }
-
- $this->updatedAt = new \DateTime();
- }
-
/**
* Set name.
*
/**
* @return bool
*/
- public function isTwoFactorAuthentication()
+ public function isEmailTwoFactor()
+ {
+ return $this->emailTwoFactor;
+ }
+
+ /**
+ * @param bool $emailTwoFactor
+ */
+ public function setEmailTwoFactor($emailTwoFactor)
{
- return $this->twoFactorAuthentication;
+ $this->emailTwoFactor = $emailTwoFactor;
}
/**
- * @param bool $twoFactorAuthentication
+ * Used in the user config form to be "like" the email option.
*/
- public function setTwoFactorAuthentication($twoFactorAuthentication)
+ public function isGoogleTwoFactor()
{
- $this->twoFactorAuthentication = $twoFactorAuthentication;
+ return $this->isGoogleAuthenticatorEnabled();
}
- public function isEmailAuthEnabled()
+ /**
+ * {@inheritdoc}
+ */
+ public function isEmailAuthEnabled(): bool
{
- return $this->twoFactorAuthentication;
+ return $this->emailTwoFactor;
}
- public function getEmailAuthCode()
+ /**
+ * {@inheritdoc}
+ */
+ public function getEmailAuthCode(): string
{
return $this->authCode;
}
- public function setEmailAuthCode($authCode)
+ /**
+ * {@inheritdoc}
+ */
+ public function setEmailAuthCode(string $authCode): void
{
$this->authCode = $authCode;
}
- public function addTrustedComputer($token, \DateTime $validUntil)
+ /**
+ * {@inheritdoc}
+ */
+ public function getEmailAuthRecipient(): string
{
- $this->trusted[$token] = $validUntil->format('r');
+ return $this->email;
}
- public function isTrustedComputer($token)
+ /**
+ * {@inheritdoc}
+ */
+ public function isGoogleAuthenticatorEnabled(): bool
{
- if (isset($this->trusted[$token])) {
- $now = new \DateTime();
- $validUntil = new \DateTime($this->trusted[$token]);
+ return $this->googleAuthenticatorSecret ? true : false;
+ }
- return $now < $validUntil;
- }
+ /**
+ * {@inheritdoc}
+ */
+ public function getGoogleAuthenticatorUsername(): string
+ {
+ return $this->username;
+ }
- return false;
+ /**
+ * {@inheritdoc}
+ */
+ public function getGoogleAuthenticatorSecret(): string
+ {
+ return $this->googleAuthenticatorSecret;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function setGoogleAuthenticatorSecret(?string $googleAuthenticatorSecret): void
+ {
+ $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 false === $this->findBackupCode($code) ? false : true;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function invalidateBackupCode(string $code): void
+ {
+ $key = $this->findBackupCode($code);
+
+ if (false !== $key) {
+ unset($this->backupCodes[$key]);
+ }
}
/**
return $this->clients->first();
}
}
+
+ /**
+ * Try to find a backup code from the list of backup codes of the current user.
+ *
+ * @param string $code Given code from the user
+ *
+ * @return string|false
+ */
+ private function findBackupCode(string $code)
+ {
+ foreach ($this->backupCodes as $key => $backupCode) {
+ // backup code are hashed using `password_hash`
+ // see ConfigController->otpAppAction
+ if (password_verify($code, $backupCode)) {
+ return $key;
+ }
+ }
+
+ return false;
+ }
}