From 56c403ecbc1b86380ab577db2c0fb9c5f068292f Mon Sep 17 00:00:00 2001
From: Carl Christian Snethlage <50491877+calixtus@users.noreply.github.com>
Date: Wed, 28 Jun 2023 14:11:26 +0200
Subject: [PATCH 01/21] Added dependency
---
build.gradle | 2 ++
1 file changed, 2 insertions(+)
diff --git a/build.gradle b/build.gradle
index 2b6a5e58528..f1fe7082c4e 100644
--- a/build.gradle
+++ b/build.gradle
@@ -127,6 +127,8 @@ dependencies {
implementation group: 'org.apache.commons', name: 'commons-lang3', version: '3.12.0'
implementation 'com.h2database:h2-mvstore:2.1.214'
+ implementation group: 'com.github.javakeyring', name: 'java-keyring', version: '1.0.2'
+
// required for reading write-protected PDFs - see https://github.com/JabRef/jabref/pull/942#issuecomment-209252635
implementation 'org.bouncycastle:bcprov-jdk18on:1.74'
From 25d5e7ec27f758e2fbe45c6352680965f67e0d50 Mon Sep 17 00:00:00 2001
From: Carl Christian Snethlage <50491877+calixtus@users.noreply.github.com>
Date: Wed, 28 Jun 2023 14:11:35 +0200
Subject: [PATCH 02/21] Added prefs option
---
.../gui/preferences/general/GeneralTab.fxml | 2 +-
.../gui/preferences/general/GeneralTab.java | 2 ++
.../general/GeneralTabViewModel.java | 7 +++++++
.../jabref/preferences/JabRefPreferences.java | 6 +++++-
.../preferences/WorkspacePreferences.java | 17 ++++++++++++++++-
src/main/resources/l10n/JabRef_en.properties | 2 ++
6 files changed, 33 insertions(+), 3 deletions(-)
diff --git a/src/main/java/org/jabref/gui/preferences/general/GeneralTab.fxml b/src/main/java/org/jabref/gui/preferences/general/GeneralTab.fxml
index 706d9510baf..2685915ced4 100644
--- a/src/main/java/org/jabref/gui/preferences/general/GeneralTab.fxml
+++ b/src/main/java/org/jabref/gui/preferences/general/GeneralTab.fxml
@@ -65,7 +65,7 @@
-
+
diff --git a/src/main/java/org/jabref/gui/preferences/general/GeneralTab.java b/src/main/java/org/jabref/gui/preferences/general/GeneralTab.java
index ecd749be4ca..f709754600f 100644
--- a/src/main/java/org/jabref/gui/preferences/general/GeneralTab.java
+++ b/src/main/java/org/jabref/gui/preferences/general/GeneralTab.java
@@ -42,6 +42,7 @@ public class GeneralTab extends AbstractPreferenceTabView i
@FXML private CheckBox showAdvancedHints;
@FXML private CheckBox inspectionWarningDuplicate;
@FXML private CheckBox confirmDelete;
+ @FXML private CheckBox useKeyring;
@FXML private CheckBox collectTelemetry;
@FXML private ComboBox biblatexMode;
@FXML private CheckBox alwaysReformatBib;
@@ -109,6 +110,7 @@ public void initialize() {
showAdvancedHints.selectedProperty().bindBidirectional(viewModel.showAdvancedHintsProperty());
inspectionWarningDuplicate.selectedProperty().bindBidirectional(viewModel.inspectionWarningDuplicateProperty());
confirmDelete.selectedProperty().bindBidirectional(viewModel.confirmDeleteProperty());
+ useKeyring.selectedProperty().bindBidirectional(viewModel.useKeyringProperty());
collectTelemetry.selectedProperty().bindBidirectional(viewModel.collectTelemetryProperty());
diff --git a/src/main/java/org/jabref/gui/preferences/general/GeneralTabViewModel.java b/src/main/java/org/jabref/gui/preferences/general/GeneralTabViewModel.java
index b7b723046e3..8928fe567b7 100644
--- a/src/main/java/org/jabref/gui/preferences/general/GeneralTabViewModel.java
+++ b/src/main/java/org/jabref/gui/preferences/general/GeneralTabViewModel.java
@@ -76,6 +76,7 @@ public String getDisplayName() {
private final BooleanProperty inspectionWarningDuplicateProperty = new SimpleBooleanProperty();
private final BooleanProperty confirmDeleteProperty = new SimpleBooleanProperty();
+ private final BooleanProperty useKeyringProperty = new SimpleBooleanProperty();
private final BooleanProperty collectTelemetryProperty = new SimpleBooleanProperty();
private final ListProperty bibliographyModeListProperty = new SimpleListProperty<>();
@@ -152,6 +153,7 @@ public void setValues() {
showAdvancedHintsProperty.setValue(workspacePreferences.shouldShowAdvancedHints());
inspectionWarningDuplicateProperty.setValue(workspacePreferences.shouldWarnAboutDuplicatesInInspection());
confirmDeleteProperty.setValue(workspacePreferences.shouldConfirmDelete());
+ useKeyringProperty.setValue(workspacePreferences.shouldUseKeyring());
collectTelemetryProperty.setValue(telemetryPreferences.shouldCollectTelemetry());
@@ -187,6 +189,7 @@ public void storeSettings() {
workspacePreferences.setShowAdvancedHints(showAdvancedHintsProperty.getValue());
workspacePreferences.setWarnAboutDuplicatesInInspection(inspectionWarningDuplicateProperty.getValue());
workspacePreferences.setConfirmDelete(confirmDeleteProperty.getValue());
+ workspacePreferences.setUseKeyring(useKeyringProperty.getValue());
telemetryPreferences.setCollectTelemetry(collectTelemetryProperty.getValue());
@@ -287,6 +290,10 @@ public BooleanProperty confirmDeleteProperty() {
return this.confirmDeleteProperty;
}
+ public BooleanProperty useKeyringProperty() {
+ return this.useKeyringProperty;
+ }
+
public BooleanProperty collectTelemetryProperty() {
return this.collectTelemetryProperty;
}
diff --git a/src/main/java/org/jabref/preferences/JabRefPreferences.java b/src/main/java/org/jabref/preferences/JabRefPreferences.java
index 896b6b6e7ff..040ab4774fd 100644
--- a/src/main/java/org/jabref/preferences/JabRefPreferences.java
+++ b/src/main/java/org/jabref/preferences/JabRefPreferences.java
@@ -271,6 +271,7 @@ public class JabRefPreferences implements PreferencesService {
public static final String DEFAULT_CITATION_KEY_PATTERN = "defaultBibtexKeyPattern";
public static final String UNWANTED_CITATION_KEY_CHARACTERS = "defaultUnwantedBibtexKeyCharacters";
public static final String CONFIRM_DELETE = "confirmDelete";
+ public static final String USE_KEYRING = "useKeyring";
public static final String WARN_BEFORE_OVERWRITING_KEY = "warnBeforeOverwritingKey";
public static final String AVOID_OVERWRITING_KEY = "avoidOverwritingKey";
public static final String AUTOLINK_EXACT_KEY_ONLY = "autolinkExactKeyOnly";
@@ -657,6 +658,7 @@ private JabRefPreferences() {
defaults.put(AVOID_OVERWRITING_KEY, Boolean.FALSE);
defaults.put(WARN_BEFORE_OVERWRITING_KEY, Boolean.TRUE);
defaults.put(CONFIRM_DELETE, Boolean.TRUE);
+ defaults.put(USE_KEYRING, Boolean.FALSE);
defaults.put(DEFAULT_CITATION_KEY_PATTERN, "[auth][year]");
defaults.put(UNWANTED_CITATION_KEY_CHARACTERS, "-`ʹ:!;?^+");
defaults.put(RESOLVE_STRINGS_FOR_FIELDS, "author;booktitle;editor;editora;editorb;editorc;institution;issuetitle;journal;journalsubtitle;journaltitle;mainsubtitle;month;publisher;shortauthor;shorteditor;subtitle;titleaddon");
@@ -2009,7 +2011,8 @@ public WorkspacePreferences getWorkspacePreferences() {
getBoolean(OPEN_LAST_EDITED),
getBoolean(SHOW_ADVANCED_HINTS),
getBoolean(WARN_ABOUT_DUPLICATES_IN_INSPECTION),
- getBoolean(CONFIRM_DELETE));
+ getBoolean(CONFIRM_DELETE),
+ getBoolean(USE_KEYRING));
EasyBind.listen(workspacePreferences.languageProperty(), (obs, oldValue, newValue) -> {
put(LANGUAGE, newValue.getId());
@@ -2025,6 +2028,7 @@ public WorkspacePreferences getWorkspacePreferences() {
EasyBind.listen(workspacePreferences.showAdvancedHintsProperty(), (obs, oldValue, newValue) -> putBoolean(SHOW_ADVANCED_HINTS, newValue));
EasyBind.listen(workspacePreferences.warnAboutDuplicatesInInspectionProperty(), (obs, oldValue, newValue) -> putBoolean(WARN_ABOUT_DUPLICATES_IN_INSPECTION, newValue));
EasyBind.listen(workspacePreferences.confirmDeleteProperty(), (obs, oldValue, newValue) -> putBoolean(CONFIRM_DELETE, newValue));
+ EasyBind.listen(workspacePreferences.useKeyringProperty(), (obs, oldValue, newValue) -> putBoolean(USE_KEYRING, newValue));
return workspacePreferences;
}
diff --git a/src/main/java/org/jabref/preferences/WorkspacePreferences.java b/src/main/java/org/jabref/preferences/WorkspacePreferences.java
index bde96a61704..9c8e44d6829 100644
--- a/src/main/java/org/jabref/preferences/WorkspacePreferences.java
+++ b/src/main/java/org/jabref/preferences/WorkspacePreferences.java
@@ -20,6 +20,7 @@ public class WorkspacePreferences {
private final BooleanProperty showAdvancedHints;
private final BooleanProperty warnAboutDuplicatesInInspection;
private final BooleanProperty confirmDelete;
+ private final BooleanProperty useKeyring;
public WorkspacePreferences(Language language,
boolean shouldOverrideDefaultFontSize,
@@ -29,7 +30,8 @@ public WorkspacePreferences(Language language,
boolean shouldOpenLastEdited,
boolean showAdvancedHints,
boolean warnAboutDuplicatesInInspection,
- boolean confirmDelete) {
+ boolean confirmDelete,
+ boolean useKeyring) {
this.language = new SimpleObjectProperty<>(language);
this.shouldOverrideDefaultFontSize = new SimpleBooleanProperty(shouldOverrideDefaultFontSize);
this.mainFontSize = new SimpleIntegerProperty(mainFontSize);
@@ -39,6 +41,7 @@ public WorkspacePreferences(Language language,
this.showAdvancedHints = new SimpleBooleanProperty(showAdvancedHints);
this.warnAboutDuplicatesInInspection = new SimpleBooleanProperty(warnAboutDuplicatesInInspection);
this.confirmDelete = new SimpleBooleanProperty(confirmDelete);
+ this.useKeyring = new SimpleBooleanProperty(useKeyring);
}
public Language getLanguage() {
@@ -140,4 +143,16 @@ public BooleanProperty confirmDeleteProperty() {
public void setConfirmDelete(boolean confirmDelete) {
this.confirmDelete.set(confirmDelete);
}
+
+ public boolean shouldUseKeyring() {
+ return useKeyring.get();
+ }
+
+ public BooleanProperty useKeyringProperty() {
+ return useKeyring;
+ }
+
+ public void setUseKeyring(boolean useKeyring) {
+ this.useKeyring.set(useKeyring);
+ }
}
diff --git a/src/main/resources/l10n/JabRef_en.properties b/src/main/resources/l10n/JabRef_en.properties
index ab6c8ab5b4a..6d4a4bf73a4 100644
--- a/src/main/resources/l10n/JabRef_en.properties
+++ b/src/main/resources/l10n/JabRef_en.properties
@@ -840,6 +840,8 @@ Show\ BibTeX\ source\ by\ default=Show BibTeX source by default
Show\ confirmation\ dialog\ when\ deleting\ entries=Show confirmation dialog when deleting entries
+Use\ OS\ credential\ store\ to\ store\ custom\ api\ keys\ and\ passwords=Use OS credential store to store custom api keys and passwords
+
Show\ last\ names\ only=Show last names only
Show\ names\ unchanged=Show names unchanged
From 897798ed225571d9cb540f34eea817d591137bd2 Mon Sep 17 00:00:00 2001
From: Carl Christian Snethlage <50491877+calixtus@users.noreply.github.com>
Date: Wed, 28 Jun 2023 15:36:40 +0200
Subject: [PATCH 03/21] Added dependency
---
build.gradle | 2 +-
src/main/java/module-info.java | 2 ++
2 files changed, 3 insertions(+), 1 deletion(-)
diff --git a/build.gradle b/build.gradle
index f1fe7082c4e..ebd827a7784 100644
--- a/build.gradle
+++ b/build.gradle
@@ -127,7 +127,6 @@ dependencies {
implementation group: 'org.apache.commons', name: 'commons-lang3', version: '3.12.0'
implementation 'com.h2database:h2-mvstore:2.1.214'
- implementation group: 'com.github.javakeyring', name: 'java-keyring', version: '1.0.2'
// required for reading write-protected PDFs - see https://github.com/JabRef/jabref/pull/942#issuecomment-209252635
implementation 'org.bouncycastle:bcprov-jdk18on:1.74'
@@ -139,6 +138,7 @@ dependencies {
implementation 'io.github.java-diff-utils:java-diff-utils:4.12'
implementation 'info.debatty:java-string-similarity:2.0.0'
+ implementation 'com.github.javakeyring:java-keyring:1.0.2'
antlr4 'org.antlr:antlr4:4.13.0'
implementation 'org.antlr:antlr4-runtime:4.13.0'
diff --git a/src/main/java/module-info.java b/src/main/java/module-info.java
index 91229649901..2138923ed88 100644
--- a/src/main/java/module-info.java
+++ b/src/main/java/module-info.java
@@ -99,6 +99,8 @@
requires com.h2database.mvstore;
+ requires java.keyring;
+
requires org.jooq.jool;
// fulltext search
From a8c6f3816a4f69c5a4f85cae93d29894f9e6e503 Mon Sep 17 00:00:00 2001
From: Carl Christian Snethlage <50491877+calixtus@users.noreply.github.com>
Date: Wed, 28 Jun 2023 15:37:07 +0200
Subject: [PATCH 04/21] Added test for proxy to JabRefGUI
---
src/main/java/org/jabref/gui/JabRefGUI.java | 39 +++++++++++++++++----
1 file changed, 33 insertions(+), 6 deletions(-)
diff --git a/src/main/java/org/jabref/gui/JabRefGUI.java b/src/main/java/org/jabref/gui/JabRefGUI.java
index 74afaa50314..747de973368 100644
--- a/src/main/java/org/jabref/gui/JabRefGUI.java
+++ b/src/main/java/org/jabref/gui/JabRefGUI.java
@@ -4,6 +4,7 @@
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
+import java.util.Optional;
import java.util.stream.Collectors;
import javafx.application.Platform;
@@ -30,6 +31,8 @@
import org.jabref.preferences.PreferencesService;
import com.airhacks.afterburner.injection.Injector;
+import com.github.javakeyring.Keyring;
+import com.github.javakeyring.PasswordAccessException;
import impl.org.controlsfx.skin.DecorationPane;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -71,13 +74,37 @@ public JabRefGUI(Stage mainStage,
preferencesService.getInternalPreferences())
.checkForNewVersionDelayed();
- if (preferencesService.getProxyPreferences().shouldUseProxy() && preferencesService.getProxyPreferences().shouldUseAuthentication()) {
+ setupProxy();
+ }
+
+ private void setupProxy() {
+ if (!preferencesService.getProxyPreferences().shouldUseProxy() || !preferencesService.getProxyPreferences().shouldUseAuthentication()) {
+ return;
+ }
+
+ if (!preferencesService.getWorkspacePreferences().shouldUseKeyring()) {
DialogService dialogService = Injector.instantiateModelOrService(DialogService.class);
- dialogService.showPasswordDialogAndWait(Localization.lang("Proxy configuration"), Localization.lang("Proxy requires password"), Localization.lang("Password"))
- .ifPresent(newPassword -> {
- preferencesService.getProxyPreferences().setPassword(newPassword);
- ProxyRegisterer.register(preferencesService.getProxyPreferences());
- });
+ Optional password = dialogService.showPasswordDialogAndWait(
+ Localization.lang("Proxy configuration"),
+ Localization.lang("Proxy requires password"),
+ Localization.lang("Password"));
+ if (password.isPresent()) {
+ preferencesService.getProxyPreferences().setPassword(password.get());
+ ProxyRegisterer.register(preferencesService.getProxyPreferences());
+ } else {
+ LOGGER.warn("No proxy password specified");
+ }
+ return;
+ }
+
+ try (final Keyring keyring = Keyring.create()) {
+ String password = keyring.getPassword("org.jabref", "_proxy");
+ preferencesService.getProxyPreferences().setPassword(password);
+ ProxyRegisterer.register(preferencesService.getProxyPreferences());
+ } catch (PasswordAccessException ex) {
+ LOGGER.warn("JabRef uses proxy password from key store but no password is stored");
+ } catch (Exception ex) {
+ LOGGER.warn("JabRef could not open the key store");
}
}
From 4b2c1823e66677dd7115205f04ae140ded7cd1f7 Mon Sep 17 00:00:00 2001
From: Carl Christian Snethlage <50491877+calixtus@users.noreply.github.com>
Date: Wed, 28 Jun 2023 15:45:34 +0200
Subject: [PATCH 05/21] Removed unused code
---
.../jabref/gui/preferences/network/NetworkTabViewModel.java | 5 -----
1 file changed, 5 deletions(-)
diff --git a/src/main/java/org/jabref/gui/preferences/network/NetworkTabViewModel.java b/src/main/java/org/jabref/gui/preferences/network/NetworkTabViewModel.java
index a54c6431159..37b4f0caaf2 100644
--- a/src/main/java/org/jabref/gui/preferences/network/NetworkTabViewModel.java
+++ b/src/main/java/org/jabref/gui/preferences/network/NetworkTabViewModel.java
@@ -194,11 +194,6 @@ public void storeSettings() {
}
private void storeRemoteSettings() {
- RemotePreferences newRemotePreferences = new RemotePreferences(
- remotePreferences.getPort(),
- remoteServerProperty.getValue()
- );
-
getPortAsInt(remotePortProperty.getValue()).ifPresent(newPort -> {
if (remotePreferences.isDifferentPort(newPort)) {
remotePreferences.setPort(newPort);
From cf99af69f369997a4873d0d3e312f97cd136de2c Mon Sep 17 00:00:00 2001
From: Carl Christian Snethlage <50491877+calixtus@users.noreply.github.com>
Date: Wed, 28 Jun 2023 15:58:16 +0200
Subject: [PATCH 06/21] Added network configuration with keyring
---
.../jabref/gui/preferences/network/NetworkTab.java | 1 +
.../org/jabref/preferences/JabRefPreferences.java | 14 ++++++++++++++
2 files changed, 15 insertions(+)
diff --git a/src/main/java/org/jabref/gui/preferences/network/NetworkTab.java b/src/main/java/org/jabref/gui/preferences/network/NetworkTab.java
index 093ac11fd63..2eb1161bee7 100644
--- a/src/main/java/org/jabref/gui/preferences/network/NetworkTab.java
+++ b/src/main/java/org/jabref/gui/preferences/network/NetworkTab.java
@@ -106,6 +106,7 @@ public void initialize() {
proxyPassword.textProperty().bindBidirectional(viewModel.proxyPasswordProperty());
proxyPassword.disableProperty().bind(proxyCustomAndAuthentication.not());
proxyAttentionLabel.disableProperty().bind(proxyCustomAndAuthentication.not());
+ proxyAttentionLabel.visibleProperty().bind(preferencesService.getWorkspacePreferences().useKeyringProperty().not());
proxyPassword.setRight(IconTheme.JabRefIcons.PASSWORD_REVEALED.getGraphicNode());
proxyPassword.getRight().addEventFilter(MouseEvent.MOUSE_PRESSED, this::proxyPasswordReveal);
diff --git a/src/main/java/org/jabref/preferences/JabRefPreferences.java b/src/main/java/org/jabref/preferences/JabRefPreferences.java
index 040ab4774fd..34f0841af27 100644
--- a/src/main/java/org/jabref/preferences/JabRefPreferences.java
+++ b/src/main/java/org/jabref/preferences/JabRefPreferences.java
@@ -113,6 +113,7 @@
import org.jabref.model.search.rules.SearchRules;
import org.jabref.model.strings.StringUtil;
+import com.github.javakeyring.Keyring;
import com.tobiasdiez.easybind.EasyBind;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -1535,6 +1536,19 @@ public ProxyPreferences getProxyPreferences() {
EasyBind.listen(proxyPreferences.portProperty(), (obs, oldValue, newValue) -> put(PROXY_PORT, newValue));
EasyBind.listen(proxyPreferences.useAuthenticationProperty(), (obs, oldValue, newValue) -> putBoolean(PROXY_USE_AUTHENTICATION, newValue));
EasyBind.listen(proxyPreferences.usernameProperty(), (obs, oldValue, newValue) -> put(PROXY_USERNAME, newValue));
+ EasyBind.listen(proxyPreferences.passwordProperty(), (obs, oldValue, newValue) -> {
+ if (getWorkspacePreferences().shouldUseKeyring()) {
+ try (final Keyring keyring = Keyring.create()) {
+ if (StringUtil.isBlank(newValue)) {
+ keyring.deletePassword("org.jabref", "proxy");
+ } else {
+ keyring.setPassword("org.jabref", "proxy", newValue.trim());
+ }
+ } catch (Exception ex) {
+ LOGGER.error("Unable to open key store");
+ }
+ }
+ });
return proxyPreferences;
}
From 9099ca5e2f2ea8a1f3a31b614e09e7173e9b3591 Mon Sep 17 00:00:00 2001
From: Carl Christian Snethlage <50491877+calixtus@users.noreply.github.com>
Date: Wed, 28 Jun 2023 17:07:38 +0200
Subject: [PATCH 07/21] Added custom api key storage in keyring
---
.../jabref/preferences/JabRefPreferences.java | 65 ++++++++++++++++++-
1 file changed, 63 insertions(+), 2 deletions(-)
diff --git a/src/main/java/org/jabref/preferences/JabRefPreferences.java b/src/main/java/org/jabref/preferences/JabRefPreferences.java
index 34f0841af27..71af8508a95 100644
--- a/src/main/java/org/jabref/preferences/JabRefPreferences.java
+++ b/src/main/java/org/jabref/preferences/JabRefPreferences.java
@@ -114,6 +114,7 @@
import org.jabref.model.strings.StringUtil;
import com.github.javakeyring.Keyring;
+import com.github.javakeyring.PasswordAccessException;
import com.tobiasdiez.easybind.EasyBind;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -981,6 +982,7 @@ public void clear() throws BackingStoreException {
clearAllBibEntryTypes();
clearCitationKeyPatterns();
clearTruststoreFromCustomCertificates();
+ clearCustomFetcherKeys();
prefs.clear();
new SharedDatabasePreferences().clear();
}
@@ -2777,7 +2779,9 @@ private Set getFetcherKeys() {
List names = getStringList(FETCHER_CUSTOM_KEY_NAMES);
List uses = getStringList(FETCHER_CUSTOM_KEY_USES);
- List keys = getStringList(FETCHER_CUSTOM_KEYS);
+ List keys = getWorkspacePreferences().shouldUseKeyring()
+ ? getFetcherKeysFromKeyring(names)
+ : getStringList(FETCHER_CUSTOM_KEYS);
for (int i = 0; i < names.size(); i++) {
fetcherApiKeys.add(new FetcherApiKey(
@@ -2790,6 +2794,25 @@ private Set getFetcherKeys() {
return fetcherApiKeys;
}
+ private List getFetcherKeysFromKeyring(List names) {
+ List keys = new ArrayList<>();
+
+ try (final Keyring keyring = Keyring.create()) {
+ for (String fetcher : names) {
+ try {
+ keys.add(keyring.getPassword("org.jabref.customapikeys", fetcher));
+ } catch (PasswordAccessException ex) {
+ LOGGER.warn("No api key stored for {} fetcher", fetcher);
+ keys.add("");
+ }
+ }
+ } catch (Exception ex) {
+ LOGGER.warn("JabRef could not open the key store");
+ }
+
+ return keys;
+ }
+
private void storeFetcherKeys(Set fetcherApiKeys) {
List names = new ArrayList<>();
List uses = new ArrayList<>();
@@ -2803,7 +2826,45 @@ private void storeFetcherKeys(Set fetcherApiKeys) {
putStringList(FETCHER_CUSTOM_KEY_NAMES, names);
putStringList(FETCHER_CUSTOM_KEY_USES, uses);
- putStringList(FETCHER_CUSTOM_KEYS, keys);
+ if (getWorkspacePreferences().shouldUseKeyring()) {
+ storeFetcherKeysToKeyring(names, keys);
+ } else {
+ putStringList(FETCHER_CUSTOM_KEYS, keys);
+ }
+ }
+
+ private void storeFetcherKeysToKeyring(List names, List keys) {
+ try (final Keyring keyring = Keyring.create()) {
+ for (int i = 0; i < names.size(); i++) {
+ if (StringUtil.isNullOrEmpty(keys.get(i))) {
+ try {
+ keyring.deletePassword("org.jabref.customapikeys", names.get(i));
+ } catch (PasswordAccessException ex) {
+ // Already removed
+ }
+ } else {
+ keyring.setPassword("org.jabref.customapikeys", names.get(i), keys.get(i));
+ }
+ }
+ } catch (Exception ex) {
+ LOGGER.error("Unable to open key store");
+ }
+ }
+
+ /**
+ * Clears the custom fetcher keys in the backing store and in the credential store
+ */
+ private void clearCustomFetcherKeys() {
+ put(FETCHER_CUSTOM_KEYS, "");
+
+ List names = getStringList(FETCHER_CUSTOM_KEY_NAMES);
+ try (final Keyring keyring = Keyring.create()) {
+ for (String name : names) {
+ keyring.deletePassword("org.jabref.customapikeys", name);
+ }
+ } catch (Exception ex) {
+ LOGGER.error("Unable to open key store");
+ }
}
@Override
From 50a97efe027b8c5c6a7c504b9916950e39786ecd Mon Sep 17 00:00:00 2001
From: Carl Christian Snethlage <50491877+calixtus@users.noreply.github.com>
Date: Wed, 28 Jun 2023 17:34:11 +0200
Subject: [PATCH 08/21] Enhanced security of the proxy password
---
src/main/java/org/jabref/gui/JabRefGUI.java | 6 +++++-
src/main/java/org/jabref/preferences/JabRefPreferences.java | 6 +++++-
2 files changed, 10 insertions(+), 2 deletions(-)
diff --git a/src/main/java/org/jabref/gui/JabRefGUI.java b/src/main/java/org/jabref/gui/JabRefGUI.java
index 747de973368..699fc339412 100644
--- a/src/main/java/org/jabref/gui/JabRefGUI.java
+++ b/src/main/java/org/jabref/gui/JabRefGUI.java
@@ -25,6 +25,7 @@
import org.jabref.logic.shared.DatabaseNotSupportedException;
import org.jabref.logic.shared.exception.InvalidDBMSConnectionPropertiesException;
import org.jabref.logic.shared.exception.NotASharedDatabaseException;
+import org.jabref.logic.shared.security.Password;
import org.jabref.logic.util.WebViewStore;
import org.jabref.model.util.FileUpdateMonitor;
import org.jabref.preferences.GuiPreferences;
@@ -98,7 +99,10 @@ private void setupProxy() {
}
try (final Keyring keyring = Keyring.create()) {
- String password = keyring.getPassword("org.jabref", "_proxy");
+ String password = new Password(
+ keyring.getPassword("org.jabref", "proxy"),
+ preferencesService.getProxyPreferences().getUsername())
+ .decrypt();
preferencesService.getProxyPreferences().setPassword(password);
ProxyRegisterer.register(preferencesService.getProxyPreferences());
} catch (PasswordAccessException ex) {
diff --git a/src/main/java/org/jabref/preferences/JabRefPreferences.java b/src/main/java/org/jabref/preferences/JabRefPreferences.java
index 71af8508a95..9b2abd07072 100644
--- a/src/main/java/org/jabref/preferences/JabRefPreferences.java
+++ b/src/main/java/org/jabref/preferences/JabRefPreferences.java
@@ -94,6 +94,7 @@
import org.jabref.logic.protectedterms.ProtectedTermsPreferences;
import org.jabref.logic.remote.RemotePreferences;
import org.jabref.logic.shared.prefs.SharedDatabasePreferences;
+import org.jabref.logic.shared.security.Password;
import org.jabref.logic.util.OS;
import org.jabref.logic.util.Version;
import org.jabref.logic.util.io.AutoLinkPreferences;
@@ -1544,7 +1545,10 @@ public ProxyPreferences getProxyPreferences() {
if (StringUtil.isBlank(newValue)) {
keyring.deletePassword("org.jabref", "proxy");
} else {
- keyring.setPassword("org.jabref", "proxy", newValue.trim());
+ keyring.setPassword("org.jabref", "proxy", new Password(
+ newValue.trim(),
+ proxyPreferences.getUsername())
+ .encrypt());
}
} catch (Exception ex) {
LOGGER.error("Unable to open key store");
From 79c9f91e749e3644b79200b3bcf9666ea4247cdb Mon Sep 17 00:00:00 2001
From: Carl Christian Snethlage <50491877+calixtus@users.noreply.github.com>
Date: Wed, 28 Jun 2023 17:40:51 +0200
Subject: [PATCH 09/21] Enhanced security of the custom api keys
---
.../java/org/jabref/preferences/JabRefPreferences.java | 10 ++++++++--
1 file changed, 8 insertions(+), 2 deletions(-)
diff --git a/src/main/java/org/jabref/preferences/JabRefPreferences.java b/src/main/java/org/jabref/preferences/JabRefPreferences.java
index 9b2abd07072..a70ce944aa9 100644
--- a/src/main/java/org/jabref/preferences/JabRefPreferences.java
+++ b/src/main/java/org/jabref/preferences/JabRefPreferences.java
@@ -2804,7 +2804,10 @@ private List getFetcherKeysFromKeyring(List names) {
try (final Keyring keyring = Keyring.create()) {
for (String fetcher : names) {
try {
- keys.add(keyring.getPassword("org.jabref.customapikeys", fetcher));
+ keys.add(new Password(
+ keyring.getPassword("org.jabref.customapikeys", fetcher),
+ getInternalPreferences().getUserAndHost())
+ .decrypt());
} catch (PasswordAccessException ex) {
LOGGER.warn("No api key stored for {} fetcher", fetcher);
keys.add("");
@@ -2847,7 +2850,10 @@ private void storeFetcherKeysToKeyring(List names, List keys) {
// Already removed
}
} else {
- keyring.setPassword("org.jabref.customapikeys", names.get(i), keys.get(i));
+ keyring.setPassword("org.jabref.customapikeys", names.get(i), new Password(
+ keys.get(i),
+ getInternalPreferences().getUserAndHost())
+ .encrypt());
}
}
} catch (Exception ex) {
From 0bb364e53949bb58946cb4340f5051f61dc38afb Mon Sep 17 00:00:00 2001
From: Carl Christian Snethlage <50491877+calixtus@users.noreply.github.com>
Date: Wed, 28 Jun 2023 17:51:15 +0200
Subject: [PATCH 10/21] Refined preferences option
---
.../java/org/jabref/gui/preferences/general/GeneralTab.fxml | 2 +-
src/main/resources/l10n/JabRef_en.properties | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/main/java/org/jabref/gui/preferences/general/GeneralTab.fxml b/src/main/java/org/jabref/gui/preferences/general/GeneralTab.fxml
index 2685915ced4..d0cb34c1a2d 100644
--- a/src/main/java/org/jabref/gui/preferences/general/GeneralTab.fxml
+++ b/src/main/java/org/jabref/gui/preferences/general/GeneralTab.fxml
@@ -65,7 +65,7 @@
-
+
diff --git a/src/main/resources/l10n/JabRef_en.properties b/src/main/resources/l10n/JabRef_en.properties
index 6d4a4bf73a4..e510c777da6 100644
--- a/src/main/resources/l10n/JabRef_en.properties
+++ b/src/main/resources/l10n/JabRef_en.properties
@@ -840,7 +840,7 @@ Show\ BibTeX\ source\ by\ default=Show BibTeX source by default
Show\ confirmation\ dialog\ when\ deleting\ entries=Show confirmation dialog when deleting entries
-Use\ OS\ credential\ store\ to\ store\ custom\ api\ keys\ and\ passwords=Use OS credential store to store custom api keys and passwords
+Use\ OS\ credential\ store\ to\ store\ custom\ api\ keys\ and\ passwords\ (save\ and\ reopen\ preferences\ required)=Use OS credential store to store custom api keys and passwords (save and reopen preferences required)
Show\ last\ names\ only=Show last names only
From d89c3a85ba108da4e3087f017f4723ef72ec61ac Mon Sep 17 00:00:00 2001
From: Carl Christian Snethlage <50491877+calixtus@users.noreply.github.com>
Date: Wed, 28 Jun 2023 18:11:33 +0200
Subject: [PATCH 11/21] CHANGELOG.md
---
CHANGELOG.md | 1 +
build.gradle | 1 -
2 files changed, 1 insertion(+), 1 deletion(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 284a9311440..97dea627f3a 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -36,6 +36,7 @@ Note that this project **does not** adhere to [Semantic Versioning](http://semve
- We enabled the user to change the name of a field in a custom entry type by double-clicking on it. [#9840](https://github.com/JabRef/jabref/issues/9840)
- We integrated two mail actions ("As Email" and "To Kindle") under a new "Send" option in the right-click & Tools menus. The Kindle option creates an email targeted to the user's Kindle email, which can be set in preferences under "External programs" [#6186](https://github.com/JabRef/jabref/issues/6186)
- We added an option to clear recent libraries' history. [#10003](https://github.com/JabRef/jabref/issues/10003)
+- We added an option to encrypt and remember the proxy password and the custom api keys between sessions. [#10044](https://github.com/JabRef/jabref/issues/10044)
### Changed
diff --git a/build.gradle b/build.gradle
index ebd827a7784..be98d90ab07 100644
--- a/build.gradle
+++ b/build.gradle
@@ -127,7 +127,6 @@ dependencies {
implementation group: 'org.apache.commons', name: 'commons-lang3', version: '3.12.0'
implementation 'com.h2database:h2-mvstore:2.1.214'
-
// required for reading write-protected PDFs - see https://github.com/JabRef/jabref/pull/942#issuecomment-209252635
implementation 'org.bouncycastle:bcprov-jdk18on:1.74'
From 662c18c003a983f7d9f222777b68f035d5d09d78 Mon Sep 17 00:00:00 2001
From: Carl Christian Snethlage <50491877+calixtus@users.noreply.github.com>
Date: Wed, 28 Jun 2023 19:37:50 +0200
Subject: [PATCH 12/21] checkstyle
---
CHANGELOG.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 97dea627f3a..78112de74ed 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -36,7 +36,7 @@ Note that this project **does not** adhere to [Semantic Versioning](http://semve
- We enabled the user to change the name of a field in a custom entry type by double-clicking on it. [#9840](https://github.com/JabRef/jabref/issues/9840)
- We integrated two mail actions ("As Email" and "To Kindle") under a new "Send" option in the right-click & Tools menus. The Kindle option creates an email targeted to the user's Kindle email, which can be set in preferences under "External programs" [#6186](https://github.com/JabRef/jabref/issues/6186)
- We added an option to clear recent libraries' history. [#10003](https://github.com/JabRef/jabref/issues/10003)
-- We added an option to encrypt and remember the proxy password and the custom api keys between sessions. [#10044](https://github.com/JabRef/jabref/issues/10044)
+- We added an option to encrypt and remember the proxy password and the custom api keys between sessions. [#10044](https://github.com/JabRef/jabref/issues/10044)
### Changed
From 9a0e88f553de0655f4ce2ba45a20e9b044264fd1 Mon Sep 17 00:00:00 2001
From: Carl Christian Snethlage <50491877+calixtus@users.noreply.github.com>
Date: Thu, 29 Jun 2023 13:27:48 +0200
Subject: [PATCH 13/21] Implement discussion decisions
---
src/main/java/org/jabref/gui/JabRefGUI.java | 2 +-
.../gui/preferences/general/GeneralTab.fxml | 1 -
.../gui/preferences/general/GeneralTab.java | 2 -
.../general/GeneralTabViewModel.java | 7 ---
.../gui/preferences/network/NetworkTab.fxml | 2 +-
.../gui/preferences/network/NetworkTab.java | 6 +-
.../network/NetworkTabViewModel.java | 62 +++++++------------
.../jabref/logic/net/ProxyPreferences.java | 27 ++++++--
.../jabref/preferences/JabRefPreferences.java | 37 ++++++-----
.../preferences/WorkspacePreferences.java | 17 +----
src/main/resources/l10n/JabRef_en.properties | 2 +-
.../java/org/jabref/logic/net/ProxyTest.java | 11 +++-
12 files changed, 78 insertions(+), 98 deletions(-)
diff --git a/src/main/java/org/jabref/gui/JabRefGUI.java b/src/main/java/org/jabref/gui/JabRefGUI.java
index 699fc339412..531a776e6c1 100644
--- a/src/main/java/org/jabref/gui/JabRefGUI.java
+++ b/src/main/java/org/jabref/gui/JabRefGUI.java
@@ -83,7 +83,7 @@ private void setupProxy() {
return;
}
- if (!preferencesService.getWorkspacePreferences().shouldUseKeyring()) {
+ if (!preferencesService.getProxyPreferences().shouldPersistPassword()) {
DialogService dialogService = Injector.instantiateModelOrService(DialogService.class);
Optional password = dialogService.showPasswordDialogAndWait(
Localization.lang("Proxy configuration"),
diff --git a/src/main/java/org/jabref/gui/preferences/general/GeneralTab.fxml b/src/main/java/org/jabref/gui/preferences/general/GeneralTab.fxml
index d0cb34c1a2d..60892aea5cf 100644
--- a/src/main/java/org/jabref/gui/preferences/general/GeneralTab.fxml
+++ b/src/main/java/org/jabref/gui/preferences/general/GeneralTab.fxml
@@ -65,7 +65,6 @@
-
diff --git a/src/main/java/org/jabref/gui/preferences/general/GeneralTab.java b/src/main/java/org/jabref/gui/preferences/general/GeneralTab.java
index f709754600f..ecd749be4ca 100644
--- a/src/main/java/org/jabref/gui/preferences/general/GeneralTab.java
+++ b/src/main/java/org/jabref/gui/preferences/general/GeneralTab.java
@@ -42,7 +42,6 @@ public class GeneralTab extends AbstractPreferenceTabView i
@FXML private CheckBox showAdvancedHints;
@FXML private CheckBox inspectionWarningDuplicate;
@FXML private CheckBox confirmDelete;
- @FXML private CheckBox useKeyring;
@FXML private CheckBox collectTelemetry;
@FXML private ComboBox biblatexMode;
@FXML private CheckBox alwaysReformatBib;
@@ -110,7 +109,6 @@ public void initialize() {
showAdvancedHints.selectedProperty().bindBidirectional(viewModel.showAdvancedHintsProperty());
inspectionWarningDuplicate.selectedProperty().bindBidirectional(viewModel.inspectionWarningDuplicateProperty());
confirmDelete.selectedProperty().bindBidirectional(viewModel.confirmDeleteProperty());
- useKeyring.selectedProperty().bindBidirectional(viewModel.useKeyringProperty());
collectTelemetry.selectedProperty().bindBidirectional(viewModel.collectTelemetryProperty());
diff --git a/src/main/java/org/jabref/gui/preferences/general/GeneralTabViewModel.java b/src/main/java/org/jabref/gui/preferences/general/GeneralTabViewModel.java
index 8928fe567b7..b7b723046e3 100644
--- a/src/main/java/org/jabref/gui/preferences/general/GeneralTabViewModel.java
+++ b/src/main/java/org/jabref/gui/preferences/general/GeneralTabViewModel.java
@@ -76,7 +76,6 @@ public String getDisplayName() {
private final BooleanProperty inspectionWarningDuplicateProperty = new SimpleBooleanProperty();
private final BooleanProperty confirmDeleteProperty = new SimpleBooleanProperty();
- private final BooleanProperty useKeyringProperty = new SimpleBooleanProperty();
private final BooleanProperty collectTelemetryProperty = new SimpleBooleanProperty();
private final ListProperty bibliographyModeListProperty = new SimpleListProperty<>();
@@ -153,7 +152,6 @@ public void setValues() {
showAdvancedHintsProperty.setValue(workspacePreferences.shouldShowAdvancedHints());
inspectionWarningDuplicateProperty.setValue(workspacePreferences.shouldWarnAboutDuplicatesInInspection());
confirmDeleteProperty.setValue(workspacePreferences.shouldConfirmDelete());
- useKeyringProperty.setValue(workspacePreferences.shouldUseKeyring());
collectTelemetryProperty.setValue(telemetryPreferences.shouldCollectTelemetry());
@@ -189,7 +187,6 @@ public void storeSettings() {
workspacePreferences.setShowAdvancedHints(showAdvancedHintsProperty.getValue());
workspacePreferences.setWarnAboutDuplicatesInInspection(inspectionWarningDuplicateProperty.getValue());
workspacePreferences.setConfirmDelete(confirmDeleteProperty.getValue());
- workspacePreferences.setUseKeyring(useKeyringProperty.getValue());
telemetryPreferences.setCollectTelemetry(collectTelemetryProperty.getValue());
@@ -290,10 +287,6 @@ public BooleanProperty confirmDeleteProperty() {
return this.confirmDeleteProperty;
}
- public BooleanProperty useKeyringProperty() {
- return this.useKeyringProperty;
- }
-
public BooleanProperty collectTelemetryProperty() {
return this.collectTelemetryProperty;
}
diff --git a/src/main/java/org/jabref/gui/preferences/network/NetworkTab.fxml b/src/main/java/org/jabref/gui/preferences/network/NetworkTab.fxml
index a7851acdbb2..7817d437c75 100644
--- a/src/main/java/org/jabref/gui/preferences/network/NetworkTab.fxml
+++ b/src/main/java/org/jabref/gui/preferences/network/NetworkTab.fxml
@@ -50,7 +50,7 @@
-
+
diff --git a/src/main/java/org/jabref/gui/preferences/network/NetworkTab.java b/src/main/java/org/jabref/gui/preferences/network/NetworkTab.java
index 2eb1161bee7..19c3425edd0 100644
--- a/src/main/java/org/jabref/gui/preferences/network/NetworkTab.java
+++ b/src/main/java/org/jabref/gui/preferences/network/NetworkTab.java
@@ -50,8 +50,8 @@ public class NetworkTab extends AbstractPreferenceTabView i
@FXML private TextField proxyUsername;
@FXML private Label proxyPasswordLabel;
@FXML private CustomPasswordField proxyPassword;
- @FXML private Label proxyAttentionLabel;
@FXML private Button checkConnectionButton;
+ @FXML private CheckBox proxyPersistPassword;
@FXML private TableView customCertificatesTable;
@FXML private TableColumn certIssuer;
@@ -105,8 +105,8 @@ public void initialize() {
proxyPasswordLabel.disableProperty().bind(proxyCustomAndAuthentication.not());
proxyPassword.textProperty().bindBidirectional(viewModel.proxyPasswordProperty());
proxyPassword.disableProperty().bind(proxyCustomAndAuthentication.not());
- proxyAttentionLabel.disableProperty().bind(proxyCustomAndAuthentication.not());
- proxyAttentionLabel.visibleProperty().bind(preferencesService.getWorkspacePreferences().useKeyringProperty().not());
+ proxyPersistPassword.selectedProperty().bindBidirectional(viewModel.proxyPersistPasswordProperty());
+ proxyPersistPassword.disableProperty().bind(proxyCustomAndAuthentication.not());
proxyPassword.setRight(IconTheme.JabRefIcons.PASSWORD_REVEALED.getGraphicNode());
proxyPassword.getRight().addEventFilter(MouseEvent.MOUSE_PRESSED, this::proxyPasswordReveal);
diff --git a/src/main/java/org/jabref/gui/preferences/network/NetworkTabViewModel.java b/src/main/java/org/jabref/gui/preferences/network/NetworkTabViewModel.java
index 37b4f0caaf2..1379d5ebbe2 100644
--- a/src/main/java/org/jabref/gui/preferences/network/NetworkTabViewModel.java
+++ b/src/main/java/org/jabref/gui/preferences/network/NetworkTabViewModel.java
@@ -4,7 +4,6 @@
import java.nio.file.Path;
import java.util.Collections;
import java.util.List;
-import java.util.Objects;
import java.util.Optional;
import java.util.concurrent.atomic.AtomicBoolean;
@@ -43,12 +42,8 @@
import de.saxsys.mvvmfx.utils.validation.ValidationStatus;
import de.saxsys.mvvmfx.utils.validation.Validator;
import kong.unirest.UnirestException;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
public class NetworkTabViewModel implements PreferenceTabViewModel {
- private static final Logger LOGGER = LoggerFactory.getLogger(NetworkTabViewModel.class);
-
private final BooleanProperty remoteServerProperty = new SimpleBooleanProperty();
private final StringProperty remotePortProperty = new SimpleStringProperty("");
private final BooleanProperty proxyUseProperty = new SimpleBooleanProperty();
@@ -57,6 +52,7 @@ public class NetworkTabViewModel implements PreferenceTabViewModel {
private final BooleanProperty proxyUseAuthenticationProperty = new SimpleBooleanProperty();
private final StringProperty proxyUsernameProperty = new SimpleStringProperty("");
private final StringProperty proxyPasswordProperty = new SimpleStringProperty("");
+ private final BooleanProperty proxyPersistPasswordProperty = new SimpleBooleanProperty();
private final ListProperty customCertificateListProperty = new SimpleListProperty<>(FXCollections.observableArrayList());
private final Validator remotePortValidator;
@@ -92,7 +88,8 @@ public NetworkTabViewModel(DialogService dialogService, PreferencesService prefe
proxyPreferences.getPort(),
proxyPreferences.shouldUseAuthentication(),
proxyPreferences.getUsername(),
- proxyPreferences.getPassword());
+ proxyPreferences.getPassword(),
+ proxyPreferences.shouldPersistPassword());
remotePortValidator = new FunctionBasedValidator<>(
remotePortProperty,
@@ -140,6 +137,7 @@ public NetworkTabViewModel(DialogService dialogService, PreferencesService prefe
Localization.lang("Network"),
Localization.lang("Proxy configuration"),
Localization.lang("Please specify a password"))));
+
this.trustStoreManager = new TrustStoreManager(Path.of(sslPreferences.getTruststorePath()));
}
@@ -159,6 +157,7 @@ private void setProxyValues() {
proxyUseAuthenticationProperty.setValue(proxyPreferences.shouldUseAuthentication());
proxyUsernameProperty.setValue(proxyPreferences.getUsername());
proxyPasswordProperty.setValue(proxyPreferences.getPassword());
+ proxyPersistPasswordProperty.setValue(proxyPreferences.shouldPersistPassword());
}
private void setSSLValues() {
@@ -181,19 +180,6 @@ private void setSSLValues() {
@Override
public void storeSettings() {
- storeRemoteSettings();
- storeProxySettings(new ProxyPreferences(
- proxyUseProperty.getValue(),
- proxyHostnameProperty.getValue().trim(),
- proxyPortProperty.getValue().trim(),
- proxyUseAuthenticationProperty.getValue(),
- proxyUsernameProperty.getValue().trim(),
- proxyPasswordProperty.getValue()
- ));
- storeSSLSettings();
- }
-
- private void storeRemoteSettings() {
getPortAsInt(remotePortProperty.getValue()).ifPresent(newPort -> {
if (remotePreferences.isDifferentPort(newPort)) {
remotePreferences.setPort(newPort);
@@ -207,25 +193,16 @@ private void storeRemoteSettings() {
remotePreferences.setUseRemoteServer(false);
Globals.REMOTE_LISTENER.stop();
}
- }
-
- private void storeProxySettings(ProxyPreferences newProxyPreferences) {
- if (Objects.equals(newProxyPreferences, proxyPreferences)) {
- // nothing changed; thus, nothing to store
- return;
- }
- ProxyRegisterer.register(newProxyPreferences);
+ proxyPreferences.setUseProxy(proxyUseProperty.getValue());
+ proxyPreferences.setHostname(proxyHostnameProperty.getValue().trim());
+ proxyPreferences.setPort(proxyPortProperty.getValue().trim());
+ proxyPreferences.setUseAuthentication(proxyUseAuthenticationProperty.getValue());
+ proxyPreferences.setUsername(proxyUsernameProperty.getValue().trim());
+ proxyPreferences.setPersistPassword(proxyPersistPasswordProperty.getValue()); // Set before the password to actually persist
+ proxyPreferences.setPassword(proxyPasswordProperty.getValue());
+ ProxyRegisterer.register(proxyPreferences);
- proxyPreferences.setUseProxy(newProxyPreferences.shouldUseProxy());
- proxyPreferences.setHostname(newProxyPreferences.getHostname());
- proxyPreferences.setPort(newProxyPreferences.getPort());
- proxyPreferences.setUseAuthentication(newProxyPreferences.shouldUseAuthentication());
- proxyPreferences.setUsername(newProxyPreferences.getUsername());
- proxyPreferences.setPassword(newProxyPreferences.getPassword());
- }
-
- public void storeSSLSettings() {
trustStoreManager.flush();
}
@@ -294,15 +271,14 @@ public void checkConnection() {
final String testUrl = "http://jabref.org";
- // Workaround for testing, since the URLDownload uses stored proxy settings, see
- // preferences.storeProxyPreferences(...) below.
- storeProxySettings(new ProxyPreferences(
+ ProxyRegisterer.register(new ProxyPreferences(
proxyUseProperty.getValue(),
proxyHostnameProperty.getValue().trim(),
proxyPortProperty.getValue().trim(),
proxyUseAuthenticationProperty.getValue(),
proxyUsernameProperty.getValue().trim(),
- proxyPasswordProperty.getValue()
+ proxyPasswordProperty.getValue(),
+ proxyPersistPasswordProperty.getValue()
));
URLDownload urlDownload;
@@ -319,7 +295,7 @@ public void checkConnection() {
dialogService.showErrorDialogAndWait(dialogTitle, connectionFailedText);
}
- storeProxySettings(backupProxyPreferences);
+ ProxyRegisterer.register(backupProxyPreferences);
}
@Override
@@ -363,6 +339,10 @@ public StringProperty proxyPasswordProperty() {
return proxyPasswordProperty;
}
+ public BooleanProperty proxyPersistPasswordProperty() {
+ return proxyPersistPasswordProperty;
+ }
+
public ListProperty customCertificateListProperty() {
return customCertificateListProperty;
}
diff --git a/src/main/java/org/jabref/logic/net/ProxyPreferences.java b/src/main/java/org/jabref/logic/net/ProxyPreferences.java
index 5479e6beb72..7a010420b7e 100644
--- a/src/main/java/org/jabref/logic/net/ProxyPreferences.java
+++ b/src/main/java/org/jabref/logic/net/ProxyPreferences.java
@@ -15,22 +15,25 @@ public class ProxyPreferences {
private final BooleanProperty useAuthentication;
private final StringProperty username;
private final StringProperty password;
+ private final BooleanProperty persistPassword;
public ProxyPreferences(Boolean useProxy,
String hostname,
String port,
Boolean useAuthentication,
String username,
- String password) {
+ String password,
+ boolean persistPassword) {
this.useProxy = new SimpleBooleanProperty(useProxy);
this.hostname = new SimpleStringProperty(hostname);
this.port = new SimpleStringProperty(port);
this.useAuthentication = new SimpleBooleanProperty(useAuthentication);
this.username = new SimpleStringProperty(username);
this.password = new SimpleStringProperty(password);
+ this.persistPassword = new SimpleBooleanProperty(persistPassword);
}
- public final Boolean shouldUseProxy() {
+ public final boolean shouldUseProxy() {
return useProxy.getValue();
}
@@ -66,7 +69,7 @@ public void setPort(String port) {
this.port.set(port);
}
- public final Boolean shouldUseAuthentication() {
+ public final boolean shouldUseAuthentication() {
return useAuthentication.getValue();
}
@@ -102,6 +105,18 @@ public void setPassword(String password) {
this.password.set(password);
}
+ public boolean shouldPersistPassword() {
+ return persistPassword.getValue();
+ }
+
+ public BooleanProperty persistPasswordProperty() {
+ return persistPassword;
+ }
+
+ public void setPersistPassword(boolean persistPassword) {
+ this.persistPassword.set(persistPassword);
+ }
+
@Override
public boolean equals(Object o) {
if (this == o) {
@@ -118,7 +133,8 @@ public boolean equals(Object o) {
&& Objects.equals(port.getValue(), other.port.getValue())
&& Objects.equals(useAuthentication.getValue(), other.useAuthentication.getValue())
&& Objects.equals(username.getValue(), other.username.getValue())
- && Objects.equals(password.getValue(), other.password.getValue());
+ && Objects.equals(password.getValue(), other.password.getValue())
+ && Objects.equals(persistPassword.getValue(), other.persistPassword.getValue());
}
@Override
@@ -129,6 +145,7 @@ public int hashCode() {
port.getValue(),
useAuthentication.getValue(),
username.getValue(),
- password.getValue());
+ password.getValue(),
+ persistPassword.getValue());
}
}
diff --git a/src/main/java/org/jabref/preferences/JabRefPreferences.java b/src/main/java/org/jabref/preferences/JabRefPreferences.java
index a70ce944aa9..aff292e1203 100644
--- a/src/main/java/org/jabref/preferences/JabRefPreferences.java
+++ b/src/main/java/org/jabref/preferences/JabRefPreferences.java
@@ -274,7 +274,6 @@ public class JabRefPreferences implements PreferencesService {
public static final String DEFAULT_CITATION_KEY_PATTERN = "defaultBibtexKeyPattern";
public static final String UNWANTED_CITATION_KEY_CHARACTERS = "defaultUnwantedBibtexKeyCharacters";
public static final String CONFIRM_DELETE = "confirmDelete";
- public static final String USE_KEYRING = "useKeyring";
public static final String WARN_BEFORE_OVERWRITING_KEY = "warnBeforeOverwritingKey";
public static final String AVOID_OVERWRITING_KEY = "avoidOverwritingKey";
public static final String AUTOLINK_EXACT_KEY_ONLY = "autolinkExactKeyOnly";
@@ -360,9 +359,10 @@ public class JabRefPreferences implements PreferencesService {
private static final String PROXY_PORT = "proxyPort";
private static final String PROXY_HOSTNAME = "proxyHostname";
private static final String PROXY_USE = "useProxy";
+ private static final String PROXY_USE_AUTHENTICATION = "useProxyAuthentication";
private static final String PROXY_USERNAME = "proxyUsername";
private static final String PROXY_PASSWORD = "proxyPassword";
- private static final String PROXY_USE_AUTHENTICATION = "useProxyAuthentication";
+ private static final String PROXY_PERSIST_PASSWORD = "persistPassword";
// SSL
private static final String TRUSTSTORE_PATH = "truststorePath";
@@ -541,6 +541,7 @@ private JabRefPreferences() {
defaults.put(PROXY_USE_AUTHENTICATION, Boolean.FALSE);
defaults.put(PROXY_USERNAME, "");
defaults.put(PROXY_PASSWORD, "");
+ defaults.put(PROXY_PERSIST_PASSWORD, Boolean.FALSE);
// SSL
defaults.put(TRUSTSTORE_PATH, OS.getNativeDesktop()
@@ -661,7 +662,6 @@ private JabRefPreferences() {
defaults.put(AVOID_OVERWRITING_KEY, Boolean.FALSE);
defaults.put(WARN_BEFORE_OVERWRITING_KEY, Boolean.TRUE);
defaults.put(CONFIRM_DELETE, Boolean.TRUE);
- defaults.put(USE_KEYRING, Boolean.FALSE);
defaults.put(DEFAULT_CITATION_KEY_PATTERN, "[auth][year]");
defaults.put(UNWANTED_CITATION_KEY_CHARACTERS, "-`ʹ:!;?^+");
defaults.put(RESOLVE_STRINGS_FOR_FIELDS, "author;booktitle;editor;editora;editorb;editorc;institution;issuetitle;journal;journalsubtitle;journaltitle;mainsubtitle;month;publisher;shortauthor;shorteditor;subtitle;titleaddon");
@@ -1532,7 +1532,8 @@ public ProxyPreferences getProxyPreferences() {
get(PROXY_PORT),
getBoolean(PROXY_USE_AUTHENTICATION),
get(PROXY_USERNAME),
- (String) defaults.get(PROXY_PASSWORD));
+ (String) defaults.get(PROXY_PASSWORD),
+ getBoolean(PROXY_PERSIST_PASSWORD));
EasyBind.listen(proxyPreferences.useProxyProperty(), (obs, oldValue, newValue) -> putBoolean(PROXY_USE, newValue));
EasyBind.listen(proxyPreferences.hostnameProperty(), (obs, oldValue, newValue) -> put(PROXY_HOSTNAME, newValue));
@@ -1540,7 +1541,7 @@ public ProxyPreferences getProxyPreferences() {
EasyBind.listen(proxyPreferences.useAuthenticationProperty(), (obs, oldValue, newValue) -> putBoolean(PROXY_USE_AUTHENTICATION, newValue));
EasyBind.listen(proxyPreferences.usernameProperty(), (obs, oldValue, newValue) -> put(PROXY_USERNAME, newValue));
EasyBind.listen(proxyPreferences.passwordProperty(), (obs, oldValue, newValue) -> {
- if (getWorkspacePreferences().shouldUseKeyring()) {
+ if (getProxyPreferences().shouldPersistPassword()) {
try (final Keyring keyring = Keyring.create()) {
if (StringUtil.isBlank(newValue)) {
keyring.deletePassword("org.jabref", "proxy");
@@ -1551,7 +1552,17 @@ public ProxyPreferences getProxyPreferences() {
.encrypt());
}
} catch (Exception ex) {
- LOGGER.error("Unable to open key store");
+ LOGGER.warn("Unable to open key store");
+ }
+ }
+ });
+ EasyBind.listen(proxyPreferences.persistPasswordProperty(), (obs, oldValue, newValue) -> {
+ putBoolean(PROXY_PERSIST_PASSWORD, newValue);
+ if (!newValue) {
+ try (final Keyring keyring = Keyring.create()) {
+ keyring.deletePassword("org.jabref", "proxy");
+ } catch (Exception ex) {
+ LOGGER.warn("Unable to remove proxy credentials");
}
}
});
@@ -2031,8 +2042,7 @@ public WorkspacePreferences getWorkspacePreferences() {
getBoolean(OPEN_LAST_EDITED),
getBoolean(SHOW_ADVANCED_HINTS),
getBoolean(WARN_ABOUT_DUPLICATES_IN_INSPECTION),
- getBoolean(CONFIRM_DELETE),
- getBoolean(USE_KEYRING));
+ getBoolean(CONFIRM_DELETE));
EasyBind.listen(workspacePreferences.languageProperty(), (obs, oldValue, newValue) -> {
put(LANGUAGE, newValue.getId());
@@ -2048,7 +2058,6 @@ public WorkspacePreferences getWorkspacePreferences() {
EasyBind.listen(workspacePreferences.showAdvancedHintsProperty(), (obs, oldValue, newValue) -> putBoolean(SHOW_ADVANCED_HINTS, newValue));
EasyBind.listen(workspacePreferences.warnAboutDuplicatesInInspectionProperty(), (obs, oldValue, newValue) -> putBoolean(WARN_ABOUT_DUPLICATES_IN_INSPECTION, newValue));
EasyBind.listen(workspacePreferences.confirmDeleteProperty(), (obs, oldValue, newValue) -> putBoolean(CONFIRM_DELETE, newValue));
- EasyBind.listen(workspacePreferences.useKeyringProperty(), (obs, oldValue, newValue) -> putBoolean(USE_KEYRING, newValue));
return workspacePreferences;
}
@@ -2783,9 +2792,7 @@ private Set getFetcherKeys() {
List names = getStringList(FETCHER_CUSTOM_KEY_NAMES);
List uses = getStringList(FETCHER_CUSTOM_KEY_USES);
- List keys = getWorkspacePreferences().shouldUseKeyring()
- ? getFetcherKeysFromKeyring(names)
- : getStringList(FETCHER_CUSTOM_KEYS);
+ List keys = getFetcherKeysFromKeyring(names);
for (int i = 0; i < names.size(); i++) {
fetcherApiKeys.add(new FetcherApiKey(
@@ -2833,11 +2840,7 @@ private void storeFetcherKeys(Set fetcherApiKeys) {
putStringList(FETCHER_CUSTOM_KEY_NAMES, names);
putStringList(FETCHER_CUSTOM_KEY_USES, uses);
- if (getWorkspacePreferences().shouldUseKeyring()) {
- storeFetcherKeysToKeyring(names, keys);
- } else {
- putStringList(FETCHER_CUSTOM_KEYS, keys);
- }
+ storeFetcherKeysToKeyring(names, keys);
}
private void storeFetcherKeysToKeyring(List names, List keys) {
diff --git a/src/main/java/org/jabref/preferences/WorkspacePreferences.java b/src/main/java/org/jabref/preferences/WorkspacePreferences.java
index 9c8e44d6829..bde96a61704 100644
--- a/src/main/java/org/jabref/preferences/WorkspacePreferences.java
+++ b/src/main/java/org/jabref/preferences/WorkspacePreferences.java
@@ -20,7 +20,6 @@ public class WorkspacePreferences {
private final BooleanProperty showAdvancedHints;
private final BooleanProperty warnAboutDuplicatesInInspection;
private final BooleanProperty confirmDelete;
- private final BooleanProperty useKeyring;
public WorkspacePreferences(Language language,
boolean shouldOverrideDefaultFontSize,
@@ -30,8 +29,7 @@ public WorkspacePreferences(Language language,
boolean shouldOpenLastEdited,
boolean showAdvancedHints,
boolean warnAboutDuplicatesInInspection,
- boolean confirmDelete,
- boolean useKeyring) {
+ boolean confirmDelete) {
this.language = new SimpleObjectProperty<>(language);
this.shouldOverrideDefaultFontSize = new SimpleBooleanProperty(shouldOverrideDefaultFontSize);
this.mainFontSize = new SimpleIntegerProperty(mainFontSize);
@@ -41,7 +39,6 @@ public WorkspacePreferences(Language language,
this.showAdvancedHints = new SimpleBooleanProperty(showAdvancedHints);
this.warnAboutDuplicatesInInspection = new SimpleBooleanProperty(warnAboutDuplicatesInInspection);
this.confirmDelete = new SimpleBooleanProperty(confirmDelete);
- this.useKeyring = new SimpleBooleanProperty(useKeyring);
}
public Language getLanguage() {
@@ -143,16 +140,4 @@ public BooleanProperty confirmDeleteProperty() {
public void setConfirmDelete(boolean confirmDelete) {
this.confirmDelete.set(confirmDelete);
}
-
- public boolean shouldUseKeyring() {
- return useKeyring.get();
- }
-
- public BooleanProperty useKeyringProperty() {
- return useKeyring;
- }
-
- public void setUseKeyring(boolean useKeyring) {
- this.useKeyring.set(useKeyring);
- }
}
diff --git a/src/main/resources/l10n/JabRef_en.properties b/src/main/resources/l10n/JabRef_en.properties
index e510c777da6..dd7e74faa00 100644
--- a/src/main/resources/l10n/JabRef_en.properties
+++ b/src/main/resources/l10n/JabRef_en.properties
@@ -840,7 +840,7 @@ Show\ BibTeX\ source\ by\ default=Show BibTeX source by default
Show\ confirmation\ dialog\ when\ deleting\ entries=Show confirmation dialog when deleting entries
-Use\ OS\ credential\ store\ to\ store\ custom\ api\ keys\ and\ passwords\ (save\ and\ reopen\ preferences\ required)=Use OS credential store to store custom api keys and passwords (save and reopen preferences required)
+Persist\ password\ between\ sessions=Persist password between sessions
Show\ last\ names\ only=Show last names only
diff --git a/src/test/java/org/jabref/logic/net/ProxyTest.java b/src/test/java/org/jabref/logic/net/ProxyTest.java
index 510f9ce1a50..6b6e844d1b6 100644
--- a/src/test/java/org/jabref/logic/net/ProxyTest.java
+++ b/src/test/java/org/jabref/logic/net/ProxyTest.java
@@ -12,12 +12,14 @@ public class ProxyTest {
@Test
public void testProxyPreferencesStorePassword() {
// mock data
- Boolean useProxy = true;
+ boolean useProxy = true;
String hostname = "testName";
String port = "8080";
- Boolean useAuthentication = true;
+ boolean useAuthentication = true;
String username = "testUserName";
String password = "testPassword";
+ boolean persist = false;
+
// Creates proxy preference
ProxyPreferences proxyPref = new ProxyPreferences(
useProxy,
@@ -25,7 +27,9 @@ public void testProxyPreferencesStorePassword() {
port,
useAuthentication,
username,
- password);
+ password,
+ persist);
+
// Check if mock data is stored in object memory and can be extracted
assertEquals(proxyPref.shouldUseProxy(), true);
assertEquals(proxyPref.getHostname(), hostname);
@@ -33,5 +37,6 @@ public void testProxyPreferencesStorePassword() {
assertEquals(proxyPref.shouldUseAuthentication(), true);
assertEquals(proxyPref.getUsername(), username);
assertEquals(proxyPref.getPassword(), password);
+ assertEquals(proxyPref.shouldPersistPassword(), persist);
}
}
From 753c150750ad4477c8e4cbd5b1497673f2817934 Mon Sep 17 00:00:00 2001
From: Carl Christian Snethlage <50491877+calixtus@users.noreply.github.com>
Date: Thu, 29 Jun 2023 15:10:33 +0200
Subject: [PATCH 14/21] Added migrations
---
.../migrations/PreferencesMigrations.java | 35 +++++++++++++++++++
.../jabref/preferences/JabRefPreferences.java | 14 +++-----
2 files changed, 39 insertions(+), 10 deletions(-)
diff --git a/src/main/java/org/jabref/migrations/PreferencesMigrations.java b/src/main/java/org/jabref/migrations/PreferencesMigrations.java
index 9d88661ed15..9e5cf2a52af 100644
--- a/src/main/java/org/jabref/migrations/PreferencesMigrations.java
+++ b/src/main/java/org/jabref/migrations/PreferencesMigrations.java
@@ -20,6 +20,7 @@
import org.jabref.gui.maintable.MainTableColumnModel;
import org.jabref.logic.citationkeypattern.GlobalCitationKeyPattern;
import org.jabref.logic.cleanup.FieldFormatterCleanups;
+import org.jabref.logic.shared.security.Password;
import org.jabref.logic.util.OS;
import org.jabref.model.entry.field.SpecialField;
import org.jabref.model.entry.field.StandardField;
@@ -28,6 +29,8 @@
import org.jabref.preferences.CleanupPreferences;
import org.jabref.preferences.JabRefPreferences;
+import com.github.javakeyring.Keyring;
+import com.github.javakeyring.PasswordAccessException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -60,6 +63,7 @@ public static void runMigrations(JabRefPreferences preferences) {
upgradeColumnPreferences(preferences);
restoreVariablesForBackwardCompatibility(preferences);
upgradeCleanups(preferences);
+ moveApiKeysToKeyring(preferences);
}
/**
@@ -516,4 +520,35 @@ private static void upgradeCleanups(JabRefPreferences prefs) {
prefs.put(V6_0_CLEANUP_FIELD_FORMATTERS, String.join(OS.NEWLINE, formatterCleanups.subList(1, formatterCleanups.size() - 1)));
}
}
+
+ private static void moveApiKeysToKeyring(JabRefPreferences preferences) {
+ final String V5_9_FETCHER_CUSTOM_KEY_NAMES = "fetcherCustomKeyNames";
+ final String V5_9_FETCHER_CUSTOM_KEYS = "fetcherCustomKeys";
+
+ List names = preferences.getStringList(V5_9_FETCHER_CUSTOM_KEY_NAMES);
+ List keys = preferences.getStringList(V5_9_FETCHER_CUSTOM_KEYS);
+
+ if (keys.size() > 0) {
+ try (final Keyring keyring = Keyring.create()) {
+ for (int i = 0; i < names.size(); i++) {
+ if (StringUtil.isNullOrEmpty(keys.get(i))) {
+ try {
+ keyring.deletePassword("org.jabref.customapikeys", names.get(i));
+ } catch (
+ PasswordAccessException ex) {
+ // Already removed
+ }
+ } else {
+ keyring.setPassword("org.jabref.customapikeys", names.get(i), new Password(
+ keys.get(i),
+ preferences.getInternalPreferences().getUserAndHost())
+ .encrypt());
+ }
+ }
+ } catch (
+ Exception ex) {
+ LOGGER.error("Unable to open key store");
+ }
+ }
+ }
}
diff --git a/src/main/java/org/jabref/preferences/JabRefPreferences.java b/src/main/java/org/jabref/preferences/JabRefPreferences.java
index aff292e1203..99a26239c9b 100644
--- a/src/main/java/org/jabref/preferences/JabRefPreferences.java
+++ b/src/main/java/org/jabref/preferences/JabRefPreferences.java
@@ -218,10 +218,6 @@ public class JabRefPreferences implements PreferencesService {
public static final String BASE_DOI_URI = "baseDOIURI";
public static final String USE_CUSTOM_DOI_URI = "useCustomDOIURI";
- public static final String FETCHER_CUSTOM_KEY_NAMES = "fetcherCustomKeyNames";
- public static final String FETCHER_CUSTOM_KEY_USES = "fetcherCustomKeyUses";
- public static final String FETCHER_CUSTOM_KEYS = "fetcherCustomKeys";
-
public static final String USE_OWNER = "useOwner";
public static final String DEFAULT_OWNER = "defaultOwner";
public static final String OVERWRITE_OWNER = "overwriteOwner";
@@ -364,6 +360,10 @@ public class JabRefPreferences implements PreferencesService {
private static final String PROXY_PASSWORD = "proxyPassword";
private static final String PROXY_PERSIST_PASSWORD = "persistPassword";
+ // Web search
+ private static final String FETCHER_CUSTOM_KEY_NAMES = "fetcherCustomKeyNames";
+ private static final String FETCHER_CUSTOM_KEY_USES = "fetcherCustomKeyUses";
+
// SSL
private static final String TRUSTSTORE_PATH = "truststorePath";
@@ -655,7 +655,6 @@ private JabRefPreferences() {
defaults.put(FETCHER_CUSTOM_KEY_NAMES, "Springer;IEEEXplore;SAO/NASA ADS;ScienceDirect;Biodiversity Heritage");
defaults.put(FETCHER_CUSTOM_KEY_USES, "FALSE;FALSE;FALSE;FALSE;FALSE");
- defaults.put(FETCHER_CUSTOM_KEYS, "");
defaults.put(USE_OWNER, Boolean.FALSE);
defaults.put(OVERWRITE_OWNER, Boolean.FALSE);
@@ -2864,12 +2863,7 @@ private void storeFetcherKeysToKeyring(List names, List keys) {
}
}
- /**
- * Clears the custom fetcher keys in the backing store and in the credential store
- */
private void clearCustomFetcherKeys() {
- put(FETCHER_CUSTOM_KEYS, "");
-
List names = getStringList(FETCHER_CUSTOM_KEY_NAMES);
try (final Keyring keyring = Keyring.create()) {
for (String name : names) {
From c0d966c58d903ee67e03db2b2816496112c069e3 Mon Sep 17 00:00:00 2001
From: Carl Christian Snethlage <50491877+calixtus@users.noreply.github.com>
Date: Thu, 29 Jun 2023 15:57:16 +0200
Subject: [PATCH 15/21] Added migrationtest
---
.../migrations/PreferencesMigrations.java | 21 ++++---------
.../migrations/PreferencesMigrationsTest.java | 30 ++++++++++++++++++-
2 files changed, 35 insertions(+), 16 deletions(-)
diff --git a/src/main/java/org/jabref/migrations/PreferencesMigrations.java b/src/main/java/org/jabref/migrations/PreferencesMigrations.java
index 9e5cf2a52af..1ce5e59d853 100644
--- a/src/main/java/org/jabref/migrations/PreferencesMigrations.java
+++ b/src/main/java/org/jabref/migrations/PreferencesMigrations.java
@@ -30,7 +30,6 @@
import org.jabref.preferences.JabRefPreferences;
import com.github.javakeyring.Keyring;
-import com.github.javakeyring.PasswordAccessException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -521,7 +520,7 @@ private static void upgradeCleanups(JabRefPreferences prefs) {
}
}
- private static void moveApiKeysToKeyring(JabRefPreferences preferences) {
+ static void moveApiKeysToKeyring(JabRefPreferences preferences) {
final String V5_9_FETCHER_CUSTOM_KEY_NAMES = "fetcherCustomKeyNames";
final String V5_9_FETCHER_CUSTOM_KEYS = "fetcherCustomKeys";
@@ -531,20 +530,12 @@ private static void moveApiKeysToKeyring(JabRefPreferences preferences) {
if (keys.size() > 0) {
try (final Keyring keyring = Keyring.create()) {
for (int i = 0; i < names.size(); i++) {
- if (StringUtil.isNullOrEmpty(keys.get(i))) {
- try {
- keyring.deletePassword("org.jabref.customapikeys", names.get(i));
- } catch (
- PasswordAccessException ex) {
- // Already removed
- }
- } else {
- keyring.setPassword("org.jabref.customapikeys", names.get(i), new Password(
- keys.get(i),
- preferences.getInternalPreferences().getUserAndHost())
- .encrypt());
- }
+ keyring.setPassword("org.jabref.customapikeys", names.get(i), new Password(
+ keys.get(i),
+ preferences.getInternalPreferences().getUserAndHost())
+ .encrypt());
}
+ preferences.deleteKey(V5_9_FETCHER_CUSTOM_KEYS);
} catch (
Exception ex) {
LOGGER.error("Unable to open key store");
diff --git a/src/test/java/org/jabref/migrations/PreferencesMigrationsTest.java b/src/test/java/org/jabref/migrations/PreferencesMigrationsTest.java
index 099327a7518..7146764d8c1 100644
--- a/src/test/java/org/jabref/migrations/PreferencesMigrationsTest.java
+++ b/src/test/java/org/jabref/migrations/PreferencesMigrationsTest.java
@@ -7,9 +7,15 @@
import org.jabref.preferences.JabRefPreferences;
+import com.github.javakeyring.Keyring;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
+import org.mockito.Answers;
+import org.mockito.MockedStatic;
+import org.mockito.Mockito;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
@@ -27,7 +33,7 @@ class PreferencesMigrationsTest {
@BeforeEach
void setUp() {
- prefs = mock(JabRefPreferences.class);
+ prefs = mock(JabRefPreferences.class, Answers.RETURNS_DEEP_STUBS);
mainPrefsNode = mock(Preferences.class);
}
@@ -188,4 +194,26 @@ void testRestoreColumnVariablesForBackwardCompatibility() {
verify(prefs).putInt(JabRefPreferences.MAIN_FONT_SIZE, 11);
}
+
+ @Test
+ void testMoveApiKeysToKeyRing() throws Exception {
+ final String V5_9_FETCHER_CUSTOM_KEY_NAMES = "fetcherCustomKeyNames";
+ final String V5_9_FETCHER_CUSTOM_KEYS = "fetcherCustomKeys";
+ final Keyring keyring = mock(Keyring.class);
+
+ when(prefs.getStringList(V5_9_FETCHER_CUSTOM_KEY_NAMES)).thenReturn(List.of("FetcherA", "FetcherB", "FetcherC"));
+ when(prefs.getStringList(V5_9_FETCHER_CUSTOM_KEYS)).thenReturn(List.of("KeyA", "KeyB", "KeyC"));
+ when(prefs.getInternalPreferences().getUserAndHost()).thenReturn("user-host");
+
+ try (MockedStatic keyringFactory = Mockito.mockStatic(Keyring.class, Answers.RETURNS_DEEP_STUBS)) {
+ keyringFactory.when(Keyring::create).thenReturn(keyring);
+
+ PreferencesMigrations.moveApiKeysToKeyring(prefs);
+
+ verify(keyring).setPassword(eq("org.jabref.customapikeys"), eq("FetcherA"), any());
+ verify(keyring).setPassword(eq("org.jabref.customapikeys"), eq("FetcherB"), any());
+ verify(keyring).setPassword(eq("org.jabref.customapikeys"), eq("FetcherC"), any());
+ verify(prefs).deleteKey(V5_9_FETCHER_CUSTOM_KEYS);
+ }
+ }
}
From 7a53a46e44ac6fc9fbb0b691caf89e49a7e0eab8 Mon Sep 17 00:00:00 2001
From: Carl Christian Snethlage <50491877+calixtus@users.noreply.github.com>
Date: Thu, 29 Jun 2023 16:02:30 +0200
Subject: [PATCH 16/21] CHANGELOG.md
---
CHANGELOG.md | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 78112de74ed..3763ab5a8be 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -36,7 +36,7 @@ Note that this project **does not** adhere to [Semantic Versioning](http://semve
- We enabled the user to change the name of a field in a custom entry type by double-clicking on it. [#9840](https://github.com/JabRef/jabref/issues/9840)
- We integrated two mail actions ("As Email" and "To Kindle") under a new "Send" option in the right-click & Tools menus. The Kindle option creates an email targeted to the user's Kindle email, which can be set in preferences under "External programs" [#6186](https://github.com/JabRef/jabref/issues/6186)
- We added an option to clear recent libraries' history. [#10003](https://github.com/JabRef/jabref/issues/10003)
-- We added an option to encrypt and remember the proxy password and the custom api keys between sessions. [#10044](https://github.com/JabRef/jabref/issues/10044)
+- We added an option to encrypt and remember the proxy password. [#8055](https://github.com/JabRef/jabref/issues/8055)[#10044](https://github.com/JabRef/jabref/issues/10044)
### Changed
@@ -71,6 +71,7 @@ Note that this project **does not** adhere to [Semantic Versioning](http://semve
- We improved the error message when no terminal was found [#9607](https://github.com/JabRef/jabref/issues/9607)
- In the context of the "systematic literature functionality", we changed the name "database" to "catalog" to use a separate term for online catalogs in comparison to SQL databases. [#9951](https://github.com/JabRef/jabref/pull/9951)
- We now show more fields (including Special Fields) in the dropdown selection for "Save sort order" in the library properties and for "Export sort order" in the preferences. [#10010](https://github.com/JabRef/jabref/issues/10010)
+- We now encrypt and store the custom API keys in the OS native credential store. [#10044](https://github.com/JabRef/jabref/issues/10044)
### Fixed
@@ -82,7 +83,7 @@ Note that this project **does not** adhere to [Semantic Versioning](http://semve
- We fixed an issue where custom field in the custom entry types could not be set to mulitline. [#9609](https://github.com/JabRef/jabref/issues/9609)
- We fixed an issue where the Office XML exporter did not resolve BibTeX-Strings when exporting entries. [forum#3741](https://discourse.jabref.org/t/exporting-bibtex-constant-strings-to-ms-office-2007-xml/3741)
- We fixed an issue where the Merge Entries Toolbar configuration was not saved after hitting 'Merge Entries' button. [#9091](https://github.com/JabRef/jabref/issues/9091)
-- We fixed an issue where the password is saved locally if user wants to use proxy with authentication. [#8055](https://github.com/JabRef/jabref/issues/8055)
+- We fixed an issue where the password is stored in clear text if the user wants to use a proxy with authentication. [#8055](https://github.com/JabRef/jabref/issues/8055)
- JabRef is now more relaxed when parsing field content: In case a field content ended with `\`, the combination `\}` was treated as plain `}`. [#9668](https://github.com/JabRef/jabref/issues/9668)
- We resolved an issue that cut off the number of group entries when it exceeded four digits. [#8797](https://github.com/JabRef/jabref/issues/8797)
- We fixed the issue where the size of the global search window was not retained after closing. [#9362](https://github.com/JabRef/jabref/issues/9362)
From 10a5b9d70f629dda6dd17088583d08618fbda635 Mon Sep 17 00:00:00 2001
From: Carl Christian Snethlage <50491877+calixtus@users.noreply.github.com>
Date: Thu, 29 Jun 2023 17:26:16 +0200
Subject: [PATCH 17/21] l10n
---
src/main/resources/l10n/JabRef_en.properties | 1 -
1 file changed, 1 deletion(-)
diff --git a/src/main/resources/l10n/JabRef_en.properties b/src/main/resources/l10n/JabRef_en.properties
index dd7e74faa00..d566fbcb96f 100644
--- a/src/main/resources/l10n/JabRef_en.properties
+++ b/src/main/resources/l10n/JabRef_en.properties
@@ -1254,7 +1254,6 @@ Please\ specify\ a\ password=Please specify a password
Proxy\ configuration=Proxy configuration
Use\ custom\ proxy\ configuration=Use custom proxy configuration
Proxy\ requires\ authentication=Proxy requires authentication
-Password\ kept\ for\ this\ session\ only.=Password kept for this session only.
Clear\ connection\ settings=Clear connection settings
Check\ Proxy\ Setting=Check Proxy Setting
Check\ connection=Check connection
From 695a443105e589b6bac0a92ab5fde4c0a10fdb02 Mon Sep 17 00:00:00 2001
From: Oliver Kopp
Date: Sat, 1 Jul 2023 21:35:50 +0200
Subject: [PATCH 18/21] Result of discussion
Co-authored-by: Carl Christian Snethlage <50491877+calixtus@users.noreply.github.com>
---
src/main/java/org/jabref/gui/JabRefGUI.java | 4 ++--
src/main/java/org/jabref/logic/net/ProxyPreferences.java | 4 ++--
.../java/org/jabref/migrations/PreferencesMigrations.java | 5 ++---
src/main/java/org/jabref/preferences/JabRefPreferences.java | 4 ++--
4 files changed, 8 insertions(+), 9 deletions(-)
diff --git a/src/main/java/org/jabref/gui/JabRefGUI.java b/src/main/java/org/jabref/gui/JabRefGUI.java
index 531a776e6c1..e70dd45f277 100644
--- a/src/main/java/org/jabref/gui/JabRefGUI.java
+++ b/src/main/java/org/jabref/gui/JabRefGUI.java
@@ -93,7 +93,7 @@ private void setupProxy() {
preferencesService.getProxyPreferences().setPassword(password.get());
ProxyRegisterer.register(preferencesService.getProxyPreferences());
} else {
- LOGGER.warn("No proxy password specified");
+ LOGGER.warn("No proxy password specified");
}
return;
}
@@ -101,7 +101,7 @@ private void setupProxy() {
try (final Keyring keyring = Keyring.create()) {
String password = new Password(
keyring.getPassword("org.jabref", "proxy"),
- preferencesService.getProxyPreferences().getUsername())
+ preferencesService.getInternalPreferences().getUserAndHost())
.decrypt();
preferencesService.getProxyPreferences().setPassword(password);
ProxyRegisterer.register(preferencesService.getProxyPreferences());
diff --git a/src/main/java/org/jabref/logic/net/ProxyPreferences.java b/src/main/java/org/jabref/logic/net/ProxyPreferences.java
index 7a010420b7e..dc5311ab139 100644
--- a/src/main/java/org/jabref/logic/net/ProxyPreferences.java
+++ b/src/main/java/org/jabref/logic/net/ProxyPreferences.java
@@ -70,7 +70,7 @@ public void setPort(String port) {
}
public final boolean shouldUseAuthentication() {
- return useAuthentication.getValue();
+ return useAuthentication.get();
}
public BooleanProperty useAuthenticationProperty() {
@@ -106,7 +106,7 @@ public void setPassword(String password) {
}
public boolean shouldPersistPassword() {
- return persistPassword.getValue();
+ return persistPassword.get();
}
public BooleanProperty persistPasswordProperty() {
diff --git a/src/main/java/org/jabref/migrations/PreferencesMigrations.java b/src/main/java/org/jabref/migrations/PreferencesMigrations.java
index 1ce5e59d853..c4bd8e8f665 100644
--- a/src/main/java/org/jabref/migrations/PreferencesMigrations.java
+++ b/src/main/java/org/jabref/migrations/PreferencesMigrations.java
@@ -536,9 +536,8 @@ static void moveApiKeysToKeyring(JabRefPreferences preferences) {
.encrypt());
}
preferences.deleteKey(V5_9_FETCHER_CUSTOM_KEYS);
- } catch (
- Exception ex) {
- LOGGER.error("Unable to open key store");
+ } catch (Exception ex) {
+ LOGGER.error("Unable to open key store", ex);
}
}
}
diff --git a/src/main/java/org/jabref/preferences/JabRefPreferences.java b/src/main/java/org/jabref/preferences/JabRefPreferences.java
index 99a26239c9b..2302b82d368 100644
--- a/src/main/java/org/jabref/preferences/JabRefPreferences.java
+++ b/src/main/java/org/jabref/preferences/JabRefPreferences.java
@@ -1547,11 +1547,11 @@ public ProxyPreferences getProxyPreferences() {
} else {
keyring.setPassword("org.jabref", "proxy", new Password(
newValue.trim(),
- proxyPreferences.getUsername())
+ getInternalPreferences().getUserAndHost())
.encrypt());
}
} catch (Exception ex) {
- LOGGER.warn("Unable to open key store");
+ LOGGER.warn("Unable to open key store", ex);
}
}
});
From 1f8075b225ae4a0c35132f0e4daac27c6bbd913f Mon Sep 17 00:00:00 2001
From: Carl Christian Snethlage <50491877+calixtus@users.noreply.github.com>
Date: Sat, 1 Jul 2023 22:39:19 +0200
Subject: [PATCH 19/21] Moved proxy password decrypt to prefs
---
src/main/java/org/jabref/gui/JabRefGUI.java | 42 ++++++---------
.../jabref/preferences/JabRefPreferences.java | 52 +++++++++++++------
2 files changed, 51 insertions(+), 43 deletions(-)
diff --git a/src/main/java/org/jabref/gui/JabRefGUI.java b/src/main/java/org/jabref/gui/JabRefGUI.java
index e70dd45f277..f22bbb0f30e 100644
--- a/src/main/java/org/jabref/gui/JabRefGUI.java
+++ b/src/main/java/org/jabref/gui/JabRefGUI.java
@@ -25,16 +25,14 @@
import org.jabref.logic.shared.DatabaseNotSupportedException;
import org.jabref.logic.shared.exception.InvalidDBMSConnectionPropertiesException;
import org.jabref.logic.shared.exception.NotASharedDatabaseException;
-import org.jabref.logic.shared.security.Password;
import org.jabref.logic.util.WebViewStore;
import org.jabref.model.util.FileUpdateMonitor;
import org.jabref.preferences.GuiPreferences;
import org.jabref.preferences.PreferencesService;
import com.airhacks.afterburner.injection.Injector;
-import com.github.javakeyring.Keyring;
-import com.github.javakeyring.PasswordAccessException;
import impl.org.controlsfx.skin.DecorationPane;
+import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -79,36 +77,28 @@ public JabRefGUI(Stage mainStage,
}
private void setupProxy() {
- if (!preferencesService.getProxyPreferences().shouldUseProxy() || !preferencesService.getProxyPreferences().shouldUseAuthentication()) {
+ if (!preferencesService.getProxyPreferences().shouldUseProxy()
+ || !preferencesService.getProxyPreferences().shouldUseAuthentication()) {
return;
}
- if (!preferencesService.getProxyPreferences().shouldPersistPassword()) {
- DialogService dialogService = Injector.instantiateModelOrService(DialogService.class);
- Optional password = dialogService.showPasswordDialogAndWait(
- Localization.lang("Proxy configuration"),
- Localization.lang("Proxy requires password"),
- Localization.lang("Password"));
- if (password.isPresent()) {
- preferencesService.getProxyPreferences().setPassword(password.get());
- ProxyRegisterer.register(preferencesService.getProxyPreferences());
- } else {
- LOGGER.warn("No proxy password specified");
- }
+ if (preferencesService.getProxyPreferences().shouldPersistPassword()
+ && StringUtils.isNotBlank(preferencesService.getProxyPreferences().getPassword())) {
+ ProxyRegisterer.register(preferencesService.getProxyPreferences());
return;
}
- try (final Keyring keyring = Keyring.create()) {
- String password = new Password(
- keyring.getPassword("org.jabref", "proxy"),
- preferencesService.getInternalPreferences().getUserAndHost())
- .decrypt();
- preferencesService.getProxyPreferences().setPassword(password);
+ DialogService dialogService = Injector.instantiateModelOrService(DialogService.class);
+ Optional password = dialogService.showPasswordDialogAndWait(
+ Localization.lang("Proxy configuration"),
+ Localization.lang("Proxy requires password"),
+ Localization.lang("Password"));
+
+ if (password.isPresent()) {
+ preferencesService.getProxyPreferences().setPassword(password.get());
ProxyRegisterer.register(preferencesService.getProxyPreferences());
- } catch (PasswordAccessException ex) {
- LOGGER.warn("JabRef uses proxy password from key store but no password is stored");
- } catch (Exception ex) {
- LOGGER.warn("JabRef could not open the key store");
+ } else {
+ LOGGER.warn("No proxy password specified");
}
}
diff --git a/src/main/java/org/jabref/preferences/JabRefPreferences.java b/src/main/java/org/jabref/preferences/JabRefPreferences.java
index 2302b82d368..f97680c67d7 100644
--- a/src/main/java/org/jabref/preferences/JabRefPreferences.java
+++ b/src/main/java/org/jabref/preferences/JabRefPreferences.java
@@ -1531,7 +1531,7 @@ public ProxyPreferences getProxyPreferences() {
get(PROXY_PORT),
getBoolean(PROXY_USE_AUTHENTICATION),
get(PROXY_USERNAME),
- (String) defaults.get(PROXY_PASSWORD),
+ getProxyPassword(),
getBoolean(PROXY_PERSIST_PASSWORD));
EasyBind.listen(proxyPreferences.useProxyProperty(), (obs, oldValue, newValue) -> putBoolean(PROXY_USE, newValue));
@@ -1539,22 +1539,7 @@ public ProxyPreferences getProxyPreferences() {
EasyBind.listen(proxyPreferences.portProperty(), (obs, oldValue, newValue) -> put(PROXY_PORT, newValue));
EasyBind.listen(proxyPreferences.useAuthenticationProperty(), (obs, oldValue, newValue) -> putBoolean(PROXY_USE_AUTHENTICATION, newValue));
EasyBind.listen(proxyPreferences.usernameProperty(), (obs, oldValue, newValue) -> put(PROXY_USERNAME, newValue));
- EasyBind.listen(proxyPreferences.passwordProperty(), (obs, oldValue, newValue) -> {
- if (getProxyPreferences().shouldPersistPassword()) {
- try (final Keyring keyring = Keyring.create()) {
- if (StringUtil.isBlank(newValue)) {
- keyring.deletePassword("org.jabref", "proxy");
- } else {
- keyring.setPassword("org.jabref", "proxy", new Password(
- newValue.trim(),
- getInternalPreferences().getUserAndHost())
- .encrypt());
- }
- } catch (Exception ex) {
- LOGGER.warn("Unable to open key store", ex);
- }
- }
- });
+ EasyBind.listen(proxyPreferences.passwordProperty(), (obs, oldValue, newValue) -> setProxyPassword(newValue));
EasyBind.listen(proxyPreferences.persistPasswordProperty(), (obs, oldValue, newValue) -> {
putBoolean(PROXY_PERSIST_PASSWORD, newValue);
if (!newValue) {
@@ -1569,6 +1554,39 @@ public ProxyPreferences getProxyPreferences() {
return proxyPreferences;
}
+ private String getProxyPassword() {
+ if (getBoolean(PROXY_PERSIST_PASSWORD)) {
+ try (final Keyring keyring = Keyring.create()) {
+ return new Password(
+ keyring.getPassword("org.jabref", "proxy"),
+ getInternalPreferences().getUserAndHost())
+ .decrypt();
+ } catch (PasswordAccessException ex) {
+ LOGGER.warn("JabRef uses proxy password from key store but no password is stored");
+ } catch (Exception ex) {
+ LOGGER.warn("JabRef could not open the key store");
+ }
+ }
+ return (String) defaults.get(PROXY_PASSWORD);
+ }
+
+ private void setProxyPassword(String password) {
+ if (getProxyPreferences().shouldPersistPassword()) {
+ try (final Keyring keyring = Keyring.create()) {
+ if (StringUtil.isBlank(password)) {
+ keyring.deletePassword("org.jabref", "proxy");
+ } else {
+ keyring.setPassword("org.jabref", "proxy", new Password(
+ password.trim(),
+ getInternalPreferences().getUserAndHost())
+ .encrypt());
+ }
+ } catch (Exception ex) {
+ LOGGER.warn("Unable to open key store", ex);
+ }
+ }
+ }
+
@Override
public SSLPreferences getSSLPreferences() {
if (Objects.nonNull(sslPreferences)) {
From 5cd7cf01b8d7996ce8380ea6f0d146608a6c2366 Mon Sep 17 00:00:00 2001
From: Carl Christian Snethlage <50491877+calixtus@users.noreply.github.com>
Date: Sat, 1 Jul 2023 22:59:44 +0200
Subject: [PATCH 20/21] Fixed arch test
---
src/main/java/org/jabref/gui/JabRefGUI.java | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/main/java/org/jabref/gui/JabRefGUI.java b/src/main/java/org/jabref/gui/JabRefGUI.java
index f22bbb0f30e..133df390b3f 100644
--- a/src/main/java/org/jabref/gui/JabRefGUI.java
+++ b/src/main/java/org/jabref/gui/JabRefGUI.java
@@ -26,13 +26,13 @@
import org.jabref.logic.shared.exception.InvalidDBMSConnectionPropertiesException;
import org.jabref.logic.shared.exception.NotASharedDatabaseException;
import org.jabref.logic.util.WebViewStore;
+import org.jabref.model.strings.StringUtil;
import org.jabref.model.util.FileUpdateMonitor;
import org.jabref.preferences.GuiPreferences;
import org.jabref.preferences.PreferencesService;
import com.airhacks.afterburner.injection.Injector;
import impl.org.controlsfx.skin.DecorationPane;
-import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -83,7 +83,7 @@ private void setupProxy() {
}
if (preferencesService.getProxyPreferences().shouldPersistPassword()
- && StringUtils.isNotBlank(preferencesService.getProxyPreferences().getPassword())) {
+ && StringUtil.isNotBlank(preferencesService.getProxyPreferences().getPassword())) {
ProxyRegisterer.register(preferencesService.getProxyPreferences());
return;
}
From d0ac9374baec06b2a5f2d493d41cf648be699be6 Mon Sep 17 00:00:00 2001
From: Carl Christian Snethlage <50491877+calixtus@users.noreply.github.com>
Date: Sat, 1 Jul 2023 23:22:38 +0200
Subject: [PATCH 21/21] Fixed migration
---
src/main/java/org/jabref/migrations/PreferencesMigrations.java | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/main/java/org/jabref/migrations/PreferencesMigrations.java b/src/main/java/org/jabref/migrations/PreferencesMigrations.java
index c4bd8e8f665..7a43a4a5e43 100644
--- a/src/main/java/org/jabref/migrations/PreferencesMigrations.java
+++ b/src/main/java/org/jabref/migrations/PreferencesMigrations.java
@@ -527,7 +527,7 @@ static void moveApiKeysToKeyring(JabRefPreferences preferences) {
List names = preferences.getStringList(V5_9_FETCHER_CUSTOM_KEY_NAMES);
List keys = preferences.getStringList(V5_9_FETCHER_CUSTOM_KEYS);
- if (keys.size() > 0) {
+ if (keys.size() > 0 && names.size() == keys.size()) {
try (final Keyring keyring = Keyring.create()) {
for (int i = 0; i < names.size(); i++) {
keyring.setPassword("org.jabref.customapikeys", names.get(i), new Password(