From 02a8281b448a680a2b7ebcca6f51ef0d51782b9d Mon Sep 17 00:00:00 2001 From: Oliver Kopp Date: Sun, 29 Sep 2024 15:50:57 +0200 Subject: [PATCH 01/13] Update user agent and log URL --- .../java/org/jabref/logic/importer/fetcher/ResearchGate.java | 2 +- src/main/java/org/jabref/logic/net/URLDownload.java | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/jabref/logic/importer/fetcher/ResearchGate.java b/src/main/java/org/jabref/logic/importer/fetcher/ResearchGate.java index abbababcf23..6e4f3269fdd 100644 --- a/src/main/java/org/jabref/logic/importer/fetcher/ResearchGate.java +++ b/src/main/java/org/jabref/logic/importer/fetcher/ResearchGate.java @@ -69,7 +69,7 @@ public Optional findFullText(BibEntry entry) throws IOException, FetcherExc try { html = getHTML(entry); } catch (FetcherException | NullPointerException e) { - LOGGER.debug("ResearchGate server is not available"); + LOGGER.debug("ResearchGate server is not available", e); return Optional.empty(); } Elements eLink = html.getElementsByTag("section"); diff --git a/src/main/java/org/jabref/logic/net/URLDownload.java b/src/main/java/org/jabref/logic/net/URLDownload.java index b748535a183..7f0261e01f7 100644 --- a/src/main/java/org/jabref/logic/net/URLDownload.java +++ b/src/main/java/org/jabref/logic/net/URLDownload.java @@ -65,7 +65,7 @@ */ public class URLDownload { - public static final String USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36"; + public static final String USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:130.0) Gecko/20100101 Firefox/130.0"; private static final Logger LOGGER = LoggerFactory.getLogger(URLDownload.class); private static final Duration DEFAULT_CONNECT_TIMEOUT = Duration.ofSeconds(30); private static final int MAX_RETRIES = 3; @@ -384,7 +384,7 @@ public URLConnection openConnection() throws FetcherException { } else if (status >= 400) { // in case of an error, propagate the error message SimpleHttpResponse httpResponse = new SimpleHttpResponse(httpURLConnection); - LOGGER.info("{}", httpResponse); + LOGGER.info("{}: {}", this.source, httpResponse); if (status < 500) { throw new FetcherClientException(this.source, httpResponse); } else { From 1553f052ce56584d8b01445f47a03613819cb2d3 Mon Sep 17 00:00:00 2001 From: Oliver Kopp Date: Sun, 29 Sep 2024 16:01:47 +0200 Subject: [PATCH 02/13] Remove non-used "setSSLVerification" --- .../gui/linkedfile/DownloadLinkedFileAction.java | 6 ------ .../websearch/WebSearchTabViewModel.java | 9 --------- .../java/org/jabref/logic/net/URLDownload.java | 15 --------------- 3 files changed, 30 deletions(-) diff --git a/src/main/java/org/jabref/gui/linkedfile/DownloadLinkedFileAction.java b/src/main/java/org/jabref/gui/linkedfile/DownloadLinkedFileAction.java index c81bf261ca2..47402708ad4 100644 --- a/src/main/java/org/jabref/gui/linkedfile/DownloadLinkedFileAction.java +++ b/src/main/java/org/jabref/gui/linkedfile/DownloadLinkedFileAction.java @@ -10,10 +10,7 @@ import java.util.List; import java.util.Optional; -import javax.net.ssl.HostnameVerifier; -import javax.net.ssl.HttpsURLConnection; import javax.net.ssl.SSLHandshakeException; -import javax.net.ssl.SSLSocketFactory; import javafx.beans.property.DoubleProperty; import javafx.beans.property.ReadOnlyDoubleProperty; @@ -243,8 +240,6 @@ private boolean checkSSLHandshake(URLDownload urlDownload) { } private BackgroundTask prepareDownloadTask(Path targetDirectory, URLDownload urlDownload) { - SSLSocketFactory defaultSSLSocketFactory = HttpsURLConnection.getDefaultSSLSocketFactory(); - HostnameVerifier defaultHostnameVerifier = HttpsURLConnection.getDefaultHostnameVerifier(); return BackgroundTask .wrap(() -> { String suggestedName; @@ -263,7 +258,6 @@ private BackgroundTask prepareDownloadTask(Path targetDirectory, URLDownlo .then(destination -> new FileDownloadTask(urlDownload.getSource(), destination)) .onFailure(ex -> LOGGER.error("Error in download", ex)) .onFinished(() -> { - URLDownload.setSSLVerification(defaultSSLSocketFactory, defaultHostnameVerifier); downloadProgress.unbind(); downloadProgress.set(1); }); diff --git a/src/main/java/org/jabref/gui/preferences/websearch/WebSearchTabViewModel.java b/src/main/java/org/jabref/gui/preferences/websearch/WebSearchTabViewModel.java index 71c61a5cf2d..81cc3a2a11a 100644 --- a/src/main/java/org/jabref/gui/preferences/websearch/WebSearchTabViewModel.java +++ b/src/main/java/org/jabref/gui/preferences/websearch/WebSearchTabViewModel.java @@ -5,10 +5,6 @@ import java.util.Optional; import java.util.stream.Collectors; -import javax.net.ssl.HostnameVerifier; -import javax.net.ssl.HttpsURLConnection; -import javax.net.ssl.SSLSocketFactory; - import javafx.beans.property.BooleanProperty; import javafx.beans.property.ListProperty; import javafx.beans.property.ObjectProperty; @@ -217,15 +213,10 @@ public void checkCustomApiKey() { if (!apiKey.isEmpty()) { URLDownload urlDownload; try { - SSLSocketFactory defaultSslSocketFactory = HttpsURLConnection.getDefaultSSLSocketFactory(); - HostnameVerifier defaultHostnameVerifier = HttpsURLConnection.getDefaultHostnameVerifier(); - urlDownload = new URLDownload(testUrlWithoutApiKey + apiKey); // The HEAD request cannot be used because its response is not 200 (maybe 404 or 596...). int statusCode = ((HttpURLConnection) urlDownload.getSource().openConnection()).getResponseCode(); keyValid = (statusCode >= 200) && (statusCode < 300); - - URLDownload.setSSLVerification(defaultSslSocketFactory, defaultHostnameVerifier); } catch (IOException | UnirestException e) { keyValid = false; } diff --git a/src/main/java/org/jabref/logic/net/URLDownload.java b/src/main/java/org/jabref/logic/net/URLDownload.java index 7f0261e01f7..ae41815556a 100644 --- a/src/main/java/org/jabref/logic/net/URLDownload.java +++ b/src/main/java/org/jabref/logic/net/URLDownload.java @@ -32,9 +32,7 @@ import java.util.Map.Entry; import java.util.Optional; -import javax.net.ssl.HostnameVerifier; import javax.net.ssl.HttpsURLConnection; -import javax.net.ssl.SSLSocketFactory; import org.jabref.http.dto.SimpleHttpResponse; import org.jabref.logic.importer.FetcherClientException; @@ -98,19 +96,6 @@ public URLDownload(URL source) { this.addHeader("User-Agent", URLDownload.USER_AGENT); } - /** - * @param socketFactory trust manager - * @param verifier host verifier - */ - public static void setSSLVerification(SSLSocketFactory socketFactory, HostnameVerifier verifier) { - try { - HttpsURLConnection.setDefaultSSLSocketFactory(socketFactory); - HttpsURLConnection.setDefaultHostnameVerifier(verifier); - } catch (Exception e) { - LOGGER.error("A problem occurred when reset SSL verification", e); - } - } - public URL getSource() { return source; } From c73753a056add60db40df81b66d466ab38a57f9c Mon Sep 17 00:00:00 2001 From: Oliver Kopp Date: Sun, 29 Sep 2024 16:02:04 +0200 Subject: [PATCH 03/13] Enable automatic redirect-following --- src/main/java/org/jabref/logic/net/URLDownload.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/main/java/org/jabref/logic/net/URLDownload.java b/src/main/java/org/jabref/logic/net/URLDownload.java index ae41815556a..41a900d7c8a 100644 --- a/src/main/java/org/jabref/logic/net/URLDownload.java +++ b/src/main/java/org/jabref/logic/net/URLDownload.java @@ -382,6 +382,10 @@ public URLConnection openConnection() throws FetcherException { private URLConnection getUrlConnection() throws IOException { URLConnection connection = this.source.openConnection(); + + if (connection instanceof HttpURLConnection httpConnection) { + httpConnection.setInstanceFollowRedirects(true); + } connection.setConnectTimeout((int) connectTimeout.toMillis()); for (Entry entry : this.parameters.entrySet()) { connection.setRequestProperty(entry.getKey(), entry.getValue()); From 0f3b387c69e65135fceb8a176faa0b9ac454dbb9 Mon Sep 17 00:00:00 2001 From: Oliver Kopp Date: Sun, 29 Sep 2024 16:04:48 +0200 Subject: [PATCH 04/13] Make use of TLS 1.2 --- .../java/org/jabref/logic/net/URLDownload.java | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/main/java/org/jabref/logic/net/URLDownload.java b/src/main/java/org/jabref/logic/net/URLDownload.java index 41a900d7c8a..669d265cc1d 100644 --- a/src/main/java/org/jabref/logic/net/URLDownload.java +++ b/src/main/java/org/jabref/logic/net/URLDownload.java @@ -24,6 +24,9 @@ import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.StandardCopyOption; +import java.security.KeyManagementException; +import java.security.NoSuchAlgorithmException; +import java.security.SecureRandom; import java.time.Duration; import java.util.Collections; import java.util.HashMap; @@ -33,6 +36,7 @@ import java.util.Optional; import javax.net.ssl.HttpsURLConnection; +import javax.net.ssl.SSLContext; import org.jabref.http.dto.SimpleHttpResponse; import org.jabref.logic.importer.FetcherClientException; @@ -72,6 +76,7 @@ public class URLDownload { private final Map parameters = new HashMap<>(); private String postData = ""; private Duration connectTimeout = DEFAULT_CONNECT_TIMEOUT; + private SSLContext sslContext; static { Unirest.config() @@ -94,6 +99,14 @@ public URLDownload(String source) throws MalformedURLException { public URLDownload(URL source) { this.source = source; this.addHeader("User-Agent", URLDownload.USER_AGENT); + + try { + sslContext = SSLContext.getInstance("TLSv1.2"); + sslContext.init(null, null, new SecureRandom()); + } catch (NoSuchAlgorithmException | KeyManagementException e) { + LOGGER.error("Could not initialize SSL context", e); + sslContext = null; + } } public URL getSource() { @@ -386,6 +399,11 @@ private URLConnection getUrlConnection() throws IOException { if (connection instanceof HttpURLConnection httpConnection) { httpConnection.setInstanceFollowRedirects(true); } + + if ((sslContext != null) && (connection instanceof HttpsURLConnection httpsConnection)) { + httpsConnection.setSSLSocketFactory(sslContext.getSocketFactory()); + } + connection.setConnectTimeout((int) connectTimeout.toMillis()); for (Entry entry : this.parameters.entrySet()) { connection.setRequestProperty(entry.getKey(), entry.getValue()); From c649240e99cc1d1a0bf57382decb5be51a53dcae Mon Sep 17 00:00:00 2001 From: Oliver Kopp Date: Sun, 29 Sep 2024 16:07:35 +0200 Subject: [PATCH 05/13] Fix static --- .../java/org/jabref/logic/importer/FetcherException.java | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/main/java/org/jabref/logic/importer/FetcherException.java b/src/main/java/org/jabref/logic/importer/FetcherException.java index 47f672a8c51..475f2716f10 100644 --- a/src/main/java/org/jabref/logic/importer/FetcherException.java +++ b/src/main/java/org/jabref/logic/importer/FetcherException.java @@ -14,10 +14,8 @@ public class FetcherException extends JabRefException { private static final Logger LOGGER = LoggerFactory.getLogger(FetcherException.class); - - Pattern API_KEY_PATTERN = Pattern.compile("(?i)(api|key|api[-_]?key)=[^&]*"); - - String REDACTED_STRING = "[REDACTED]"; + private static final Pattern API_KEY_PATTERN = Pattern.compile("(?i)(api|key|api[-_]?key)=[^&]*"); + private static String REDACTED_STRING = "[REDACTED]"; private final String url; private final SimpleHttpResponse httpResponse; From 390d2ce7c86b3fa679b28aaf67b9756e5a961b0b Mon Sep 17 00:00:00 2001 From: Oliver Kopp Date: Sun, 29 Sep 2024 16:07:46 +0200 Subject: [PATCH 06/13] Qucik fix to hide API keys --- src/main/java/org/jabref/logic/importer/FetcherException.java | 4 ++++ src/main/java/org/jabref/logic/net/URLDownload.java | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/jabref/logic/importer/FetcherException.java b/src/main/java/org/jabref/logic/importer/FetcherException.java index 475f2716f10..cd82a392fb9 100644 --- a/src/main/java/org/jabref/logic/importer/FetcherException.java +++ b/src/main/java/org/jabref/logic/importer/FetcherException.java @@ -89,6 +89,10 @@ private String getRedactedUrl() { return API_KEY_PATTERN.matcher(url).replaceAll(REDACTED_STRING); } + public static Object getRedactedUrl(URL source) { + return API_KEY_PATTERN.matcher(source.toString()).replaceAll(REDACTED_STRING); + } + private String getPrefix() { String superLocalizedMessage = super.getLocalizedMessage(); if (!StringUtil.isBlank(superLocalizedMessage)) { diff --git a/src/main/java/org/jabref/logic/net/URLDownload.java b/src/main/java/org/jabref/logic/net/URLDownload.java index 669d265cc1d..1f054ea5024 100644 --- a/src/main/java/org/jabref/logic/net/URLDownload.java +++ b/src/main/java/org/jabref/logic/net/URLDownload.java @@ -382,7 +382,7 @@ public URLConnection openConnection() throws FetcherException { } else if (status >= 400) { // in case of an error, propagate the error message SimpleHttpResponse httpResponse = new SimpleHttpResponse(httpURLConnection); - LOGGER.info("{}: {}", this.source, httpResponse); + LOGGER.info("{}: {}", FetcherException.getRedactedUrl(this.source), httpResponse); if (status < 500) { throw new FetcherClientException(this.source, httpResponse); } else { From 85b382e82a438537692ba75da856aa47533dc0f8 Mon Sep 17 00:00:00 2001 From: Oliver Kopp Date: Sun, 29 Sep 2024 16:08:38 +0200 Subject: [PATCH 07/13] Add CHANGELOG.md entry --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index f98cb2c822c..f49c67f35d5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -47,6 +47,7 @@ Note that this project **does not** adhere to [Semantic Versioning](https://semv - ⚠️ Renamed command line parameters `embeddBibfileInPdf` to `embedBibFileInPdf`, `writeMetadatatoPdf` to `writeMetadataToPdf`, and `writeXMPtoPdf` to `writeXmpToPdf`. [#11575](https://github.com/JabRef/jabref/pull/11575) - The browse button for a Custom theme now opens in the directory of the current used CSS file. [#11597](https://github.com/JabRef/jabref/pull/11597) - The browse button for a Custom exporter now opens in the directory of the current used exporter file. [#11717](https://github.com/JabRef/jabref/pull/11717) +- JabRef now uses TLS 1.2 for all HTTPS connections. [#11852](https://github.com/JabRef/jabref/pull/11852) - We improved the display of long messages in the integrity check dialog. [#11619](https://github.com/JabRef/jabref/pull/11619) - We improved the undo/redo buttons in the main toolbar and main menu to be disabled when there is nothing to undo/redo. [#8807](https://github.com/JabRef/jabref/issues/8807) - We improved the DOI detection in PDF imports. [#11782](https://github.com/JabRef/jabref/pull/11782) From 300b7b3ff4ee55065f7c2e9b3f08ecd0fade027b Mon Sep 17 00:00:00 2001 From: Oliver Kopp Date: Sun, 29 Sep 2024 16:33:45 +0200 Subject: [PATCH 08/13] Add hints on SSL certificates --- src/main/java/org/jabref/logic/net/URLDownload.java | 1 + .../java/org/jabref/logic/net/ssl/TrustStoreManager.java | 7 ++++++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/jabref/logic/net/URLDownload.java b/src/main/java/org/jabref/logic/net/URLDownload.java index 1f054ea5024..6fb9db4cabe 100644 --- a/src/main/java/org/jabref/logic/net/URLDownload.java +++ b/src/main/java/org/jabref/logic/net/URLDownload.java @@ -103,6 +103,7 @@ public URLDownload(URL source) { try { sslContext = SSLContext.getInstance("TLSv1.2"); sslContext.init(null, null, new SecureRandom()); + // Note: SSL certificates are installed at {@link TrustStoreManager#configureTrustStore(Path)} } catch (NoSuchAlgorithmException | KeyManagementException e) { LOGGER.error("Could not initialize SSL context", e); sslContext = null; diff --git a/src/main/java/org/jabref/logic/net/ssl/TrustStoreManager.java b/src/main/java/org/jabref/logic/net/ssl/TrustStoreManager.java index 4e47623846e..3eaf6659167 100644 --- a/src/main/java/org/jabref/logic/net/ssl/TrustStoreManager.java +++ b/src/main/java/org/jabref/logic/net/ssl/TrustStoreManager.java @@ -27,6 +27,9 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +/** + * @implNote SSL certificates are installed at {@link TrustStoreManager#configureTrustStore(Path)} + */ public class TrustStoreManager { private static final Logger LOGGER = LoggerFactory.getLogger(TrustStoreManager.class); @@ -163,7 +166,9 @@ public static void createTruststoreFileIfNotExist(Path storePath) { } } - // based on https://stackoverflow.com/a/62586564/3450689 + /** + * @implNote based on https://stackoverflow.com/a/62586564/3450689 + */ private static void configureTrustStore(Path myStorePath) throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, CertificateException, IOException { X509TrustManager jreTrustManager = getJreTrustManager(); From d4e933ab9a761da2d17681a0d301d0827ae0426c Mon Sep 17 00:00:00 2001 From: Oliver Kopp Date: Sun, 29 Sep 2024 17:20:08 +0200 Subject: [PATCH 09/13] Fix Exception catching --- .../org/jabref/logic/importer/fileformat/MarcXmlParser.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/jabref/logic/importer/fileformat/MarcXmlParser.java b/src/main/java/org/jabref/logic/importer/fileformat/MarcXmlParser.java index 195199bc469..3178cec3643 100644 --- a/src/main/java/org/jabref/logic/importer/fileformat/MarcXmlParser.java +++ b/src/main/java/org/jabref/logic/importer/fileformat/MarcXmlParser.java @@ -407,7 +407,7 @@ private void putElectronicLocation(BibEntry bibEntry, Element datafield) { try { LinkedFile linkedFile = new LinkedFile(URI.create(resource).toURL(), "PDF"); bibEntry.setField(StandardField.FILE, linkedFile.toString()); - } catch (MalformedURLException e) { + } catch (MalformedURLException | IllegalArgumentException e) { LOGGER.info("Malformed URL: {}", resource); } } else { From 759b1d7f843850404b917a614d176fc9f6737c1f Mon Sep 17 00:00:00 2001 From: Oliver Kopp Date: Sun, 29 Sep 2024 17:20:16 +0200 Subject: [PATCH 10/13] Streamline test code --- .../importer/fetcher/BvbFetcherTest.java | 62 +++++++------------ 1 file changed, 24 insertions(+), 38 deletions(-) diff --git a/src/test/java/org/jabref/logic/importer/fetcher/BvbFetcherTest.java b/src/test/java/org/jabref/logic/importer/fetcher/BvbFetcherTest.java index c478693330b..9db7018bbc5 100644 --- a/src/test/java/org/jabref/logic/importer/fetcher/BvbFetcherTest.java +++ b/src/test/java/org/jabref/logic/importer/fetcher/BvbFetcherTest.java @@ -12,7 +12,6 @@ import org.apache.lucene.queryparser.flexible.core.nodes.QueryNode; import org.apache.lucene.queryparser.flexible.standard.parser.StandardSyntaxParser; -import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import static org.jabref.logic.importer.fetcher.transformers.AbstractQueryTransformer.NO_EXPLICIT_FIELD; @@ -23,8 +22,30 @@ class BvbFetcherTest { BvbFetcher fetcher = new BvbFetcher(); - BibEntry bibEntryISBN0134685997; - BibEntry bibEntryISBN9783960886402; + BibEntry bibEntryISBN9783960886402 = new BibEntry(StandardEntryType.Misc) + .withField(StandardField.TITLE, "Effective Java") + .withField(StandardField.YEAR, "2018") + .withField(StandardField.SUBTITLE, "best practices für die Java-Plattform") + .withField(StandardField.AUTHOR, "Bloch, Joshua") + .withField(StandardField.TITLEADDON, "Joshua Bloch") + .withField(StandardField.EDITION, "3. Auflage, Übersetzung der englischsprachigen 3. Originalausgabe 2018") + .withField(StandardField.FILE, "ParsedFileField{description='', link='http://search.ebscohost.com/login.aspx?direct=true&scope=site&db=nlebk&db=nlabk&AN=1906353', fileType='PDF'}") + .withField(StandardField.ISBN, "9783960886402") + .withField(StandardField.KEYWORDS, "Klassen, Interfaces, Generics, Enums, Annotationen, Lambdas, Streams, Module, parallel, Parallele Programmierung, Serialisierung, funktional, funktionale Programmierung, Java EE, Jakarta EE") + .withField(StandardField.ADDRESS, "Heidelberg") + .withField(StandardField.PAGETOTAL, "396") + .withField(StandardField.PUBLISHER, "{dpunkt.verlag} and {Dpunkt. Verlag (Heidelberg)}"); + + BibEntry bibEntryISBN0134685997 = new BibEntry(StandardEntryType.Misc) + .withField(StandardField.TITLE, "Effective Java") + .withField(StandardField.YEAR, "2018") + .withField(StandardField.AUTHOR, "Bloch, Joshua") + .withField(StandardField.TITLEADDON, "Joshua Bloch") + .withField(StandardField.EDITION, "Third edition") + .withField(StandardField.ISBN, "0134685997") + .withField(StandardField.PAGETOTAL, "392") + .withField(StandardField.ADDRESS, "Boston") + .withField(StandardField.PUBLISHER, "{Addison-Wesley}"); @Test void performTest() throws Exception { @@ -38,41 +59,6 @@ void performTest() throws Exception { // result.forEach(entry -> System.out.println(entry.toString())); } - @BeforeEach - void setUp() { - fetcher = new BvbFetcher(); - - bibEntryISBN9783960886402 = new BibEntry(StandardEntryType.Misc) - .withField(StandardField.TITLE, "Effective Java") - .withField(StandardField.YEAR, "2018") - .withField(StandardField.SUBTITLE, "best practices für die Java-Plattform") - .withField(StandardField.AUTHOR, "Bloch, Joshua") - .withField(StandardField.TITLEADDON, "Joshua Bloch") - .withField(StandardField.EDITION, "3. Auflage, Übersetzung der englischsprachigen 3. Originalausgabe 2018") - .withField(StandardField.FILE, "ParsedFileField{description='', link='http://search.ebscohost.com/login.aspx?direct=true&scope=site&db=nlebk&db=nlabk&AN=1906353', fileType='PDF'}") - .withField(StandardField.ISBN, "9783960886402") - .withField(StandardField.KEYWORDS, "Klassen, Interfaces, Generics, Enums, Annotationen, Lambdas, Streams, Module, parallel, Parallele Programmierung, Serialisierung, funktional, funktionale Programmierung, Java EE, Jakarta EE") - .withField(StandardField.ADDRESS, "Heidelberg") - .withField(StandardField.PAGETOTAL, "396") - .withField(StandardField.PUBLISHER, "{dpunkt.verlag} and {Dpunkt. Verlag (Heidelberg)}"); - - bibEntryISBN0134685997 = new BibEntry(StandardEntryType.Misc) - .withField(StandardField.TITLE, "Effective Java") - .withField(StandardField.YEAR, "2018") - .withField(StandardField.AUTHOR, "Bloch, Joshua") - .withField(StandardField.TITLEADDON, "Joshua Bloch") - .withField(StandardField.EDITION, "Third edition") - .withField(StandardField.ISBN, "0134685997") - .withField(StandardField.PAGETOTAL, "392") - .withField(StandardField.ADDRESS, "Boston") - .withField(StandardField.PUBLISHER, "{Addison-Wesley}"); - } - - @Test - void getName() { - assertEquals("Bibliotheksverbund Bayern (Experimental)", fetcher.getName()); - } - @Test void simpleSearchQueryURLCorrect() throws Exception { String query = "java jdk"; From 654616cd448db90e0bbae13c632726d5b77fa870 Mon Sep 17 00:00:00 2001 From: Oliver Kopp Date: Sun, 29 Sep 2024 22:47:39 +0200 Subject: [PATCH 11/13] Fix URL for "Volltext" --- CHANGELOG.md | 1 + .../java/org/jabref/logic/importer/fetcher/BvbFetcher.java | 3 +++ .../jabref/logic/importer/fileformat/MarcXmlParser.java | 5 +++-- .../org/jabref/logic/importer/fetcher/BvbFetcherTest.java | 7 ++++--- 4 files changed, 11 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f49c67f35d5..42b9f6e7576 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -74,6 +74,7 @@ Note that this project **does not** adhere to [Semantic Versioning](https://semv - We fixed an issue where search result highlighting was incorrectly highlighting the boolean operators. [#11595](https://github.com/JabRef/jabref/issues/11595) - We fixed an issue where search result highlighting was broken at complex searches. [#8067](https://github.com/JabRef/jabref/issues/8067) - We fixed an exception when searching for unlinked files. [#11731](https://github.com/JabRef/jabref/issues/11731) +- We fixed an issue with the link to the full text at the BVB fetcher. [#11852](https://github.com/JabRef/jabref/pull/11852) - We fixed an issue where two contradicting notifications were shown when cutting an entry in the main table. [#11724](https://github.com/JabRef/jabref/pull/11724) - We fixed an issue where unescaped braces in the arXiv fetcher were not treated. [#11704](https://github.com/JabRef/jabref/issues/11704) - We fixed an issue where HTML instead of the fulltext pdf was downloaded when importing arXiv entries. [#4913](https://github.com/JabRef/jabref/issues/4913) diff --git a/src/main/java/org/jabref/logic/importer/fetcher/BvbFetcher.java b/src/main/java/org/jabref/logic/importer/fetcher/BvbFetcher.java index 4cfba366384..e570a13f754 100644 --- a/src/main/java/org/jabref/logic/importer/fetcher/BvbFetcher.java +++ b/src/main/java/org/jabref/logic/importer/fetcher/BvbFetcher.java @@ -14,6 +14,9 @@ import org.apache.hc.core5.net.URIBuilder; import org.apache.lucene.queryparser.flexible.core.nodes.QueryNode; +/** + * Fetcher for https://www.bib-bvb.de/. + */ public class BvbFetcher implements SearchBasedParserFetcher { private static final String URL_PATTERN = "http://bvbr.bib-bvb.de:5661/bvb01sru?"; diff --git a/src/main/java/org/jabref/logic/importer/fileformat/MarcXmlParser.java b/src/main/java/org/jabref/logic/importer/fileformat/MarcXmlParser.java index 3178cec3643..9832507b07f 100644 --- a/src/main/java/org/jabref/logic/importer/fileformat/MarcXmlParser.java +++ b/src/main/java/org/jabref/logic/importer/fileformat/MarcXmlParser.java @@ -18,6 +18,7 @@ import org.jabref.logic.importer.AuthorListParser; import org.jabref.logic.importer.ParseException; import org.jabref.logic.importer.Parser; +import org.jabref.logic.util.StandardFileType; import org.jabref.model.entry.AuthorList; import org.jabref.model.entry.BibEntry; import org.jabref.model.entry.Date; @@ -405,8 +406,8 @@ private void putElectronicLocation(BibEntry bibEntry, Element datafield) { if ("Volltext".equals(fulltext) && StringUtil.isNotBlank(resource)) { try { - LinkedFile linkedFile = new LinkedFile(URI.create(resource).toURL(), "PDF"); - bibEntry.setField(StandardField.FILE, linkedFile.toString()); + LinkedFile linkedFile = new LinkedFile("", URI.create(resource).toURL(), StandardFileType.PDF.getName()); + bibEntry.setFiles(List.of(linkedFile)); } catch (MalformedURLException | IllegalArgumentException e) { LOGGER.info("Malformed URL: {}", resource); } diff --git a/src/test/java/org/jabref/logic/importer/fetcher/BvbFetcherTest.java b/src/test/java/org/jabref/logic/importer/fetcher/BvbFetcherTest.java index 9db7018bbc5..e7f39ee2c11 100644 --- a/src/test/java/org/jabref/logic/importer/fetcher/BvbFetcherTest.java +++ b/src/test/java/org/jabref/logic/importer/fetcher/BvbFetcherTest.java @@ -5,7 +5,9 @@ import java.util.List; import org.jabref.logic.importer.FetcherException; +import org.jabref.logic.util.StandardFileType; import org.jabref.model.entry.BibEntry; +import org.jabref.model.entry.LinkedFile; import org.jabref.model.entry.field.StandardField; import org.jabref.model.entry.types.StandardEntryType; import org.jabref.testutils.category.FetcherTest; @@ -29,7 +31,7 @@ class BvbFetcherTest { .withField(StandardField.AUTHOR, "Bloch, Joshua") .withField(StandardField.TITLEADDON, "Joshua Bloch") .withField(StandardField.EDITION, "3. Auflage, Übersetzung der englischsprachigen 3. Originalausgabe 2018") - .withField(StandardField.FILE, "ParsedFileField{description='', link='http://search.ebscohost.com/login.aspx?direct=true&scope=site&db=nlebk&db=nlabk&AN=1906353', fileType='PDF'}") + .withFiles(List.of(new LinkedFile("", "http://search.ebscohost.com/login.aspx?direct=true&scope=site&db=nlebk&db=nlabk&AN=1906353", StandardFileType.PDF))) .withField(StandardField.ISBN, "9783960886402") .withField(StandardField.KEYWORDS, "Klassen, Interfaces, Generics, Enums, Annotationen, Lambdas, Streams, Module, parallel, Parallele Programmierung, Serialisierung, funktional, funktionale Programmierung, Java EE, Jakarta EE") .withField(StandardField.ADDRESS, "Heidelberg") @@ -78,8 +80,7 @@ void complexSearchQueryURLCorrect() throws Exception { @Test void performSearchMatchingMultipleEntries() throws FetcherException { List searchResult = fetcher.performSearch("effective java bloch"); - assertEquals(bibEntryISBN9783960886402, searchResult.getFirst()); - assertEquals(bibEntryISBN0134685997, searchResult.get(1)); + assertEquals(List.of(bibEntryISBN9783960886402, bibEntryISBN0134685997), searchResult.subList(0, 1)); } @Test From d1c33d93d8c32c646e3cca41ab17cd07518f2b0d Mon Sep 17 00:00:00 2001 From: Oliver Kopp Date: Sun, 29 Sep 2024 22:52:40 +0200 Subject: [PATCH 12/13] Extract method --- .../importer/fileformat/MarcXmlParser.java | 34 ++++++++----------- .../importer/fetcher/BvbFetcherTest.java | 2 +- 2 files changed, 15 insertions(+), 21 deletions(-) diff --git a/src/main/java/org/jabref/logic/importer/fileformat/MarcXmlParser.java b/src/main/java/org/jabref/logic/importer/fileformat/MarcXmlParser.java index 9832507b07f..1e918099990 100644 --- a/src/main/java/org/jabref/logic/importer/fileformat/MarcXmlParser.java +++ b/src/main/java/org/jabref/logic/importer/fileformat/MarcXmlParser.java @@ -23,6 +23,7 @@ import org.jabref.model.entry.BibEntry; import org.jabref.model.entry.Date; import org.jabref.model.entry.LinkedFile; +import org.jabref.model.entry.field.Field; import org.jabref.model.entry.field.StandardField; import org.jabref.model.entry.types.StandardEntryType; import org.jabref.model.strings.StringUtil; @@ -381,17 +382,7 @@ private void putDoi(BibEntry bibEntry, Element datafield) { if ("e".equals(ind1) && StringUtil.isNotBlank("u") && StringUtil.isNotBlank(resource)) { // DOI String fulltext = getSubfield("3", datafield); - - if ("Volltext".equals(fulltext)) { - try { - LinkedFile linkedFile = new LinkedFile(URI.create(resource).toURL(), "PDF"); - bibEntry.setField(StandardField.FILE, linkedFile.toString()); - } catch (MalformedURLException e) { - LOGGER.info("Malformed URL: {}", resource); - } - } else { - bibEntry.setField(StandardField.DOI, resource); - } + handleVolltext(bibEntry, fulltext, resource, StandardField.DOI); } } @@ -403,17 +394,20 @@ private void putElectronicLocation(BibEntry bibEntry, Element datafield) { if ("4".equals(ind1) && "0".equals(ind2)) { String fulltext = getSubfield("3", datafield); String resource = getSubfield("u", datafield); + handleVolltext(bibEntry, fulltext, resource, StandardField.URL); + } + } - if ("Volltext".equals(fulltext) && StringUtil.isNotBlank(resource)) { - try { - LinkedFile linkedFile = new LinkedFile("", URI.create(resource).toURL(), StandardFileType.PDF.getName()); - bibEntry.setFiles(List.of(linkedFile)); - } catch (MalformedURLException | IllegalArgumentException e) { - LOGGER.info("Malformed URL: {}", resource); - } - } else { - bibEntry.setField(StandardField.URL, resource); + private static void handleVolltext(BibEntry bibEntry, String fieldName, String resource, Field fallBackField) { + if ("Volltext".equals(fieldName) && StringUtil.isNotBlank(resource)) { + try { + LinkedFile linkedFile = new LinkedFile("", URI.create(resource).toURL(), StandardFileType.PDF.getName()); + bibEntry.setFiles(List.of(linkedFile)); + } catch (MalformedURLException | IllegalArgumentException e) { + LOGGER.info("Malformed URL: {}", resource); } + } else { + bibEntry.setField(fallBackField, resource); } } diff --git a/src/test/java/org/jabref/logic/importer/fetcher/BvbFetcherTest.java b/src/test/java/org/jabref/logic/importer/fetcher/BvbFetcherTest.java index e7f39ee2c11..e1d08456fd4 100644 --- a/src/test/java/org/jabref/logic/importer/fetcher/BvbFetcherTest.java +++ b/src/test/java/org/jabref/logic/importer/fetcher/BvbFetcherTest.java @@ -80,7 +80,7 @@ void complexSearchQueryURLCorrect() throws Exception { @Test void performSearchMatchingMultipleEntries() throws FetcherException { List searchResult = fetcher.performSearch("effective java bloch"); - assertEquals(List.of(bibEntryISBN9783960886402, bibEntryISBN0134685997), searchResult.subList(0, 1)); + assertEquals(List.of(bibEntryISBN9783960886402, bibEntryISBN0134685997), searchResult.subList(0, 2)); } @Test From f406414dc67e6dafd0964b3e826b2574ece12f83 Mon Sep 17 00:00:00 2001 From: Oliver Kopp Date: Sun, 29 Sep 2024 23:06:44 +0200 Subject: [PATCH 13/13] Fix IllegalArgumentException in IEEE --- src/main/java/org/jabref/logic/importer/fetcher/IEEE.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/java/org/jabref/logic/importer/fetcher/IEEE.java b/src/main/java/org/jabref/logic/importer/fetcher/IEEE.java index f74803c8b99..6d1f93e9b65 100644 --- a/src/main/java/org/jabref/logic/importer/fetcher/IEEE.java +++ b/src/main/java/org/jabref/logic/importer/fetcher/IEEE.java @@ -30,6 +30,7 @@ import org.jabref.model.entry.field.StandardField; import org.jabref.model.entry.identifier.DOI; import org.jabref.model.entry.types.StandardEntryType; +import org.jabref.model.strings.StringUtil; import kong.unirest.core.json.JSONArray; import kong.unirest.core.json.JSONObject; @@ -118,10 +119,9 @@ private static BibEntry parseJsonResponse(JSONObject jsonEntry, Character keywor entry.setField(StandardField.ISBN, jsonEntry.optString("isbn")); entry.setField(StandardField.ISSN, jsonEntry.optString("issn")); entry.setField(StandardField.ISSUE, jsonEntry.optString("issue")); - try { - entry.addFile(new LinkedFile(URI.create(jsonEntry.optString("pdf_url")).toURL(), "PDF")); - } catch (MalformedURLException e) { - LOGGER.error("Fetched PDF URL String is malformed."); + String pdfUrl = jsonEntry.optString("pdf_url"); + if (!StringUtil.isBlank(pdfUrl)) { + entry.addFile(new LinkedFile("", pdfUrl, "PDF")); } entry.setField(StandardField.JOURNALTITLE, jsonEntry.optString("publication_title")); entry.setField(StandardField.DATE, jsonEntry.optString("publication_date"));