diff --git a/apps/settings/lib/ConfigLexicon.php b/apps/settings/lib/ConfigLexicon.php
index 754f2a4ccad..415ec2f487b 100644
--- a/apps/settings/lib/ConfigLexicon.php
+++ b/apps/settings/lib/ConfigLexicon.php
@@ -20,6 +20,7 @@ use OCP\Config\ValueType;
* Please Add & Manage your Config Keys in that file and keep the Lexicon up to date!
*/
class ConfigLexicon implements ILexicon {
+ public const LOGIN_QRCODE_ONETIME = 'qrcode_onetime';
public const USER_SETTINGS_EMAIL = 'email';
public const USER_LIST_SHOW_STORAGE_PATH = 'user_list_show_storage_path';
public const USER_LIST_SHOW_USER_BACKEND = 'user_list_show_user_backend';
@@ -33,7 +34,9 @@ class ConfigLexicon implements ILexicon {
}
public function getAppConfigs(): array {
- return [];
+ return [
+ new Entry(key: self::LOGIN_QRCODE_ONETIME, type: ValueType::BOOL, defaultRaw: false, definition: 'Use onetime QR codes for app passwords', note: 'Limits compatibility for mobile apps to versions released in 2026 or later'),
+ ];
}
public function getUserConfigs(): array {
diff --git a/apps/settings/lib/Controller/AuthSettingsController.php b/apps/settings/lib/Controller/AuthSettingsController.php
index 223537e1956..4873592d8a6 100644
--- a/apps/settings/lib/Controller/AuthSettingsController.php
+++ b/apps/settings/lib/Controller/AuthSettingsController.php
@@ -14,12 +14,14 @@ use OC\Authentication\Token\INamedToken;
use OC\Authentication\Token\IProvider;
use OC\Authentication\Token\RemoteWipe;
use OCA\Settings\Activity\Provider;
+use OCA\Settings\ConfigLexicon;
use OCP\Activity\IManager;
use OCP\AppFramework\Controller;
use OCP\AppFramework\Http;
use OCP\AppFramework\Http\Attribute\NoAdminRequired;
use OCP\AppFramework\Http\Attribute\PasswordConfirmationRequired;
use OCP\AppFramework\Http\JSONResponse;
+use OCP\AppFramework\Services\IAppConfig;
use OCP\Authentication\Exceptions\ExpiredTokenException;
use OCP\Authentication\Exceptions\InvalidTokenException;
use OCP\Authentication\Exceptions\WipeTokenException;
@@ -32,49 +34,31 @@ use OCP\Session\Exceptions\SessionNotAvailableException;
use Psr\Log\LoggerInterface;
class AuthSettingsController extends Controller {
- /** @var IProvider */
- private $tokenProvider;
- /** @var RemoteWipe */
- private $remoteWipe;
-
- /**
- * @param string $appName
- * @param IRequest $request
- * @param IProvider $tokenProvider
- * @param ISession $session
- * @param ISecureRandom $random
- * @param string|null $userId
- * @param IUserSession $userSession
- * @param IManager $activityManager
- * @param RemoteWipe $remoteWipe
- * @param LoggerInterface $logger
- */
public function __construct(
string $appName,
IRequest $request,
- IProvider $tokenProvider,
+ private IProvider $tokenProvider,
private ISession $session,
private ISecureRandom $random,
private ?string $userId,
private IUserSession $userSession,
private IManager $activityManager,
- RemoteWipe $remoteWipe,
+ private IAppConfig $appConfig,
+ private RemoteWipe $remoteWipe,
private LoggerInterface $logger,
) {
parent::__construct($appName, $request);
- $this->tokenProvider = $tokenProvider;
- $this->remoteWipe = $remoteWipe;
}
/**
* @NoSubAdminRequired
*
- * @param bool $oneTime If set to true, the returned token can only be used to get the actual app password a single time
+ * @param bool $qrcodeLogin If set to true, the returned token could be (depending on server settings) a onetime password, that can only be used to get the actual app password a single time
*/
#[NoAdminRequired]
#[PasswordConfirmationRequired]
- public function create(string $name = '', bool $oneTime = false): JSONResponse {
+ public function create(string $name = '', bool $qrcodeLogin = false): JSONResponse {
if ($this->checkAppToken()) {
return $this->getServiceNotAvailableResponse();
}
@@ -100,10 +84,16 @@ class AuthSettingsController extends Controller {
return $this->getServiceNotAvailableResponse();
}
- if ($oneTime) {
- $name = 'One time login';
- $type = IToken::ONETIME_TOKEN;
- $scope = [];
+ if ($qrcodeLogin) {
+ if ($this->appConfig->getAppValueBool(ConfigLexicon::LOGIN_QRCODE_ONETIME)) {
+ $name = 'One time login';
+ $type = IToken::ONETIME_TOKEN;
+ $scope = [];
+ } else {
+ $name = 'QR Code login';
+ $type = IToken::PERMANENT_TOKEN;
+ $scope = null;
+ }
} elseif ($name === '') {
// No name is only allowed for one time logins
return $this->getServiceNotAvailableResponse();
diff --git a/core/src/components/AccountMenu/AccountMenuProfileEntry.vue b/core/src/components/AccountMenu/AccountMenuProfileEntry.vue
index 4e6eb6a78a1..daf4dee17e3 100644
--- a/core/src/components/AccountMenu/AccountMenuProfileEntry.vue
+++ b/core/src/components/AccountMenu/AccountMenuProfileEntry.vue
@@ -113,7 +113,7 @@ export default defineComponent({
async handleQrCodeClick() {
await confirmPassword()
- const { data } = await axios.post