Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions lib/Controller/PageController.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
use OCA\Mail\Service\ContextChat\ContextChatSettingsService;
use OCA\Mail\Service\InternalAddressService;
use OCA\Mail\Service\OutboxService;
use OCA\Mail\Service\Provisioning\Manager as ProvisioningManager;
use OCA\Mail\Service\QuickActionsService;
use OCA\Mail\Service\SmimeService;
use OCA\Viewer\Event\LoadViewer;
Expand Down Expand Up @@ -94,6 +95,7 @@ public function __construct(
private ContextChatSettingsService $contextChatSettingsService,
private ClassificationSettingsService $classificationSettingsService,
private IAppConfig $appConfig,
private ProvisioningManager $provisioningManager,
) {
parent::__construct($appName, $request);

Expand Down Expand Up @@ -226,6 +228,26 @@ public function index(): TemplateResponse {
$passwordIsUnavailable,
);

// Whether any of the user's provisioned accounts use a master password.
// Frontend skips INBOX sync for provisioned accounts when the session has
// no login password *unless* this is true (#13807, #9008, #9653).
$masterPasswordEnabled = false;
foreach ($mailAccounts as $mailAccount) {
$provisioningId = $mailAccount->getMailAccount()->getProvisioningId();
if ($provisioningId === null) {
continue;
}
$provisioning = $this->provisioningManager->getConfigById($provisioningId);
if ($provisioning !== null && $provisioning->getMasterPasswordEnabled() === true) {
$masterPasswordEnabled = true;
break;
}
}
$this->initialStateService->provideInitialState(
'master-password-enabled',
$masterPasswordEnabled,
);

$response = new TemplateResponse($this->appName, 'index');
$this->initialStateService->provideInitialState('preferences', [
'attachment-size-limit' => $this->config->getSystemValue('app.mail.attachment-size-limit', 0),
Expand Down
5 changes: 3 additions & 2 deletions src/components/Navigation.vue
Original file line number Diff line number Diff line change
Expand Up @@ -233,14 +233,15 @@ export default {
},

/**
* Disable provisioned accounts when no password is available.
* Disable provisioned accounts when no password is available and no master password is configured.
* Loading messages of those accounts will fail and an endless spinner will be shown.
*
* @param {object} account Account object
* @return {boolean} True if the account should be disabled
*/
isDisabled(account) {
return (this.passwordIsUnavailable && !!account.provisioningId) && !!this.mainStore.masterPasswordEnabled
// Disable provisioned accounts on passwordless sessions unless a master password is configured.
return this.passwordIsUnavailable && !!account.provisioningId && !this.mainStore.masterPasswordEnabled
},
},
}
Expand Down
1 change: 1 addition & 0 deletions src/init.js
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,7 @@ export default function initAfterAppCreation() {
mainStore.setSnoozeDisabledMutation(disableSnooze)
mainStore.setGoogleOauthUrlMutation(googleOauthUrl)
mainStore.setMicrosoftOauthUrlMutation(microsoftOauthUrl)
mainStore.setMasterPasswordEnabledMutation(loadState('mail', 'master-password-enabled', false))
mainStore.setFollowUpFeatureAvailableMutation(followUpFeatureAvailable)
mainStore.setContextChatFeatureAvailableMutation(contextChatFeatureAvailable)

Expand Down
10 changes: 6 additions & 4 deletions src/store/mainStore/actions.js
Original file line number Diff line number Diff line change
Expand Up @@ -902,9 +902,10 @@ export default function mainStoreActions() {

const mailbox = this.getMailbox(mailboxId)

// Skip superfluous requests if using passwordless authentication. They will fail anyway.
// Skip superfluous requests if using passwordless authentication without a
// master password. With a master password these requests succeed (#9008, #9653).
const passwordIsUnavailable = this.getPreference('password-is-unavailable', false)
const isDisabled = (account) => passwordIsUnavailable && !!account.provisioningId
const isDisabled = (account) => passwordIsUnavailable && !!account.provisioningId && !this.masterPasswordEnabled

if (mailbox.isUnified) {
return Promise.all(this.getAccounts
Expand Down Expand Up @@ -1004,9 +1005,10 @@ export default function mainStoreActions() {
})
},
async syncInboxes() {
// Skip superfluous requests if using passwordless authentication. They will fail anyway.
// Skip superfluous requests if using passwordless authentication without a
// master password. With a master password these requests succeed (#9008, #9653).
const passwordIsUnavailable = this.getPreference('password-is-unavailable', false)
const isDisabled = (account) => passwordIsUnavailable && !!account.provisioningId
const isDisabled = (account) => passwordIsUnavailable && !!account.provisioningId && !this.masterPasswordEnabled

return handleHttpAuthErrors(async () => {
const results = await Promise.all(this.getAccounts
Expand Down
22 changes: 20 additions & 2 deletions tests/Unit/Controller/PageControllerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
use OCA\Mail\Contracts\IUserPreferences;
use OCA\Mail\Controller\PageController;
use OCA\Mail\Db\Mailbox;
use OCA\Mail\Db\MailAccount;
use OCA\Mail\Db\TagMapper;
use OCA\Mail\Service\AccountService;
use OCA\Mail\Service\AiIntegrations\AiIntegrationsService;
Expand All @@ -26,6 +27,7 @@
use OCA\Mail\Service\InternalAddressService;
use OCA\Mail\Service\MailManager;
use OCA\Mail\Service\OutboxService;
use OCA\Mail\Service\Provisioning\Manager as ProvisioningManager;
use OCA\Mail\Service\QuickActionsService;
use OCA\Mail\Service\SmimeService;
use OCP\App\IAppManager;
Expand Down Expand Up @@ -122,6 +124,10 @@ class PageControllerTest extends TestCase {
private ContextChatSettingsService $contextChatSettingsService;

private ClassificationSettingsService|MockObject $classificationSettingsService;

/** @var ProvisioningManager|MockObject */
private $provisioningManager;

protected function setUp(): void {
parent::setUp();

Expand Down Expand Up @@ -154,6 +160,7 @@ protected function setUp(): void {
$this->contextChatSettingsService->method('isIndexingEnabled')->willReturn(true);

$this->classificationSettingsService = $this->createMock(ClassificationSettingsService::class);
$this->provisioningManager = $this->createMock(ProvisioningManager::class);
$this->controller = new PageController(
$this->appName,
$this->request,
Expand All @@ -180,14 +187,21 @@ protected function setUp(): void {
$this->appManager,
$this->contextChatSettingsService,
$this->classificationSettingsService,
$this->appConfig
$this->appConfig,
$this->provisioningManager,
);
}

public function testIndex(): void {
$account1 = $this->createMock(Account::class);
$account2 = $this->createMock(Account::class);
$mailbox = $this->createStub(Mailbox::class);
$mailAccount1 = $this->createMock(MailAccount::class);
$mailAccount1->method('getProvisioningId')->willReturn(null);
$mailAccount2 = $this->createMock(MailAccount::class);
$mailAccount2->method('getProvisioningId')->willReturn(null);
$account1->method('getMailAccount')->willReturn($mailAccount1);
$account2->method('getMailAccount')->willReturn($mailAccount2);
$this->preferences->expects($this->exactly(15))
->method('getPreference')
->willReturnMap([
Expand Down Expand Up @@ -347,7 +361,10 @@ public function testIndex(): void {
$this->classificationSettingsService->expects(($this->once()))
->method(('isClassificationEnabledByDefault'))
->willReturn(true);
$this->initialState->expects($this->exactly(27))
$this->provisioningManager->expects($this->never())
->method('getConfigById');

$this->initialState->expects($this->exactly(28))
->method('provideInitialState')
->withConsecutive(
['debug', true],
Expand All @@ -361,6 +378,7 @@ public function testIndex(): void {
['smime-sign-aliases',[]],
['sort-order', 'newest'],
['password-is-unavailable', true],
['master-password-enabled', false],
['preferences', [
'attachment-size-limit' => 123,
'external-avatars' => 'true',
Expand Down