diff --git a/packages/lib/models/settings/builtInMetadata.ts b/packages/lib/models/settings/builtInMetadata.ts index e822d3689ce..0482f4fb483 100644 --- a/packages/lib/models/settings/builtInMetadata.ts +++ b/packages/lib/models/settings/builtInMetadata.ts @@ -1576,6 +1576,20 @@ const builtInMetadata = (Setting: typeof SettingType) => { isGlobal: true, }, + 'featureFlag.linuxKeychain': { + value: false, + type: SettingItemType.Bool, + public: true, + storage: SettingStorage.File, + appTypes: [AppType.Desktop], + label: () => 'Enable keychain support', + description: () => 'This is an experimental setting to enable keychain support on Linux', + show: () => shim.isLinux(), + section: 'general', + isGlobal: true, + advanced: true, + }, + // 'featureFlag.syncAccurateTimestamps': { // value: false, diff --git a/packages/lib/services/SettingUtils.ts b/packages/lib/services/SettingUtils.ts index 131b555d211..4686a27a80d 100644 --- a/packages/lib/services/SettingUtils.ts +++ b/packages/lib/services/SettingUtils.ts @@ -34,6 +34,13 @@ export async function loadKeychainServiceAndSettings(keychainServiceDrivers: Key Setting.setKeychainService(KeychainService.instance()); await Setting.load(); + // Using Linux with the keychain has been observed to cause all secure settings to be lost + // on Fedora 40 + GNOME. (This may have been related to running multiple Joplin instances). + // For now, make saving to the keychain opt-in until more feedback is received. + if (shim.isLinux() && !Setting.value('featureFlag.linuxKeychain')) { + KeychainService.instance().readOnly = true; + } + // This is part of the migration to the new sync target info. It needs to be // set as early as possible since it's used to tell if E2EE is enabled, it // contains the master keys, etc. Once it has been set, it becomes a noop diff --git a/packages/lib/versionInfo.ts b/packages/lib/versionInfo.ts index dd9d061bc74..037e3408534 100644 --- a/packages/lib/versionInfo.ts +++ b/packages/lib/versionInfo.ts @@ -1,9 +1,13 @@ +import Logger from '@joplin/utils/Logger'; import { _ } from './locale'; import Setting from './models/Setting'; import { reg } from './registry'; +import KeychainService from './services/keychain/KeychainService'; import { Plugins } from './services/plugins/PluginService'; import shim from './shim'; +const logger = Logger.create('versionInfo'); + export interface PackageInfo { name: string; version: string; @@ -70,15 +74,21 @@ export default function versionInfo(packageInfo: PackageInfo, plugins: Plugins) copyrightText.replace('YYYY', `${now.getFullYear()}`), ]; + let keychainSupported = false; + try { + // To allow old keys to be read, certain apps allow read-only keychain access: + keychainSupported = Setting.value('keychain.supported') >= 1 && !KeychainService.instance().readOnly; + } catch (error) { + logger.error('Failed to determine if keychain is supported', error); + } + const body = [ _('%s %s (%s, %s)', p.name, p.version, Setting.value('env'), shim.platformName()), '', _('Client ID: %s', Setting.value('clientId')), _('Sync Version: %s', Setting.value('syncVersion')), _('Profile Version: %s', reg.db().version()), - // The portable app temporarily supports read-only keychain access (but disallows - // write). - _('Keychain Supported: %s', (Setting.value('keychain.supported') >= 1 && !shim.isPortable()) ? _('Yes') : _('No')), + _('Keychain Supported: %s', keychainSupported ? _('Yes') : _('No')), ]; if (gitInfo) {