Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
51 commits
Select commit Hold shift + click to select a range
8bbcbfc
Allow SSO users to send and recieve mail via master password
mickenordin Sep 30, 2023
fb8dcb7
Run composer run cs:fix
mickenordin Oct 1, 2023
9ba1d28
Add deeper master password integration
mickenordin Oct 3, 2023
073670c
Move master password detection into the provisioning middleware
mickenordin Oct 4, 2023
c4658bf
Move settings in to provisioning
mickenordin Oct 4, 2023
51a5d39
Add migration
mickenordin Oct 5, 2023
ddd11ca
Add plumbing to ProvisioningMapper
mickenordin Oct 5, 2023
a1226e7
Clean up
mickenordin Oct 5, 2023
d728bd5
Get password from provisioning
mickenordin Oct 5, 2023
152f5a4
Assume table exists, but check for columns
mickenordin Oct 5, 2023
1941c61
Make it possible to access the mail account, so that we can get the p…
mickenordin Oct 5, 2023
e889ef7
composer cs:fix
mickenordin Oct 5, 2023
37e4681
Fix(l10n): Update translations from Transifex
nextcloud-bot Oct 7, 2023
d423d14
Fix(l10n): Update translations from Transifex
nextcloud-bot Oct 8, 2023
366b233
Fix(l10n): Update translations from Transifex
nextcloud-bot Oct 9, 2023
50734dc
fix(preprocessing): chunk message query
miaulalala Oct 5, 2023
a238918
fix(sync): return if headers couldn't be parsed
miaulalala Oct 5, 2023
fd36f09
fix(mailto): show empty thread view on handler
st3iny Oct 9, 2023
4a87a15
Fix(l10n): Update translations from Transifex
nextcloud-bot Oct 11, 2023
6273c9b
Avoid calling Mailbox.vue::loadEnvelopes twice when switching between…
GretaD Oct 10, 2023
0842311
fix(retention): properly clean orphans
st3iny Oct 9, 2023
28f0e73
chore: Drop unused \OCA\Mail\Account::testConnectivity
ChristophWurst Oct 11, 2023
77f48f3
fix: Rate-limit IMAP auth if the password is wrong
ChristophWurst Oct 6, 2023
c00d2fd
ci: Add caches to integration tests
ChristophWurst Oct 11, 2023
4a0924c
ci(smime): skip content type null test
st3iny Oct 11, 2023
62a009d
fix(search): Use corresponding table alias for recipient search
ChristophWurst Oct 11, 2023
3c05ceb
Fix(l10n): Update translations from Transifex
nextcloud-bot Oct 12, 2023
5bed5d9
chore: Fix undeclared class properties in integration tests
ChristophWurst Oct 11, 2023
2fcd50d
Fix(l10n): Update translations from Transifex
nextcloud-bot Oct 14, 2023
5022717
Fix(l10n): Update translations from Transifex
nextcloud-bot Oct 15, 2023
c16b919
Fix(l10n): Update translations from Transifex
nextcloud-bot Oct 16, 2023
48d70cc
fix(search): Limit recipient joins to their types
ChristophWurst Oct 11, 2023
ec161b2
Add getter for masterPasswordEnabled
mickenordin Oct 17, 2023
cd42375
Fix(l10n): Update translations from Transifex
nextcloud-bot Oct 17, 2023
23a5f12
Chore: drop use of \OCA\Mail\Account::getImapConnection
hamza221 Oct 11, 2023
0c15930
fix(deps): bump @nextcloud/moment from 1.2.1 to ^1.2.2 (main) (#8970)
renovate[bot] Oct 17, 2023
63a0764
Fix(l10n): Update translations from Transifex
nextcloud-bot Oct 18, 2023
47b33a7
Bump babel
GretaD Oct 18, 2023
15c59e5
fix(deps): bump ramda from 0.29.0 to ^0.29.1
renovate[bot] Oct 17, 2023
9e8ad4a
fix(deps): pin @ckeditor/ckeditor5-dev-utils from 37.0.1 to 37.0.1
renovate[bot] Oct 18, 2023
d94ee87
fix(deps): bump stylelint from 15.10.3 to ^15.11.0 (main) (#8972)
renovate[bot] Oct 18, 2023
8629256
Fix(l10n): Update translations from Transifex
nextcloud-bot Oct 19, 2023
128e727
Merge branch 'main' into main
mickenordin Oct 20, 2023
80516e9
Merge branch 'main' into main
mickenordin Oct 20, 2023
41bb5a9
Merge branch 'main' into main
mickenordin Oct 20, 2023
6524a1c
Merge branch 'main' into main
mickenordin Oct 25, 2023
f0b772a
Merge branch 'main' into main
mickenordin Oct 25, 2023
8fd4982
Move password logic to ProvisioningManager for performance reasons
mickenordin Oct 25, 2023
3dc1ed9
Bump version to 3.5.0-alpha.3 to trigger migration
mickenordin Oct 25, 2023
f8e26af
Merge branch 'main' into main
mickenordin Oct 26, 2023
f3c7d57
Merge branch 'main' into main
mickenordin Oct 26, 2023
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
2 changes: 1 addition & 1 deletion appinfo/info.xml
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ The rating depends on the installed text processing backend. See [the rating ove

Learn more about the Nextcloud Ethical AI Rating [in our blog](https://nextcloud.com/blog/nextcloud-ethical-ai-rating/).
]]></description>
<version>3.5.0-alpha.2</version>
<version>3.5.0-alpha.3</version>
<licence>agpl</licence>
<author>Greta Doçi</author>
<author homepage="https://github.com/nextcloud/groupware">Nextcloud Groupware Team</author>
Expand Down
10 changes: 10 additions & 0 deletions lib/Db/Provisioning.php
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,10 @@
* @method void setSmtpPort(int $smtpPort)
* @method string getSmtpSslMode()
* @method void setSmtpSslMode(string $smtpSslMode)
* @method bool|null getMasterPasswordEnabled()
* @method void setMasterPasswordEnabled(bool $masterPasswordEnabled)
* @method bool|null getMasterPassword()
* @method void setMasterPassword(string $masterPassword)
* @method bool|null getSieveEnabled()
* @method void setSieveEnabled(bool $sieveEnabled)
* @method string|null getSieveHost()
Expand Down Expand Up @@ -81,6 +85,8 @@ class Provisioning extends Entity implements JsonSerializable {
protected $smtpHost;
protected $smtpPort;
protected $smtpSslMode;
protected $masterPasswordEnabled;
protected $masterPassword;
protected $sieveEnabled;
protected $sieveUser;
protected $sieveHost;
Expand All @@ -93,6 +99,8 @@ class Provisioning extends Entity implements JsonSerializable {
public function __construct() {
$this->addType('imapPort', 'integer');
$this->addType('smtpPort', 'integer');
$this->addType('masterPasswordEnabled', 'boolean');
$this->addType('masterPassword', 'string');
$this->addType('sieveEnabled', 'boolean');
$this->addType('sievePort', 'integer');
$this->addType('ldapAliasesProvisioning', 'boolean');
Expand All @@ -112,6 +120,8 @@ public function jsonSerialize() {
'smtpHost' => $this->getSmtpHost(),
'smtpPort' => $this->getSmtpPort(),
'smtpSslMode' => $this->getSmtpSslMode(),
'masterPasswordEnabled' => $this->getMasterPasswordEnabled(),
'masterPassword' => $this->getMasterPassword(),
'sieveEnabled' => $this->getSieveEnabled(),
'sieveUser' => $this->getSieveUser(),
'sieveHost' => $this->getSieveHost(),
Expand Down
3 changes: 3 additions & 0 deletions lib/Db/ProvisioningMapper.php
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,9 @@ public function validate(array $data): Provisioning {
$provisioning->setSmtpPort((int)$data['smtpPort']);
$provisioning->setSmtpSslMode($data['smtpSslMode']);

$provisioning->setMasterPasswordEnabled((bool)$data['masterPasswordEnabled']);
$provisioning->setMasterPassword($data['masterPassword'] ?? '');

$provisioning->setSieveEnabled((bool)$data['sieveEnabled']);
$provisioning->setSieveHost($data['sieveHost'] ?? '');
$provisioning->setSieveUser($data['sieveUser'] ?? '');
Expand Down
4 changes: 3 additions & 1 deletion lib/Http/Middleware/ProvisioningMiddleware.php
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ public function beforeController($controller, $methodName) {
try {
$this->provisioningManager->provisionSingleUser($configs, $user);
$password = $this->credentialStore->getLoginCredentials()->getPassword();

// FIXME: Need to check for an empty string here too?
// The password is empty (and not null) when using WebAuthn passwordless login.
// Maybe research other providers as well.
Expand All @@ -82,7 +83,8 @@ public function beforeController($controller, $methodName) {
}
$this->provisioningManager->updatePassword(
$user,
$password
$password,
$configs
);
} catch (CredentialsUnavailableException | PasswordUnavailableException $e) {
// Nothing to update
Expand Down
58 changes: 58 additions & 0 deletions lib/Migration/Version3500Date20231005091430.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
<?php

declare(strict_types=1);

namespace OCA\Mail\Migration;

use Closure;
use OCP\DB\ISchemaWrapper;
use OCP\DB\Types;
use OCP\IConfig;
use OCP\IDBConnection;
use OCP\Migration\IOutput;
use OCP\Migration\SimpleMigrationStep;
use Psr\Log\LoggerInterface;

class Version3500Date20231005091430 extends SimpleMigrationStep {
/** @var IConfig */
protected $config;

/** @var IDBConnection */
protected $connection;

/** @var LoggerInterface */
protected $logger;

public function __construct(IConfig $config, IDBConnection $connection, LoggerInterface $logger) {
$this->config = $config;
$this->connection = $connection;
$this->logger = $logger;
}

/**
* @param IOutput $output
* @param Closure $schemaClosure The `\Closure` returns a `ISchemaWrapper`
* @param array $options
* @return null|ISchemaWrapper
*/
public function changeSchema(IOutput $output, Closure $schemaClosure, array $options): ?ISchemaWrapper {
$schema = $schemaClosure();

$provisioningTable = $schema->getTable('mail_provisionings');
if (!$provisioningTable->hasColumn('master_password_enabled')) {
$provisioningTable->addColumn('master_password_enabled', Types::BOOLEAN, [
'notnull' => false,
'default' => false,
]);
}
if (!$provisioningTable->hasColumn('master_password')) {
$provisioningTable->addColumn('master_password', Types::STRING, [
'notnull' => false,
'length' => 256,
]);
}

return $schema;
}

}
10 changes: 9 additions & 1 deletion lib/Service/Provisioning/Manager.php
Original file line number Diff line number Diff line change
Expand Up @@ -316,10 +316,18 @@ public function deprovision(Provisioning $provisioning): void {
}
}

public function updatePassword(IUser $user, string $password): void {
public function updatePassword(IUser $user, string $password, array $provisionings): void {
try {
$account = $this->mailAccountMapper->findProvisionedAccount($user);

$provisioning = $this->findMatchingConfig($provisionings, $user);
$masterPassword = $provisioning->getMasterPassword();
$masterPasswordEnabled = $provisioning->getMasterPasswordEnabled();
if ($masterPasswordEnabled && $masterPassword !== null) {
$password = $masterPassword;
$this->logger->debug('Password set to master password for ' . $user->getUID());
}

if (!empty($account->getInboundPassword())
&& $this->crypto->decrypt($account->getInboundPassword()) === $password
&& !empty($account->getOutboundPassword())
Expand Down
3 changes: 2 additions & 1 deletion src/components/Navigation.vue
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,8 @@ export default {
* @return {boolean} True if the account should be disabled
*/
isDisabled(account) {
return this.passwordIsUnavailable && !!account.provisioningId

return (this.passwordIsUnavailable && !!account.provisioningId) && !!this.$store.getters.masterPasswordEnabled
},
},
}
Expand Down
37 changes: 37 additions & 0 deletions src/components/settings/ProvisioningSettings.vue
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,37 @@
</div>
</div>
</div>
<div class="settings-group">
<div class="group-title">
{{ t('mail', 'Master password') }}
</div>
<div class="group-inputs">
<div>
<input
:id="'mail-master-password-enabled' + setting.id"
v-model="masterPasswordEnabled"
type="checkbox"
class="checkbox">
<label :for="'mail-master-password-enabled' + setting.id">
{{ t('mail', 'Use master password') }}
</label>
</div>
<div>
<input
:id="'mail-password-id' + setting.id"
v-model="passwordId"
type="hidden"
required>
<input
id="mail-master-password"
v-model="masterPassword"
:disabled="loading"
type="password"
required>
<label for="mail-master-password"> {{ t('mail', 'Master password') }} </label>
</div>
</div>
</div>
<div class="settings-group">
<div class="group-title">
{{ t('mail', 'Sieve') }}
Expand Down Expand Up @@ -411,6 +442,8 @@ export default {
smtpPort: this.setting.smtpPort || 587,
smtpUser: this.setting.smtpUser || '%USERID%domain.com',
smtpSslMode: this.setting.smtpSslMode || 'tls',
masterPasswordEnabled: this.setting.masterPasswordEnabled || '',
masterPassword: this.setting.masterPassword || '',
sieveEnabled: this.setting.sieveEnabled || '',
sieveHost: this.setting.sieveHost || '',
sievePort: this.setting.sievePort || '',
Expand Down Expand Up @@ -443,6 +476,8 @@ export default {
smtpHost: this.smtpHost,
smtpPort: this.smtpPort,
smtpSslMode: this.smtpSslMode,
masterPasswordEnabled: this.masterPasswordEnabled,
masterPassword: this.masterPassword,
sieveEnabled: this.sieveEnabled,
sieveUser: this.sieveUser,
sieveHost: this.sieveHost,
Expand Down Expand Up @@ -474,6 +509,8 @@ export default {
smtpHost: this.smtpHost,
smtpPort: this.smtpPort,
smtpSslMode: this.smtpSslMode,
masterPasswordEnabled: this.masterPasswordEnabled,
masterPassword: this.masterPassword,
sieveEnabled: this.sieveEnabled,
sieveUser: this.sieveUser,
sieveHost: this.sieveHost,
Expand Down
1 change: 1 addition & 0 deletions src/store/getters.js
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@ export const getters = {
isScheduledSendingDisabled: (state) => state.isScheduledSendingDisabled,
isSnoozeDisabled: (state) => state.isSnoozeDisabled,
googleOauthUrl: (state) => state.googleOauthUrl,
masterPasswordEnabled: (state) => state.masterPasswordEnabled,
microsoftOauthUrl: (state) => state.microsoftOauthUrl,
getActiveSieveScript: (state) => (accountId) => state.sieveScript[accountId],
getCurrentUserPrincipal: (state) => state.currentUserPrincipal,
Expand Down
1 change: 1 addition & 0 deletions src/store/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ export default new Store({
isSnoozeDisabled: false,
currentUserPrincipal: undefined,
googleOauthUrl: null,
masterPasswordEnabled: false,
sieveScript: {},
calendars: [],
smimeCertificates: [],
Expand Down
3 changes: 3 additions & 0 deletions src/store/mutations.js
Original file line number Diff line number Diff line change
Expand Up @@ -475,6 +475,9 @@ export default {
setGoogleOauthUrl(state, url) {
state.googleOauthUrl = url
},
setMasterPasswordEnabled(state, value) {
state.masterPasswordEnabled = value
},
setMicrosoftOauthUrl(state, url) {
state.microsoftOauthUrl = url
},
Expand Down
3 changes: 2 additions & 1 deletion tests/Unit/Http/Middleware/ProvisioningMiddlewareTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -217,7 +217,8 @@ public function testBeforeController() {
->method('updatePassword')
->with(
$user,
'123456'
'123456',
$configs
);

$this->middleware->beforeController(
Expand Down