BackupCodesProvider.php 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139
  1. <?php
  2. declare(strict_types=1);
  3. /**
  4. * SPDX-FileCopyrightText: 2016 Nextcloud GmbH and Nextcloud contributors
  5. * SPDX-License-Identifier: AGPL-3.0-or-later
  6. */
  7. namespace OCA\TwoFactorBackupCodes\Provider;
  8. use OC\App\AppManager;
  9. use OCA\TwoFactorBackupCodes\Service\BackupCodeStorage;
  10. use OCA\TwoFactorBackupCodes\Settings\Personal;
  11. use OCP\Authentication\TwoFactorAuth\IDeactivatableByAdmin;
  12. use OCP\Authentication\TwoFactorAuth\IPersonalProviderSettings;
  13. use OCP\Authentication\TwoFactorAuth\IProvidesPersonalSettings;
  14. use OCP\IInitialStateService;
  15. use OCP\IL10N;
  16. use OCP\IUser;
  17. use OCP\Template;
  18. class BackupCodesProvider implements IDeactivatableByAdmin, IProvidesPersonalSettings {
  19. /** @var AppManager */
  20. private $appManager;
  21. /**
  22. * @param string $appName
  23. * @param BackupCodeStorage $storage
  24. * @param IL10N $l10n
  25. * @param AppManager $appManager
  26. */
  27. public function __construct(
  28. private string $appName,
  29. private BackupCodeStorage $storage,
  30. private IL10N $l10n,
  31. AppManager $appManager,
  32. private IInitialStateService $initialStateService,
  33. ) {
  34. $this->appManager = $appManager;
  35. }
  36. /**
  37. * Get unique identifier of this 2FA provider
  38. *
  39. * @return string
  40. */
  41. public function getId(): string {
  42. return 'backup_codes';
  43. }
  44. /**
  45. * Get the display name for selecting the 2FA provider
  46. *
  47. * @return string
  48. */
  49. public function getDisplayName(): string {
  50. return $this->l10n->t('Backup code');
  51. }
  52. /**
  53. * Get the description for selecting the 2FA provider
  54. *
  55. * @return string
  56. */
  57. public function getDescription(): string {
  58. return $this->l10n->t('Use backup code');
  59. }
  60. /**
  61. * Get the template for rending the 2FA provider view
  62. *
  63. * @param IUser $user
  64. * @return Template
  65. */
  66. public function getTemplate(IUser $user): Template {
  67. return new Template('twofactor_backupcodes', 'challenge');
  68. }
  69. /**
  70. * Verify the given challenge
  71. *
  72. * @param IUser $user
  73. * @param string $challenge
  74. * @return bool
  75. */
  76. public function verifyChallenge(IUser $user, string $challenge): bool {
  77. return $this->storage->validateCode($user, $challenge);
  78. }
  79. /**
  80. * Decides whether 2FA is enabled for the given user
  81. *
  82. * @param IUser $user
  83. * @return boolean
  84. */
  85. public function isTwoFactorAuthEnabledForUser(IUser $user): bool {
  86. return $this->storage->hasBackupCodes($user);
  87. }
  88. /**
  89. * Determine whether backup codes should be active or not
  90. *
  91. * Backup codes only make sense if at least one 2FA provider is active,
  92. * hence this method checks all enabled apps on whether they provide 2FA
  93. * functionality or not. If there's at least one app, backup codes are
  94. * enabled on the personal settings page.
  95. *
  96. * @param IUser $user
  97. * @return boolean
  98. */
  99. public function isActive(IUser $user): bool {
  100. $appIds = array_filter($this->appManager->getEnabledAppsForUser($user), function ($appId) {
  101. return $appId !== $this->appName;
  102. });
  103. foreach ($appIds as $appId) {
  104. $info = $this->appManager->getAppInfo($appId);
  105. if (isset($info['two-factor-providers']) && count($info['two-factor-providers']) > 0) {
  106. return true;
  107. }
  108. }
  109. return false;
  110. }
  111. /**
  112. * @param IUser $user
  113. *
  114. * @return IPersonalProviderSettings
  115. */
  116. public function getPersonalSettings(IUser $user): IPersonalProviderSettings {
  117. $state = $this->storage->getBackupCodesState($user);
  118. $this->initialStateService->provideInitialState($this->appName, 'state', $state);
  119. return new Personal();
  120. }
  121. public function disableFor(IUser $user) {
  122. $this->storage->deleteCodes($user);
  123. }
  124. }