From 563badd89929cea05bab3e57cd591c88126676e0 Mon Sep 17 00:00:00 2001 From: Rob Emery Date: Wed, 24 Dec 2025 14:34:16 +0000 Subject: [PATCH 1/8] Adding toggle for enabling the server side component to use a ClientTLS Certificate --- lib/Controller/SettingsController.php | 3 +++ lib/Service/AuthRoundCube.php | 8 ++++++++ lib/Service/Config.php | 3 +++ src/AdminSettings.vue | 15 +++++++++++++++ 4 files changed, 29 insertions(+) diff --git a/lib/Controller/SettingsController.php b/lib/Controller/SettingsController.php index ec1570c..2cf9309 100644 --- a/lib/Controller/SettingsController.php +++ b/lib/Controller/SettingsController.php @@ -60,6 +60,7 @@ class SettingsController extends Controller Config::FORCE_SSO => [ 'rw' => true, 'default' => Config::FORCE_SSO_DEFAULT, ], Config::SHOW_TOP_LINE => [ 'rw' => true, 'default' => Config::SHOW_TOP_LINE_DEFAULT, ], Config::ENABLE_SSL_VERIFY => [ 'rw' => true, 'default' => Config::ENABLE_SSL_VERIFY_DEFAULT, ], + Config::ENABLE_TLS_CLIENT_CERTIFICATES => [ 'rw' => true, 'default' => Config::ENABLE_TLS_CLIENT_CERTIFICATES_DEFAULT, ], Config::PERSONAL_ENCRYPTION => [ 'rw' => true, 'default' => Config::PERSONAL_ENCRYPTION_DEFAULT, ], Config::CARDDAV_PROVISIONG_TAG => [ 'rw' => true, 'default' => Config::CARDDAV_PROVISIONG_TAG_DEFAULT, ], ]; @@ -162,6 +163,7 @@ public function setAdmin(string $setting, mixed $value, bool $force = false):Dat case Config::SHOW_TOP_LINE: case Config::ENABLE_SSL_VERIFY: case Config::PERSONAL_ENCRYPTION: + case Config::ENABLE_TLS_CLIENT_CERTIFICATES: $newValue = filter_var($value, FILTER_VALIDATE_BOOLEAN, ['flags' => FILTER_NULL_ON_FAILURE]); if ($newValue === null) { return self::grumble($this->l->t( @@ -249,6 +251,7 @@ public function getAdmin(?string $setting = null):DataResponse case Config::SHOW_TOP_LINE: case Config::ENABLE_SSL_VERIFY: case Config::PERSONAL_ENCRYPTION: + case Config::ENABLE_TLS_CLIENT_CERTIFICATES: if ($humanValue !== null) { $humanValue = $humanValue ? $this->l->t('true') : $this->l->t('false'); } diff --git a/lib/Service/AuthRoundCube.php b/lib/Service/AuthRoundCube.php index be6555b..42a2a38 100644 --- a/lib/Service/AuthRoundCube.php +++ b/lib/Service/AuthRoundCube.php @@ -58,6 +58,7 @@ class AuthRoundCube /** @var bool */ private $enableSSLVerify; + private $enableClientTLSCertificates; private $proto; private $host; @@ -80,6 +81,7 @@ public function __construct( protected ILogger $logger, ) { $this->enableSSLVerify = $this->config->getAppValue(Config::ENABLE_SSL_VERIFY); + $this->enableClientTLSCertificates = $this->config->getAppValue(Config::ENABLE_TLS_CLIENT_CERTIFICATES); $location = $this->config->getAppValue(Config::EXTERNAL_LOCATION); if ($location[0] == '/') { @@ -458,6 +460,12 @@ private function sendRequest(string $rcQuery = '', string $method = 'POST', ?arr $curlOpts[CURLOPT_SSL_VERIFYPEER] = false; $curlOpts[CURLOPT_SSL_VERIFYHOST] = 0; } + if ($this->enableClientTLSCertificates) { + $curlOpts[CURLOPT_SSLKEY] = "TODO-ClientCertificate.key"; + $curlOpts[CURLOPT_SSLCERT] = "TODO-ClientCertificate.pem"; + $curlOpts[CURLOPT_SSLKEYPASSWD] = "TODO-ClientCertificatePassword"; + } + curl_setopt_array($curl, $curlOpts); $rawResponse = curl_exec($curl); diff --git a/lib/Service/Config.php b/lib/Service/Config.php index 115dea5..d8f5637 100644 --- a/lib/Service/Config.php +++ b/lib/Service/Config.php @@ -66,6 +66,8 @@ class Config public const SHOW_TOP_LINE_DEFAULT = false; public const ENABLE_SSL_VERIFY = 'enableSSLVerify'; public const ENABLE_SSL_VERIFY_DEFAULT = true; + public const ENABLE_TLS_CLIENT_CERTIFICATES = 'enableTLSClientCertificates'; + public const ENABLE_SSL_VERIFY_DEFAULT = false; public const PERSONAL_ENCRYPTION = 'personalEncryption'; public const PERSONAL_ENCRYPTION_DEFAULT = false; public const CARDDAV_PROVISIONG_TAG = 'cardDavProvisioningTag'; @@ -78,6 +80,7 @@ class Config self::FORCE_SSO => self::FORCE_SSO_DEFAULT, self::SHOW_TOP_LINE => self::SHOW_TOP_LINE_DEFAULT, self::ENABLE_SSL_VERIFY => self::ENABLE_SSL_VERIFY_DEFAULT, + self::ENABLE_TLS_CLIENT_CERTIFICATES => self::ENABLE_TLS_CLIENT_CERTIFICATES_DEFAULT, self::PERSONAL_ENCRYPTION => self::PERSONAL_ENCRYPTION_DEFAULT, self::CARDDAV_PROVISIONG_TAG => self::CARDDAV_PROVISIONG_TAG_DEFAULT, ]; diff --git a/src/AdminSettings.vue b/src/AdminSettings.vue index c8e36e0..97b0487 100644 --- a/src/AdminSettings.vue +++ b/src/AdminSettings.vue @@ -170,6 +170,20 @@ > {{ t(appName, 'Enable SSL verification.') }} + + Date: Wed, 24 Dec 2025 16:33:34 +0000 Subject: [PATCH 2/8] Fix copy-pasta --- lib/Service/Config.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Service/Config.php b/lib/Service/Config.php index d8f5637..b7bac55 100644 --- a/lib/Service/Config.php +++ b/lib/Service/Config.php @@ -67,7 +67,7 @@ class Config public const ENABLE_SSL_VERIFY = 'enableSSLVerify'; public const ENABLE_SSL_VERIFY_DEFAULT = true; public const ENABLE_TLS_CLIENT_CERTIFICATES = 'enableTLSClientCertificates'; - public const ENABLE_SSL_VERIFY_DEFAULT = false; + public const ENABLE_TLS_CLIENT_CERTIFICATES_DEFAULT = false; public const PERSONAL_ENCRYPTION = 'personalEncryption'; public const PERSONAL_ENCRYPTION_DEFAULT = false; public const CARDDAV_PROVISIONG_TAG = 'cardDavProvisioningTag'; From 596fd4728eb1971c06052675b4f53fa02b9278e7 Mon Sep 17 00:00:00 2001 From: Rob Emery Date: Fri, 26 Dec 2025 20:45:51 +0000 Subject: [PATCH 3/8] Adding configuration options for the certificate, key file etc --- lib/Controller/SettingsController.php | 3 ++ lib/Service/AuthRoundCube.php | 12 +++++-- lib/Service/Config.php | 9 ++++++ src/AdminSettings.vue | 45 +++++++++++++++++++++++++++ 4 files changed, 66 insertions(+), 3 deletions(-) diff --git a/lib/Controller/SettingsController.php b/lib/Controller/SettingsController.php index 2cf9309..b01025e 100644 --- a/lib/Controller/SettingsController.php +++ b/lib/Controller/SettingsController.php @@ -61,6 +61,9 @@ class SettingsController extends Controller Config::SHOW_TOP_LINE => [ 'rw' => true, 'default' => Config::SHOW_TOP_LINE_DEFAULT, ], Config::ENABLE_SSL_VERIFY => [ 'rw' => true, 'default' => Config::ENABLE_SSL_VERIFY_DEFAULT, ], Config::ENABLE_TLS_CLIENT_CERTIFICATES => [ 'rw' => true, 'default' => Config::ENABLE_TLS_CLIENT_CERTIFICATES_DEFAULT, ], + Config::CLIENT_TLS_KEY_FILE => [ 'rw' => true, 'default' => Config::CLIENT_TLS_KEY_FILE_DEFAULT, ] + Config::CLIENT_TLS_CERTIFICATE_FILE => [ 'rw' => true, 'default' => Config::CLIENT_TLS_CERTIFICATE_FILE_DEFAULT, ], + Config::CLIENT_TLS_KEY_PASSWORD => [ 'rw' => true, 'default' => Config::CLIENT_TLS_KEY_PASSWORD_DEFAULT, ], Config::PERSONAL_ENCRYPTION => [ 'rw' => true, 'default' => Config::PERSONAL_ENCRYPTION_DEFAULT, ], Config::CARDDAV_PROVISIONG_TAG => [ 'rw' => true, 'default' => Config::CARDDAV_PROVISIONG_TAG_DEFAULT, ], ]; diff --git a/lib/Service/AuthRoundCube.php b/lib/Service/AuthRoundCube.php index 42a2a38..f65ac7d 100644 --- a/lib/Service/AuthRoundCube.php +++ b/lib/Service/AuthRoundCube.php @@ -55,6 +55,9 @@ class AuthRoundCube /** @var string */ private $appName; + private $clientTLSKeyFile; + private $clientTLSCertificateFile; + private $clientTLSKeyPassword; /** @var bool */ private $enableSSLVerify; @@ -82,6 +85,9 @@ public function __construct( ) { $this->enableSSLVerify = $this->config->getAppValue(Config::ENABLE_SSL_VERIFY); $this->enableClientTLSCertificates = $this->config->getAppValue(Config::ENABLE_TLS_CLIENT_CERTIFICATES); + $this->clientTLSKeyFile = $this->config->getAppValue(Config::CLIENT_TLS_KEY_FILE); + $this->clientTLSCertificateFile = $this->config->getAppValue(Config::CLIENT_TLS_CERTIFICATE_FILE); + $this->clientTLSKeyPassword = $this->config->getAppValue(Config::CLIENT_TLS_KEY_PASSWORD); $location = $this->config->getAppValue(Config::EXTERNAL_LOCATION); if ($location[0] == '/') { @@ -461,9 +467,9 @@ private function sendRequest(string $rcQuery = '', string $method = 'POST', ?arr $curlOpts[CURLOPT_SSL_VERIFYHOST] = 0; } if ($this->enableClientTLSCertificates) { - $curlOpts[CURLOPT_SSLKEY] = "TODO-ClientCertificate.key"; - $curlOpts[CURLOPT_SSLCERT] = "TODO-ClientCertificate.pem"; - $curlOpts[CURLOPT_SSLKEYPASSWD] = "TODO-ClientCertificatePassword"; + $curlOpts[CURLOPT_SSLKEY] = $this->clientTLSKeyFile; + $curlOpts[CURLOPT_SSLCERT] = $this->clientTLSCertificateFile; + $curlOpts[CURLOPT_SSLKEYPASSWD] = $this->clientTLSKeyPassword; } curl_setopt_array($curl, $curlOpts); diff --git a/lib/Service/Config.php b/lib/Service/Config.php index b7bac55..5be4410 100644 --- a/lib/Service/Config.php +++ b/lib/Service/Config.php @@ -68,6 +68,12 @@ class Config public const ENABLE_SSL_VERIFY_DEFAULT = true; public const ENABLE_TLS_CLIENT_CERTIFICATES = 'enableTLSClientCertificates'; public const ENABLE_TLS_CLIENT_CERTIFICATES_DEFAULT = false; + public const CLIENT_TLS_KEY_FILE = 'clientTLSKeyFile'; + public const CLIENT_TLS_KEY_FILE_DEFAULT = ''; + public const CLIENT_TLS_CERTIFICATE_FILE = 'clientTLSCertificateFile'; + public const CLIENT_TLS_CERTIFICATE_FILE_DEFAULT = ''; + public const CLIENT_TLS_KEY_PASSWORD = 'clientTLSKeyPassword'; + public const CLIENT_TLS_KEY_PASSWORD_DEFAULT = ''; public const PERSONAL_ENCRYPTION = 'personalEncryption'; public const PERSONAL_ENCRYPTION_DEFAULT = false; public const CARDDAV_PROVISIONG_TAG = 'cardDavProvisioningTag'; @@ -81,6 +87,9 @@ class Config self::SHOW_TOP_LINE => self::SHOW_TOP_LINE_DEFAULT, self::ENABLE_SSL_VERIFY => self::ENABLE_SSL_VERIFY_DEFAULT, self::ENABLE_TLS_CLIENT_CERTIFICATES => self::ENABLE_TLS_CLIENT_CERTIFICATES_DEFAULT, + self::CLIENT_TLS_KEY_FILE => self::CLIENT_TLS_KEY_FILE_DEFAULT, + self::CLIENT_TLS_CERTIFICATE_FILE => self::CLIENT_TLS_CERTIFICATE_FILE_DEFAULT, + self::CLIENT_TLS_KEY_PASSWORD => self::CLIENT_TLS_KEY_PASSWORD_DEFAULT, self::PERSONAL_ENCRYPTION => self::PERSONAL_ENCRYPTION_DEFAULT, self::CARDDAV_PROVISIONG_TAG => self::CARDDAV_PROVISIONG_TAG_DEFAULT, ]; diff --git a/src/AdminSettings.vue b/src/AdminSettings.vue index 97b0487..e48b18a 100644 --- a/src/AdminSettings.vue +++ b/src/AdminSettings.vue @@ -184,6 +184,48 @@ > {{ t(appName, 'Enable TLS Client Certificates.') }} + + + + + + Date: Fri, 26 Dec 2025 22:08:57 +0000 Subject: [PATCH 4/8] Missing , --- lib/Controller/SettingsController.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Controller/SettingsController.php b/lib/Controller/SettingsController.php index b01025e..724ed30 100644 --- a/lib/Controller/SettingsController.php +++ b/lib/Controller/SettingsController.php @@ -61,7 +61,7 @@ class SettingsController extends Controller Config::SHOW_TOP_LINE => [ 'rw' => true, 'default' => Config::SHOW_TOP_LINE_DEFAULT, ], Config::ENABLE_SSL_VERIFY => [ 'rw' => true, 'default' => Config::ENABLE_SSL_VERIFY_DEFAULT, ], Config::ENABLE_TLS_CLIENT_CERTIFICATES => [ 'rw' => true, 'default' => Config::ENABLE_TLS_CLIENT_CERTIFICATES_DEFAULT, ], - Config::CLIENT_TLS_KEY_FILE => [ 'rw' => true, 'default' => Config::CLIENT_TLS_KEY_FILE_DEFAULT, ] + Config::CLIENT_TLS_KEY_FILE => [ 'rw' => true, 'default' => Config::CLIENT_TLS_KEY_FILE_DEFAULT, ], Config::CLIENT_TLS_CERTIFICATE_FILE => [ 'rw' => true, 'default' => Config::CLIENT_TLS_CERTIFICATE_FILE_DEFAULT, ], Config::CLIENT_TLS_KEY_PASSWORD => [ 'rw' => true, 'default' => Config::CLIENT_TLS_KEY_PASSWORD_DEFAULT, ], Config::PERSONAL_ENCRYPTION => [ 'rw' => true, 'default' => Config::PERSONAL_ENCRYPTION_DEFAULT, ], From d65d0b35d97f923a0271b391563e8bbfed3437e3 Mon Sep 17 00:00:00 2001 From: Rob Emery Date: Sat, 27 Dec 2025 13:59:02 +0000 Subject: [PATCH 5/8] Looks like these probably need to be in here? --- lib/Controller/SettingsController.php | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/lib/Controller/SettingsController.php b/lib/Controller/SettingsController.php index ec1570c..c734b41 100644 --- a/lib/Controller/SettingsController.php +++ b/lib/Controller/SettingsController.php @@ -151,6 +151,9 @@ public function setAdmin(string $setting, mixed $value, bool $force = false):Dat case Config::EMAIL_ADDRESS_CHOICE: case Config::FIXED_SINGLE_EMAIL_ADDRESS: case Config::CARDDAV_PROVISIONG_TAG: + case Config::CLIENT_TLS_KEY_FILE: + case Config::CLIENT_TLS_CERTIFICATE_FILE: + case Config::CLIENT_TLS_KEY_PASSWORD: $newValue = $value; break; case Config::FIXED_SINGLE_EMAIL_PASSWORD: @@ -240,6 +243,9 @@ public function getAdmin(?string $setting = null):DataResponse case Config::EMAIL_ADDRESS_CHOICE: case Config::FIXED_SINGLE_EMAIL_ADDRESS: case Config::CARDDAV_PROVISIONG_TAG: + case Config::CLIENT_TLS_KEY_FILE: + case Config::CLIENT_TLS_CERTIFICATE_FILE: + case Config::CLIENT_TLS_KEY_PASSWORD: break; case Config::FIXED_SINGLE_EMAIL_PASSWORD: $humanValue = '●●●●●●●●'; From 5aed67de6971aa6355ee496e271c044d6af0a848 Mon Sep 17 00:00:00 2001 From: Rob Emery Date: Fri, 2 Jan 2026 21:35:13 +0000 Subject: [PATCH 6/8] These should be text boxes, not checkboxes --- src/AdminSettings.vue | 65 +++++++++++++++---------------------------- 1 file changed, 22 insertions(+), 43 deletions(-) diff --git a/src/AdminSettings.vue b/src/AdminSettings.vue index e48b18a..0910ac7 100644 --- a/src/AdminSettings.vue +++ b/src/AdminSettings.vue @@ -182,50 +182,29 @@ - - - - - - + + + Date: Fri, 2 Jan 2026 22:01:30 +0000 Subject: [PATCH 7/8] Adding more accurate messages etc --- src/AdminSettings.vue | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/AdminSettings.vue b/src/AdminSettings.vue index 0910ac7..62fe560 100644 --- a/src/AdminSettings.vue +++ b/src/AdminSettings.vue @@ -187,21 +187,21 @@ From 7a98903cb20916e19e73b1da4f3f974c2b55de7c Mon Sep 17 00:00:00 2001 From: Rob Emery Date: Thu, 5 Feb 2026 10:55:13 +0000 Subject: [PATCH 8/8] lint fix from 1c3ac477a1f0904dc6363d8bb26e1943f65e28da --- .eslintrc.js | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/.eslintrc.js b/.eslintrc.js index f51c13b..ad2e02f 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -1,7 +1,7 @@ module.exports = { - // extends: [ - // '@nextcloud', - // ], + extends: [ + '@nextcloud', + ], // some unused toolgit files ignorePatterns: [ 'src/toolkit/util/file-download.js', @@ -38,13 +38,25 @@ module.exports = { }, overrides: [ { + // Vue files with TypeScript need the TypeScript parser files: ['*.vue'], + parser: 'vue-eslint-parser', + parserOptions: { + parser: '@typescript-eslint/parser', + sourceType: 'module', + ecmaVersion: 2022, + }, rules: { semi: ['error', 'never'], + // False positive with TypeScript generics like defineEmits<{...}>() + 'func-call-spacing': 'off', + '@typescript-eslint/func-call-spacing': 'off', + // Webpack ?raw query not recognized by eslint resolver + 'import/no-unresolved': ['error', { ignore: ['\\?raw$'] }], }, }, { - files: ['*.ts', '*.cts', '*.mts', '*.tsx', '*.vue'], + files: ['*.ts', '*.cts', '*.mts', '*.tsx'], rules: { '@typescript-eslint/no-unused-vars': ['warn', { argsIgnorePattern: '^_' }], },