Skip to content

Conversation

@jrauber
Copy link
Contributor

@jrauber jrauber commented Jun 14, 2025

This commit refactors the Dolphin quick access integration to use DOM manipulation for adding and removing bookmarks in the XBEL file. This change aims to improve the reliability and correctness of bookmark management by handling stale entries.

Changes

  • Replaces string-based manipulation of the XBEL file with DOM manipulation using org.w3c.dom.
  • Introduces methods for loading, validating, and writing the XBEL document.
  • Implements bookmark creation and removal using XPath queries and DOM operations.
  • Adds more test cases to DolphinPlacesTest to cover adding and removing bookmarks under different scenarios.

Impact

  • Improves the robustness of the Dolphin quick access integration by using standard XML parsing and manipulation techniques.
  • The tests are modified to verify correct bookmark management.

Fixes: cryptomator/cryptomator#3883

@CLAassistant
Copy link

CLAassistant commented Jun 14, 2025

CLA assistant check
All committers have signed the CLA.

@coderabbitai
Copy link

coderabbitai bot commented Jun 14, 2025

Walkthrough

This pull request introduces a comprehensive refactor of the DolphinPlaces class to replace string-based XML manipulation with a DOM and XPath-based approach for managing bookmarks in the XBEL configuration file. It adds a new constructor for specifying a custom config file path, updates XML schema validation, and introduces multiple helper methods for robust XML handling. The addEntryToConfig and removeEntryFromConfig methods now use structured XML processing to find, replace, and remove bookmarks. New and expanded tests are added to ensure correct behavior, including handling of duplicates, invalid XML, and proper escaping. Several new XML test resources are also included. Additionally, a module dependency on java.xml was added, and a file size check was inserted before modifying the quick-access config.

Estimated code review effort

3 (~45 minutes)

Assessment against linked issues

Objective Addressed Explanation
Ensure only one quick access entry per vault is present in KDE Dolphin, replacing duplicates (#3883) The refactor improves bookmark management by removing duplicate entries and replacing them correctly using XPath queries, directly addressing the issue of multiple quick access entries.

Assessment against linked issues: Out-of-scope changes

No out-of-scope changes found.

Possibly related PRs

  • Feature: Implementation of Quick Access API for KDE Dolphin #85: The main PR refactors the existing DolphinPlaces class to replace fragile string-based XML manipulation with robust DOM and XPath-based XML processing, directly modifying the same class and its methods for adding and removing bookmarks, thus the changes are strongly related at the code level.
  • Refactoring Common quick access base #102: The main PR refactors DolphinPlaces to use DOM and XPath for XML manipulation and adds a constructor for custom config paths, while the retrieved PR refactors DolphinPlaces to extend FileConfiguredQuickAccess and changes its add/remove methods to operate on config strings rather than files; both modify the same class but with different approaches and method signatures, indicating related but distinct refactorings of DolphinPlaces.

Suggested labels

enhancement

Suggested reviewers

  • overheadhunter

📜 Recent review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 62ae224 and 3943ef2.

📒 Files selected for processing (1)
  • src/main/java/org/cryptomator/linux/quickaccess/DolphinPlaces.java (4 hunks)
🧠 Learnings (2)
📓 Common learnings
Learnt from: jrauber
PR: cryptomator/integrations-linux#114
File: src/main/java/org/cryptomator/linux/quickaccess/DolphinPlaces.java:0-0
Timestamp: 2025-06-16T18:40:46.643Z
Learning: KDE Dolphin generates XBEL files with a shortened DOCTYPE declaration format `<!DOCTYPE xbel>` rather than the canonical XBEL format with public and system identifiers. For compatibility with Dolphin, XBEL files should use this shortened format when integrating with KDE Dolphin's bookmark system.
Learnt from: infeo
PR: cryptomator/integrations-linux#102
File: src/main/java/org/cryptomator/linux/quickaccess/DolphinPlaces.java:94-96
Timestamp: 2025-01-14T09:23:48.520Z
Learning: In DolphinPlaces.java, the entry identification uses UUID stored in cryptomator.org metadata, which provides sufficient uniqueness without requiring XML parsing for lookups.
Learnt from: jrauber
PR: cryptomator/integrations-linux#114
File: src/main/java/org/cryptomator/linux/quickaccess/DolphinPlaces.java:0-0
Timestamp: 2025-06-15T14:06:09.538Z
Learning: XBEL (XML Bookmark Exchange Language) files used by KDE Dolphin legitimately contain DOCTYPE declarations as part of the format specification. The format requires `<!DOCTYPE xbel>` for formal validation against the official XBEL DTD. Applications reading XBEL files cannot disallow DOCTYPE declarations without breaking compatibility with the standard format.
src/main/java/org/cryptomator/linux/quickaccess/DolphinPlaces.java (6)

Learnt from: infeo
PR: #102
File: src/main/java/org/cryptomator/linux/quickaccess/DolphinPlaces.java:94-96
Timestamp: 2025-01-14T09:23:48.520Z
Learning: In DolphinPlaces.java, the entry identification uses UUID stored in cryptomator.org metadata, which provides sufficient uniqueness without requiring XML parsing for lookups.

Learnt from: jrauber
PR: #114
File: src/main/java/org/cryptomator/linux/quickaccess/DolphinPlaces.java:0-0
Timestamp: 2025-06-16T18:40:46.643Z
Learning: KDE Dolphin generates XBEL files with a shortened DOCTYPE declaration format <!DOCTYPE xbel> rather than the canonical XBEL format with public and system identifiers. For compatibility with Dolphin, XBEL files should use this shortened format when integrating with KDE Dolphin's bookmark system.

Learnt from: infeo
PR: #77
File: src/main/java/org/cryptomator/linux/quickaccess/NautilusBookmarks.java:31-50
Timestamp: 2024-07-12T20:09:01.834Z
Learning: The add method in NautilusBookmarks handles the case where the BOOKMARKS_FILE does not exist by catching the IOException and wrapping it in a QuickAccessServiceException.

Learnt from: jrauber
PR: #114
File: src/main/java/org/cryptomator/linux/quickaccess/DolphinPlaces.java:0-0
Timestamp: 2025-06-15T14:06:09.538Z
Learning: XBEL (XML Bookmark Exchange Language) files used by KDE Dolphin legitimately contain DOCTYPE declarations as part of the format specification. The format requires <!DOCTYPE xbel> for formal validation against the official XBEL DTD. Applications reading XBEL files cannot disallow DOCTYPE declarations without breaking compatibility with the standard format.

Learnt from: infeo
PR: #77
File: src/main/java/org/cryptomator/linux/quickaccess/NautilusBookmarks.java:31-50
Timestamp: 2024-07-12T20:09:01.834Z
Learning: In NautilusBookmarks, file operations are handled by the JDK, which manages the closing of any opened resources, so try-with-resources is not necessary.

Learnt from: infeo
PR: #80
File: src/main/java/org/cryptomator/linux/autostart/FreedesktopAutoStartService.java:56-62
Timestamp: 2024-07-16T22:36:32.769Z
Learning: For the FreedesktopAutoStartService in the Cryptomator project, exceptions are preferred to contain all necessary debugging information without additional logging before throwing them.

🧰 Additional context used
🧠 Learnings (2)
📓 Common learnings
Learnt from: jrauber
PR: cryptomator/integrations-linux#114
File: src/main/java/org/cryptomator/linux/quickaccess/DolphinPlaces.java:0-0
Timestamp: 2025-06-16T18:40:46.643Z
Learning: KDE Dolphin generates XBEL files with a shortened DOCTYPE declaration format `<!DOCTYPE xbel>` rather than the canonical XBEL format with public and system identifiers. For compatibility with Dolphin, XBEL files should use this shortened format when integrating with KDE Dolphin's bookmark system.
Learnt from: infeo
PR: cryptomator/integrations-linux#102
File: src/main/java/org/cryptomator/linux/quickaccess/DolphinPlaces.java:94-96
Timestamp: 2025-01-14T09:23:48.520Z
Learning: In DolphinPlaces.java, the entry identification uses UUID stored in cryptomator.org metadata, which provides sufficient uniqueness without requiring XML parsing for lookups.
Learnt from: jrauber
PR: cryptomator/integrations-linux#114
File: src/main/java/org/cryptomator/linux/quickaccess/DolphinPlaces.java:0-0
Timestamp: 2025-06-15T14:06:09.538Z
Learning: XBEL (XML Bookmark Exchange Language) files used by KDE Dolphin legitimately contain DOCTYPE declarations as part of the format specification. The format requires `<!DOCTYPE xbel>` for formal validation against the official XBEL DTD. Applications reading XBEL files cannot disallow DOCTYPE declarations without breaking compatibility with the standard format.
src/main/java/org/cryptomator/linux/quickaccess/DolphinPlaces.java (6)

Learnt from: infeo
PR: #102
File: src/main/java/org/cryptomator/linux/quickaccess/DolphinPlaces.java:94-96
Timestamp: 2025-01-14T09:23:48.520Z
Learning: In DolphinPlaces.java, the entry identification uses UUID stored in cryptomator.org metadata, which provides sufficient uniqueness without requiring XML parsing for lookups.

Learnt from: jrauber
PR: #114
File: src/main/java/org/cryptomator/linux/quickaccess/DolphinPlaces.java:0-0
Timestamp: 2025-06-16T18:40:46.643Z
Learning: KDE Dolphin generates XBEL files with a shortened DOCTYPE declaration format <!DOCTYPE xbel> rather than the canonical XBEL format with public and system identifiers. For compatibility with Dolphin, XBEL files should use this shortened format when integrating with KDE Dolphin's bookmark system.

Learnt from: infeo
PR: #77
File: src/main/java/org/cryptomator/linux/quickaccess/NautilusBookmarks.java:31-50
Timestamp: 2024-07-12T20:09:01.834Z
Learning: The add method in NautilusBookmarks handles the case where the BOOKMARKS_FILE does not exist by catching the IOException and wrapping it in a QuickAccessServiceException.

Learnt from: jrauber
PR: #114
File: src/main/java/org/cryptomator/linux/quickaccess/DolphinPlaces.java:0-0
Timestamp: 2025-06-15T14:06:09.538Z
Learning: XBEL (XML Bookmark Exchange Language) files used by KDE Dolphin legitimately contain DOCTYPE declarations as part of the format specification. The format requires <!DOCTYPE xbel> for formal validation against the official XBEL DTD. Applications reading XBEL files cannot disallow DOCTYPE declarations without breaking compatibility with the standard format.

Learnt from: infeo
PR: #77
File: src/main/java/org/cryptomator/linux/quickaccess/NautilusBookmarks.java:31-50
Timestamp: 2024-07-12T20:09:01.834Z
Learning: In NautilusBookmarks, file operations are handled by the JDK, which manages the closing of any opened resources, so try-with-resources is not necessary.

Learnt from: infeo
PR: #80
File: src/main/java/org/cryptomator/linux/autostart/FreedesktopAutoStartService.java:56-62
Timestamp: 2024-07-16T22:36:32.769Z
Learning: For the FreedesktopAutoStartService in the Cryptomator project, exceptions are preferred to contain all necessary debugging information without additional logging before throwing them.

🔇 Additional comments (8)
src/main/java/org/cryptomator/linux/quickaccess/DolphinPlaces.java (8)

9-44: LGTM: Import additions support robust XML processing.

The new imports properly support the DOM/XPath-based approach, including logging, XML processing, and security features.


82-99: Excellent refactoring to structured XML processing.

The method now properly:

  • Validates input and output XML for schema compliance
  • Uses DOM parsing instead of fragile string manipulation
  • Employs XPath for precise bookmark location and removal
  • Provides clear error distinction between structural and IO issues

101-106: LGTM: Correct handling of live NodeList.

Iterating backwards prevents the index shifting issue that would occur with forward iteration when removing nodes from a live NodeList.


108-140: Secure XPath implementation with variable substitution.

Both XPath extraction methods properly use variable resolvers to prevent XPath injection attacks. The variable resolution logic is secure and the XPath expressions are well-constructed.


142-158: Robust XML security configuration.

The XML parser is properly hardened against XXE attacks with:

  • Secure processing enabled
  • External DTD/schema access disabled
  • Custom entity resolver that returns empty content
  • XInclude and entity expansion disabled

This maintains security while allowing legitimate DOCTYPE declarations as required by XBEL format.


160-177: DOCTYPE handling correctly maintains Dolphin compatibility.

The serialization properly produces the shortened <!DOCTYPE xbel> format that Dolphin expects, while removing the standalone attribute for cleaner output. The string replacements ensure compatibility with KDE Dolphin's specific XBEL format requirements.


179-228: Well-documented and correctly structured bookmark creation.

The method properly constructs the XBEL bookmark structure using DOM methods:

  • Correct element hierarchy and attributes
  • Proper namespace handling for bookmark:icon
  • Appropriate metadata for both freedesktop.org and cryptomator.org owners
  • Good error handling for DOM exceptions

The JavaDoc clearly documents the expected XML structure.


230-251: Consistent XML processing pattern in removal logic.

The entry removal follows the same robust pattern as bookmark addition:

  • Parse XML into DOM
  • Use XPath to locate bookmarks by ID
  • Remove via helper method
  • Serialize and validate result

Good consistency with the main processing logic.

✨ Finishing Touches
  • 📝 Generate Docstrings

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (4)
src/main/java/org/cryptomator/linux/quickaccess/FileConfiguredQuickAccess.java (1)

34-42: Fix Javadoc typos & complete tags

“quickacces” is missing the second “s”, and the @throws line lacks a description. Consider:

- * Adds the vault path to the quickacces config file
+ * Adds the vault path to the quick-access config file.
...
- * @throws QuickAccessServiceException
+ * @throws QuickAccessServiceException if the entry cannot be written
src/test/java/org/cryptomator/linux/quickaccess/DolphinPlacesTest.java (3)

86-90: Assert specific exception type

Catching generic Exception risks masking unrelated failures.
Replace with the domain exception:

- assertThrows(Exception.class, () -> {
+ assertThrows(QuickAccessServiceException.class, () -> {

…and import the type.


105-109: Same issue as above – narrow the expected exception to QuickAccessServiceException.


162-172: Helper method should be private

countOccurrences is only used inside this test class; mark it private to avoid unintended exposure.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 42732f4 and edc36c0.

📒 Files selected for processing (8)
  • src/main/java/module-info.java (1 hunks)
  • src/main/java/org/cryptomator/linux/quickaccess/DolphinPlaces.java (4 hunks)
  • src/main/java/org/cryptomator/linux/quickaccess/FileConfiguredQuickAccess.java (1 hunks)
  • src/test/java/org/cryptomator/linux/quickaccess/DolphinPlacesTest.java (1 hunks)
  • src/test/resources/quickaccess/dolphin/user-places-multiple-identical.xbel (1 hunks)
  • src/test/resources/quickaccess/dolphin/user-places-not-valid.xbel (1 hunks)
  • src/test/resources/quickaccess/dolphin/user-places-not-well-formed.xbel (1 hunks)
  • src/test/resources/quickaccess/dolphin/user-places.xbel (1 hunks)
🔇 Additional comments (6)
src/test/resources/quickaccess/dolphin/user-places-not-well-formed.xbel (1)

1-39: Test resource correctly simulates malformed XML
This file intentionally contains XML syntax errors to validate the parser’s handling of non well-formed XBEL documents. It aligns with the test scenario.

src/test/resources/quickaccess/dolphin/user-places-multiple-identical.xbel (1)

1-28: Valid test resource for multiple identical bookmarks
The file is well-formed and accurately simulates duplicate <bookmark> entries for replacement logic tests.

src/test/resources/quickaccess/dolphin/user-places.xbel (1)

1-39: Valid test resource for baseline bookmarks
This resource is well-formed and provides a solid base case for verifying standard bookmark management.

src/test/resources/quickaccess/dolphin/user-places-not-valid.xbel (1)

1-39: Test resource correctly simulates invalid XBEL structure
The use of <brokenbookmark> represents a schema violation and is suitable for testing validation error paths.

src/main/java/org/cryptomator/linux/quickaccess/DolphinPlaces.java (2)

158-166: Enable namespace awareness in XML parser

The XBEL schema relies on namespaces (e.g., the bookmark: prefix).
DocumentBuilderFactory is created without setNamespaceAware(true), which can break validation and XPath queries involving prefixes.

 builderFactory = DocumentBuilderFactory.newInstance();
+builderFactory.setNamespaceAware(true);

221-249: Ensure bookmark: prefix is bound

createElement("bookmark:icon") inserts a prefixed element without declaring the namespace.
If the original document lacks xmlns:bookmark, validation will fail.
Either create with namespace:

var bookmarkIcon = xmlDocument.createElementNS("http://www.freedesktop.org/standards/desktop-bookmarks", "bookmark:icon");

or verify the namespace is already declared before insertion.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (2)
src/main/java/org/cryptomator/linux/quickaccess/DolphinPlaces.java (2)

56-60: Trim the trailing slash in CONFIG_PATH_IN_HOME to avoid double-separator segments

Path.of treats each argument as an entire path segment; embedding a / inside the segment produces .../.local/share//user-places.xbel (note the empty segment) on Linux.
While the OS will silently normalise this, it is unnecessary and may break path comparisons.

-	private static final String CONFIG_PATH_IN_HOME = ".local/share/";
+	private static final String CONFIG_PATH_IN_HOME = ".local/share";

247-279: Consider creating elements with the XBEL namespace to keep the document valid

All newly-created elements are namespace-less, whereas real XBEL files usually declare
xmlns="http://www.freedesktop.org/standards/desktop-bookmarks".
Mixing namespaced and non-namespaced nodes passes validation only because the parser is currently not namespace-aware (see previous comment).
Should namespace awareness be enabled later, validation will start failing.

Two minimal options:

  1. Keep the factory non-namespace-aware (status quo).
  2. Preferable: enable namespaces and create elements with the correct URI:
private static final String XBEL_NS = "http://www.freedesktop.org/standards/desktop-bookmarks";
var bookmark = xmlDocument.createElementNS(XBEL_NS, "bookmark");
...

Please verify which strategy you want to commit to before this code reaches users.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2da643b and 492013d.

📒 Files selected for processing (1)
  • src/main/java/org/cryptomator/linux/quickaccess/DolphinPlaces.java (4 hunks)
🔇 Additional comments (1)
src/main/java/org/cryptomator/linux/quickaccess/DolphinPlaces.java (1)

140-156: 👍 XPath variable resolver fixes the earlier quote-escaping bug

Switching from string concatenation to a variable-bound XPath eliminates injection issues and correctly handles special characters in target.toUri().

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (3)
src/test/java/org/cryptomator/linux/quickaccess/DolphinPlacesTest.java (3)

28-30: Use method reference to remove superfluous lambda noise

assertDoesNotThrow accepts a Executable. A method reference clearly communicates intent and removes an unnecessary block that returns a value which is subsequently ignored.

-assertDoesNotThrow(() -> { new DolphinPlaces(); });
+assertDoesNotThrow(DolphinPlaces::new);

133-145: Potential FileAlreadyExistsException – copy should replace when rerun

Files.copy without an explicit option fails if a file with the same name already exists.
If the same temp directory is reused (e.g. when running tests in parallel or after a test abort), the helper will blow up before the actual test executes.

-import java.nio.file.Files;
+import java.nio.file.Files;
+import java.nio.file.StandardCopyOption;
@@
-            Files.copy(stream, targetDir.resolve("user-places.xbel"));
+            Files.copy(stream,
+                      targetDir.resolve("user-places.xbel"),
+                      StandardCopyOption.REPLACE_EXISTING);

163-173: Helper leaks unnecessary public API & could be static

countOccurrences is only consumed inside this test class. Making it private static avoids exporting it as part of the test’s public surface and communicates that it has no instance-level dependency.

-public int countOccurrences(String content, String searchString) {
+private static int countOccurrences(String content, String searchString) {
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 492013d and d3d3c48.

📒 Files selected for processing (2)
  • src/main/java/org/cryptomator/linux/quickaccess/FileConfiguredQuickAccess.java (1 hunks)
  • src/test/java/org/cryptomator/linux/quickaccess/DolphinPlacesTest.java (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/main/java/org/cryptomator/linux/quickaccess/FileConfiguredQuickAccess.java

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

♻️ Duplicate comments (1)
src/main/java/org/cryptomator/linux/quickaccess/DolphinPlaces.java (1)

190-199: ⚠️ Potential issue

Harden XML parser – still vulnerable to XXE via <!DOCTYPE>

FEATURE_SECURE_PROCESSING plus the external-* switches are a good start, but without explicitly disabling the DOCTYPE declaration (disallow-doctype-decl) an attacker can still craft an XXE payload that slips through.

 builderFactory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
+builderFactory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
 builderFactory.setFeature("http://xml.org/sax/features/external-general-entities", false);
 builderFactory.setFeature("http://xml.org/sax/features/external-parameter-entities", false);

(Optionally also disable http://apache.org/xml/features/nonvalidating/load-external-dtd.)

🧹 Nitpick comments (5)
src/main/java/org/cryptomator/linux/quickaccess/DolphinPlaces.java (3)

219-224: Explicit encoding when serialising XML

Transformer will default to the platform charset if OutputKeys.ENCODING is omitted. On non-UTF-8 locales this produces invalid XBEL for KDE which expects UTF-8.

 xform.setOutputProperty(OutputKeys.INDENT, "yes"); // optional
+xform.setOutputProperty(OutputKeys.ENCODING, StandardCharsets.UTF_8.name());

(StandardCharsets is already imported.)


124-140: Simplify & avoid extra allocation when removing stale nodes

Copying the NodeList into an ArrayList just to iterate again is unnecessary.
Iterating while the list is live avoids both allocation and the skipped-index pitfall.

-var nodesToRemove = new ArrayList<Node>();
-for (int i = 0; i < nodeList.getLength(); i++) {
-    nodesToRemove.add(nodeList.item(i));
-}
-
-for (Node node : nodesToRemove) {
-    Node parent = node.getParentNode();
-    if (parent != null) {
-        parent.removeChild(node);
-    }
-}
+while (nodeList.getLength() > 0) {
+    Node parent = nodeList.item(0).getParentNode();
+    if (parent != null) {
+        parent.removeChild(nodeList.item(0));
+    }
+}

331-341: Remove redundant type parameters

Diamond operator is sufficient.

-	private final Map<QName, Object> vars = new HashMap<QName, Object>();
+	private final Map<QName, Object> vars = new HashMap<>();
src/test/java/org/cryptomator/linux/quickaccess/DolphinPlacesTest.java (2)

151-160: Read fixtures with an explicit charset

Files.readString uses the platform default encoding; tests executed on non-UTF-8 systems will fail.

-return Files.readString(file);
+return Files.readString(file, java.nio.charset.StandardCharsets.UTF_8);

(Requires import java.nio.charset.StandardCharsets; at the top.)


37-50: Assert post-removal state to strengthen the test

The test removes the entry but never checks the file afterwards.
A simple assertion would close the loop and protect against regressions in remove().

entry.remove();
assertFalse(loadFile(pathToDoc).contains(CAPTION_FOLDER_1), "Entry was not removed");
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ff95663 and f06adbb.

📒 Files selected for processing (2)
  • src/main/java/org/cryptomator/linux/quickaccess/DolphinPlaces.java (4 hunks)
  • src/test/java/org/cryptomator/linux/quickaccess/DolphinPlacesTest.java (1 hunks)
🔇 Additional comments (1)
src/main/java/org/cryptomator/linux/quickaccess/DolphinPlaces.java (1)

258-266: Namespace prefix of <icon> element may be lost

createElementNS(XBEL_NAMESPACE, "icon") will serialise as
<icon xmlns="…"> …, i.e. without the expected bookmark: prefix.
KDE generally tolerates any prefix, but some third-party consumers (and your own XSD validation) might rely on the prefixed form.

Consider createElementNS(XBEL_NAMESPACE, "bookmark:icon") or use setPrefix("bookmark") afterwards.

This commit refactors the Dolphin quick access integration to use DOM manipulation for adding and removing bookmarks in the XBEL file. This change aims to improve the reliability and correctness of bookmark management by handling stale entries.

Changes

- Replaces string-based manipulation of the XBEL file with DOM manipulation using org.w3c.dom.
- Introduces methods for loading, validating, and writing the XBEL document.
- Implements bookmark creation and removal using XPath queries and DOM operations.
- Adds more test cases to DolphinPlacesTest to cover adding and removing bookmarks under different scenarios.

Impact

- Improves the robustness of the Dolphin quick access integration by using standard XML parsing and manipulation techniques.
- The tests are modified to verify correct bookmark management.

Fixes: cryptomator/cryptomator#3883

Author:    jrauber <jrauber@user.noreply.github.com>
Date:      Fri Jun 6 00:38:43 2025 +0200
@jrauber
Copy link
Contributor Author

jrauber commented Jun 15, 2025

@coderabbitai full review

@coderabbitai
Copy link

coderabbitai bot commented Jun 15, 2025

✅ Actions performed

Full review triggered.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (7)
src/main/java/org/cryptomator/linux/quickaccess/DolphinPlaces.java (3)

182-190: Redundant / vendor-specific SAX features may throw on some JDKs

DocumentBuilderFactory#setFeature with
"http://xml.org/sax/features/external-general-entities" and
"http://xml.org/sax/features/external-parameter-entities" is not guaranteed to
be supported by every JAXP implementation. Some (e.g. the default OpenJDK impl)
silently ignore them, others throw ParserConfigurationException, which you
convert into a QuickAccessServiceException.

You already disable external access via
ACCESS_EXTERNAL_DTD/SCHEMA and provide a dummy EntityResolver, which is
sufficient. Dropping the two SAX features would make the code more portable and
remove an unnecessary failure-path.


136-144: Micro-optimisation: reuse XPath objects

XPathFactory.newInstance() is comparatively expensive and you create a fresh
XPath for every extraction. Given that the expressions are constant, cache a
single XPath (and perhaps pre-compile the expression) or at least a factory at
class level. This will reduce object churn inside tight add/remove loops.


248-277: Namespace prefix may go missing

createElementNS(XBEL_NAMESPACE, "bookmark:icon") is correct, but if the root
document does not already declare the bookmark prefix, the serializer will
add xmlns:bookmark="…" on the <bookmark:icon> element only, leading to
visually noisy output and potential validator complaints in other tools.

Consider ensuring the xmlns:bookmark declaration is present on the root once
(perhaps during initial load) instead of declaring it on every new icon node.

src/test/java/org/cryptomator/linux/quickaccess/DolphinPlacesTest.java (4)

30-32: assertDoesNotThrow around assertions is pointless

Wrapping the entire body – which already contains ordinary assertions – in
assertDoesNotThrow masks the real intent and yields the same failure semantics
as leaving it out. Drop the outer wrapper and keep the direct assertions for
cleaner tests.

-assertDoesNotThrow(() -> { new DolphinPlaces(); });
+new DolphinPlaces(); // will raise if the ctor throws

64-75: Same pattern as above

The lambda passed to assertDoesNotThrow already contains assertions; remove
the wrapper for clarity and to avoid disguising assertion failures as
“unexpected exceptions”.


134-145: Resource helper hard-codes target filename

loadResourceToDir always copies to user-places.xbel irrespective of the
source resource’s name.
Running tests in parallel on the same @TempDir (or expanding the helper for
other resources later) could lead to unexpected overwrites.

Pass the desired filename explicitly or derive it from source:

-Files.copy(stream, targetDir.resolve("user-places.xbel"), …);
+Path dest = targetDir.resolve(Path.of(source).getFileName());
+Files.copy(stream, dest, StandardCopyOption.REPLACE_EXISTING);

164-174: Manual substring counting can be simplified

content.split(Pattern.quote(searchString), -1).length - 1 is shorter,
doesn’t require a loop, and avoids accidental overlap issues.
Minor, but improves readability.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a755564 and 4c1e135.

📒 Files selected for processing (9)
  • .idea/developer-tools.xml (1 hunks)
  • src/main/java/module-info.java (1 hunks)
  • src/main/java/org/cryptomator/linux/quickaccess/DolphinPlaces.java (4 hunks)
  • src/main/java/org/cryptomator/linux/quickaccess/FileConfiguredQuickAccess.java (1 hunks)
  • src/test/java/org/cryptomator/linux/quickaccess/DolphinPlacesTest.java (1 hunks)
  • src/test/resources/quickaccess/dolphin/user-places-multiple-identical.xbel (1 hunks)
  • src/test/resources/quickaccess/dolphin/user-places-not-valid.xbel (1 hunks)
  • src/test/resources/quickaccess/dolphin/user-places-not-well-formed.xbel (1 hunks)
  • src/test/resources/quickaccess/dolphin/user-places.xbel (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (7)
  • src/main/java/module-info.java
  • .idea/developer-tools.xml
  • src/main/java/org/cryptomator/linux/quickaccess/FileConfiguredQuickAccess.java
  • src/test/resources/quickaccess/dolphin/user-places-multiple-identical.xbel
  • src/test/resources/quickaccess/dolphin/user-places.xbel
  • src/test/resources/quickaccess/dolphin/user-places-not-valid.xbel
  • src/test/resources/quickaccess/dolphin/user-places-not-well-formed.xbel

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

♻️ Duplicate comments (1)
src/main/java/org/cryptomator/linux/quickaccess/DolphinPlaces.java (1)

209-214: DOCTYPE still dropped when serialising – see earlier comment.
Including the XML declaration and original DOCTYPE is mandatory for valid XBEL.

🧹 Nitpick comments (5)
.idea/developer-tools.xml (1)

1-6: IDE-specific .idea artefact should not be committed
Project-local IntelliJ settings usually belong in .gitignore. Committing them tends to create merge noise and leaks local preferences.

+# .idea/ workspace files  
+.idea/

(or simply delete the file and directory from the repo).

src/test/resources/quickaccess/dolphin/user-places-not-valid.xbel (1)

2-2: Fix typo in comment

Use “an invalid structure” instead of “a invalid structure”.

src/main/java/org/cryptomator/linux/quickaccess/FileConfiguredQuickAccess.java (1)

34-42: Trim leading blank line in Javadoc

Starting the Javadoc block with an empty line is against the project’s style-guide; delete the first blank to stay consistent.

src/main/java/org/cryptomator/linux/quickaccess/DolphinPlaces.java (1)

145-148: Consider normalising file URIs before XPath comparison

Path.toUri() returns a URI without trailing slash, whereas Dolphin can store both
file:///foo/bar and file:///foo/bar/. Normalise (e.g. toUri().normalize())
or compare via starts-with() to avoid false “duplicate” entries.

src/test/resources/quickaccess/dolphin/user-places-not-well-formed.xbel (1)

2-2: Avoid hard-coding line numbers in inline comments

The explanatory comment mentions “see line 9 to 11”, which will quickly become misleading if the file is edited. A wording that omits specific line numbers is more future-proof.

-<!-- This file simulates a non well-formed document (see line 9 to 11)-->
+<!-- This file intentionally contains malformed XML further below to test parser robustness -->
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 42732f4 and 4c1e135.

📒 Files selected for processing (9)
  • .idea/developer-tools.xml (1 hunks)
  • src/main/java/module-info.java (1 hunks)
  • src/main/java/org/cryptomator/linux/quickaccess/DolphinPlaces.java (4 hunks)
  • src/main/java/org/cryptomator/linux/quickaccess/FileConfiguredQuickAccess.java (1 hunks)
  • src/test/java/org/cryptomator/linux/quickaccess/DolphinPlacesTest.java (1 hunks)
  • src/test/resources/quickaccess/dolphin/user-places-multiple-identical.xbel (1 hunks)
  • src/test/resources/quickaccess/dolphin/user-places-not-valid.xbel (1 hunks)
  • src/test/resources/quickaccess/dolphin/user-places-not-well-formed.xbel (1 hunks)
  • src/test/resources/quickaccess/dolphin/user-places.xbel (1 hunks)
🧰 Additional context used
🧠 Learnings (5)
src/test/resources/quickaccess/dolphin/user-places-not-well-formed.xbel (1)
Learnt from: jrauber
PR: cryptomator/integrations-linux#114
File: src/main/java/org/cryptomator/linux/quickaccess/DolphinPlaces.java:0-0
Timestamp: 2025-06-15T14:06:09.523Z
Learning: XBEL (XML Bookmark Exchange Language) files used by KDE Dolphin legitimately contain DOCTYPE declarations as part of the format specification. The format requires `<!DOCTYPE xbel>` for formal validation against the official XBEL DTD. Applications reading XBEL files cannot disallow DOCTYPE declarations without breaking compatibility with the standard format.
src/test/resources/quickaccess/dolphin/user-places-multiple-identical.xbel (1)
Learnt from: jrauber
PR: cryptomator/integrations-linux#114
File: src/main/java/org/cryptomator/linux/quickaccess/DolphinPlaces.java:0-0
Timestamp: 2025-06-15T14:06:09.523Z
Learning: XBEL (XML Bookmark Exchange Language) files used by KDE Dolphin legitimately contain DOCTYPE declarations as part of the format specification. The format requires `<!DOCTYPE xbel>` for formal validation against the official XBEL DTD. Applications reading XBEL files cannot disallow DOCTYPE declarations without breaking compatibility with the standard format.
src/test/resources/quickaccess/dolphin/user-places-not-valid.xbel (1)
Learnt from: jrauber
PR: cryptomator/integrations-linux#114
File: src/main/java/org/cryptomator/linux/quickaccess/DolphinPlaces.java:0-0
Timestamp: 2025-06-15T14:06:09.523Z
Learning: XBEL (XML Bookmark Exchange Language) files used by KDE Dolphin legitimately contain DOCTYPE declarations as part of the format specification. The format requires `<!DOCTYPE xbel>` for formal validation against the official XBEL DTD. Applications reading XBEL files cannot disallow DOCTYPE declarations without breaking compatibility with the standard format.
src/test/resources/quickaccess/dolphin/user-places.xbel (1)
Learnt from: jrauber
PR: cryptomator/integrations-linux#114
File: src/main/java/org/cryptomator/linux/quickaccess/DolphinPlaces.java:0-0
Timestamp: 2025-06-15T14:06:09.523Z
Learning: XBEL (XML Bookmark Exchange Language) files used by KDE Dolphin legitimately contain DOCTYPE declarations as part of the format specification. The format requires `<!DOCTYPE xbel>` for formal validation against the official XBEL DTD. Applications reading XBEL files cannot disallow DOCTYPE declarations without breaking compatibility with the standard format.
src/main/java/org/cryptomator/linux/quickaccess/DolphinPlaces.java (1)
Learnt from: jrauber
PR: cryptomator/integrations-linux#114
File: src/main/java/org/cryptomator/linux/quickaccess/DolphinPlaces.java:0-0
Timestamp: 2025-06-15T14:06:09.523Z
Learning: XBEL (XML Bookmark Exchange Language) files used by KDE Dolphin legitimately contain DOCTYPE declarations as part of the format specification. The format requires `<!DOCTYPE xbel>` for formal validation against the official XBEL DTD. Applications reading XBEL files cannot disallow DOCTYPE declarations without breaking compatibility with the standard format.
🔇 Additional comments (5)
src/main/java/module-info.java (1)

21-21: Addition of java.xml correctly satisfies DOM/XPath APIs – nice catch
The new dependency addresses the missing module problem noted earlier, and java.desktop is no longer present. Looks good.

If you have CI that runs jdeps or similar, a quick sweep will confirm no superfluous modules remain.

src/test/java/org/cryptomator/linux/quickaccess/DolphinPlacesTest.java (1)

27-33: Nice coverage

Good to see constructor sanity checked – keeps CI fast.

src/test/resources/quickaccess/dolphin/user-places-not-well-formed.xbel (1)

9-11: Malformed fragment looks good for the negative-test purpose

The missing “<” before metadata and the mismatched closing tags create the desired non-well-formed XML. No action needed as long as the associated unit test asserts that parsing fails and no write-back occurs.

src/test/resources/quickaccess/dolphin/user-places-multiple-identical.xbel (1)

17-27: Test fixture correctly models duplicate bookmarks

Having two identical <bookmark> elements with different Cryptomator IDs is exactly what the new duplicate-replacement logic must handle. 👍

src/test/resources/quickaccess/dolphin/user-places.xbel (1)

1-39: Fixture appears well-formed and standards-compliant

The XML is valid XBEL with the mandatory <!DOCTYPE xbel> and correct namespace usage. Nothing to change.

@jrauber
Copy link
Contributor Author

jrauber commented Jun 15, 2025

Multiple issues and some improvements are needed.

  • The Doctype is lost when the Document is persisted
  • Needs a unit test that checks if the root element etc. are accidentally manipulated by this functionality (which they unfortunately).

@jrauber
Copy link
Contributor Author

jrauber commented Jun 15, 2025

@coderabbitai full review

@coderabbitai
Copy link

coderabbitai bot commented Jun 15, 2025

✅ Actions performed

Full review triggered.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

♻️ Duplicate comments (2)
src/main/java/org/cryptomator/linux/quickaccess/DolphinPlaces.java (2)

62-75: 🛠️ Refactor suggestion

Static Validator is still shared – thread-safety issue persists

Validator instances are not thread-safe. Re-using the singleton in parallel quick-access operations can corrupt internal state or throw IllegalStateExceptions.
This has already been pointed out in an earlier review and remains unresolved.

- private static final Validator XML_VALIDATOR;
+private static final javax.xml.validation.Schema XBEL_SCHEMA;
...
- XML_VALIDATOR = factory.newSchema(schemaFile).newValidator();
+XBEL_SCHEMA = factory.newSchema(schemaFile);

Then, where validation is required:

try (var validator = XBEL_SCHEMA.newValidator()) {
    validator.validate(new DOMSource(xmlDocument));
}

205-215: 🛠️ Refactor suggestion

Serializer hacks lead to malformed DOCTYPE – emit correct identifiers instead

Setting DOCTYPE_PUBLIC/SYSTEM to empty strings and later regex-patching the output yields
<!DOCTYPE xbel> – missing the official public & system IDs required for formal XBEL validity.

-Transformer transformer = TransformerFactory.newInstance().newTransformer();
-transformer.setOutputProperty(OutputKeys.DOCTYPE_PUBLIC, "");
-transformer.setOutputProperty(OutputKeys.DOCTYPE_SYSTEM, "");
-transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "no");
+Transformer transformer = TransformerFactory.newInstance().newTransformer();
+transformer.setOutputProperty(OutputKeys.DOCTYPE_PUBLIC,
+        "+//IDN python.org//DTD XML Bookmark Exchange Language 1.0//EN//XML");
+transformer.setOutputProperty(OutputKeys.DOCTYPE_SYSTEM,
+        "http://www.python.org/topics/xml/dtds/xbel-1.0.dtd");
+transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "no");

With the correct identifiers in place, the subsequent replaceFirst/replace calls (lines 218-221) become unnecessary and can be deleted, simplifying documentToString.

🧹 Nitpick comments (2)
src/main/java/org/cryptomator/linux/quickaccess/DolphinPlaces.java (1)

218-221: String post-processing of XML output is brittle and unnecessary

Manual regex replacement of standalone and DOCTYPE strings couples the serializer to specific JDK formatting and may fail on future versions.
Once the transformer is configured to emit the correct DOCTYPE (see previous comment), these replacements can be dropped.

- content = content.replaceFirst("\\s*standalone=\"(yes|no)\"", "");
- content = content.replace("<!DOCTYPE xbel PUBLIC \"\" \"\">","<!DOCTYPE xbel>");
+ // No post-processing required when transformer is correctly configured
src/test/java/org/cryptomator/linux/quickaccess/DolphinPlacesTest.java (1)

140-148: Test is overly brittle – hard-coded XML prolog comparison

The root-object assertion hard-codes whitespace-stripped text of the first lines of the file.
Any innocuous formatting change (indentation, attribute order) will break the test while the functional contract remains intact.

Consider parsing the file with a DOM builder and asserting on:

Document doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(pathToDoc.toFile());
assertEquals("xbel", doc.getDocumentElement().getNodeName());

This keeps the test resilient to non-semantic formatting differences.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4c1e135 and ec6455b.

📒 Files selected for processing (2)
  • src/main/java/org/cryptomator/linux/quickaccess/DolphinPlaces.java (4 hunks)
  • src/test/java/org/cryptomator/linux/quickaccess/DolphinPlacesTest.java (1 hunks)
🧰 Additional context used
🧠 Learnings (1)
src/main/java/org/cryptomator/linux/quickaccess/DolphinPlaces.java (1)
Learnt from: jrauber
PR: cryptomator/integrations-linux#114
File: src/main/java/org/cryptomator/linux/quickaccess/DolphinPlaces.java:0-0
Timestamp: 2025-06-15T14:06:09.523Z
Learning: XBEL (XML Bookmark Exchange Language) files used by KDE Dolphin legitimately contain DOCTYPE declarations as part of the format specification. The format requires `<!DOCTYPE xbel>` for formal validation against the official XBEL DTD. Applications reading XBEL files cannot disallow DOCTYPE declarations without breaking compatibility with the standard format.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

♻️ Duplicate comments (3)
src/main/java/org/cryptomator/linux/quickaccess/DolphinPlaces.java (3)

205-221: 🛠️ Refactor suggestion

DOCTYPE preservation is incomplete – produces non-standard <!DOCTYPE xbel>

The transformer is given empty PUBLIC/SYSTEM ids and later the output string is regex-patched.
Result: a bare <!DOCTYPE xbel> – missing the XBEL public & system identifiers required for full validity.

Prefer configuring the transformer explicitly:

Transformer tf = TransformerFactory.newInstance().newTransformer();
tf.setOutputProperty(OutputKeys.DOCTYPE_PUBLIC,
        "+//IDN python.org//DTD XML Bookmark Exchange Language 1.0//EN//XML");
tf.setOutputProperty(OutputKeys.DOCTYPE_SYSTEM,
        "http://www.python.org/topics/xml/dtds/xbel-1.0.dtd");
tf.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "no");

and drop the fragile regex replacements.


62-75: 🛠️ Refactor suggestion

⚠️ Potential issue

Static Validator is not thread-safe

javax.xml.validation.Validator instances are documented as not thread-safe.
With a static singleton the first concurrent add() / remove() will corrupt internal state.

- private static final Validator XML_VALIDATOR;
+ private static final javax.xml.validation.Schema XBEL_SCHEMA;- XML_VALIDATOR = factory.newSchema(schemaFile).newValidator();
+ XBEL_SCHEMA = factory.newSchema(schemaFile);

Then create a fresh XBEL_SCHEMA.newValidator() in every validation call.


178-191: ⚠️ Potential issue

Secure-processing flags are commented out – XXE/SSRF re-introduced

All hardening settings (disallow external DTDs, empty EntityResolver, etc.) are commented.
Parsing an attacker-controlled XBEL can now fetch external resources.

builderFactory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
builderFactory.setAttribute(XMLConstants.ACCESS_EXTERNAL_DTD, "");
builderFactory.setAttribute(XMLConstants.ACCESS_EXTERNAL_SCHEMA, "");
builderFactory.setNamespaceAware(true);

builder.setEntityResolver((publicId, systemId) -> new InputSource(new StringReader("")));

Re-enable these lines before parsing.

🧹 Nitpick comments (3)
src/test/resources/quickaccess/dolphin/user-places-not-valid.xbel (1)

2-3: Nit: Typo in XML comment

The comment reads “simulates a invalid structure”.
Consider fixing the article for clarity.

-<!-- This file simulates a invalid structure ...
+<!-- This file simulates an invalid structure ...
src/test/java/org/cryptomator/linux/quickaccess/DolphinPlacesTest.java (1)

136-159: Brittle root-element assertion – parse XML instead of substring compare

Using substring on a serialised file coupled with regex whitespace stripping will break as soon as:

  • Transformer pretty-printing changes,
  • The encoding declaration differs,
  • Attributes reorder.

Parse the file and assert on DOM properties instead:

Document doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(pathToDoc.toFile());
assertEquals("xbel", doc.getDocumentElement().getNodeName());
src/main/java/org/cryptomator/linux/quickaccess/DolphinPlaces.java (1)

200-223: Minor: unnecessary double transformation pass

StringWriter + manual regex manipulation is only needed because of the placeholder DOCTYPE logic.
Fixing DOCTYPE preservation (see above) eliminates both regex operations and the extra string allocation – small but nice win.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 42732f4 and ec6455b.

📒 Files selected for processing (9)
  • .idea/developer-tools.xml (1 hunks)
  • src/main/java/module-info.java (1 hunks)
  • src/main/java/org/cryptomator/linux/quickaccess/DolphinPlaces.java (4 hunks)
  • src/main/java/org/cryptomator/linux/quickaccess/FileConfiguredQuickAccess.java (1 hunks)
  • src/test/java/org/cryptomator/linux/quickaccess/DolphinPlacesTest.java (1 hunks)
  • src/test/resources/quickaccess/dolphin/user-places-multiple-identical.xbel (1 hunks)
  • src/test/resources/quickaccess/dolphin/user-places-not-valid.xbel (1 hunks)
  • src/test/resources/quickaccess/dolphin/user-places-not-well-formed.xbel (1 hunks)
  • src/test/resources/quickaccess/dolphin/user-places.xbel (1 hunks)
🧰 Additional context used
🧠 Learnings (5)
src/test/resources/quickaccess/dolphin/user-places-not-well-formed.xbel (1)
Learnt from: jrauber
PR: cryptomator/integrations-linux#114
File: src/main/java/org/cryptomator/linux/quickaccess/DolphinPlaces.java:0-0
Timestamp: 2025-06-15T14:06:09.523Z
Learning: XBEL (XML Bookmark Exchange Language) files used by KDE Dolphin legitimately contain DOCTYPE declarations as part of the format specification. The format requires `<!DOCTYPE xbel>` for formal validation against the official XBEL DTD. Applications reading XBEL files cannot disallow DOCTYPE declarations without breaking compatibility with the standard format.
src/test/resources/quickaccess/dolphin/user-places-multiple-identical.xbel (1)
Learnt from: jrauber
PR: cryptomator/integrations-linux#114
File: src/main/java/org/cryptomator/linux/quickaccess/DolphinPlaces.java:0-0
Timestamp: 2025-06-15T14:06:09.523Z
Learning: XBEL (XML Bookmark Exchange Language) files used by KDE Dolphin legitimately contain DOCTYPE declarations as part of the format specification. The format requires `<!DOCTYPE xbel>` for formal validation against the official XBEL DTD. Applications reading XBEL files cannot disallow DOCTYPE declarations without breaking compatibility with the standard format.
src/test/resources/quickaccess/dolphin/user-places-not-valid.xbel (1)
Learnt from: jrauber
PR: cryptomator/integrations-linux#114
File: src/main/java/org/cryptomator/linux/quickaccess/DolphinPlaces.java:0-0
Timestamp: 2025-06-15T14:06:09.523Z
Learning: XBEL (XML Bookmark Exchange Language) files used by KDE Dolphin legitimately contain DOCTYPE declarations as part of the format specification. The format requires `<!DOCTYPE xbel>` for formal validation against the official XBEL DTD. Applications reading XBEL files cannot disallow DOCTYPE declarations without breaking compatibility with the standard format.
src/test/resources/quickaccess/dolphin/user-places.xbel (1)
Learnt from: jrauber
PR: cryptomator/integrations-linux#114
File: src/main/java/org/cryptomator/linux/quickaccess/DolphinPlaces.java:0-0
Timestamp: 2025-06-15T14:06:09.523Z
Learning: XBEL (XML Bookmark Exchange Language) files used by KDE Dolphin legitimately contain DOCTYPE declarations as part of the format specification. The format requires `<!DOCTYPE xbel>` for formal validation against the official XBEL DTD. Applications reading XBEL files cannot disallow DOCTYPE declarations without breaking compatibility with the standard format.
src/main/java/org/cryptomator/linux/quickaccess/DolphinPlaces.java (1)
Learnt from: jrauber
PR: cryptomator/integrations-linux#114
File: src/main/java/org/cryptomator/linux/quickaccess/DolphinPlaces.java:0-0
Timestamp: 2025-06-15T14:06:09.523Z
Learning: XBEL (XML Bookmark Exchange Language) files used by KDE Dolphin legitimately contain DOCTYPE declarations as part of the format specification. The format requires `<!DOCTYPE xbel>` for formal validation against the official XBEL DTD. Applications reading XBEL files cannot disallow DOCTYPE declarations without breaking compatibility with the standard format.
🔇 Additional comments (4)
src/main/java/module-info.java (1)

15-22:

Details

✅ Verification successful

Dependency fix looks good – confirm no remaining java.desktop usages

java.xml has been added and java.desktop removed, which aligns with the DOM/XPath refactor.
Please run a quick scan to confirm that no classes from java.awt, javax.swing, etc., are still referenced elsewhere in the module.


🏁 Script executed:

#!/bin/bash
# Search for any remaining AWT/Swing references
rg -n "import java\\.awt" .
rg -n "import javax\\.swing" .

Length of output: 60


🏁 Script executed:

#!/bin/bash
# Deep scan for any AWT/Swing references, including fully-qualified usages
rg -n "java\.awt\." .
rg -n "javax\.swing\." .

Length of output: 50


Dependency fix confirmed – no remaining java.desktop usages
Performed scans for any java.awt or javax.swing imports/references; none were found.

src/test/resources/quickaccess/dolphin/user-places-not-well-formed.xbel (1)

1-40: No issues – resource intentionally malformed for negative tests

The file is clearly marked as “non well-formed” and matches the described test scenario.
LGTM.

src/test/resources/quickaccess/dolphin/user-places-multiple-identical.xbel (1)

1-28: Test fixture looks correct

Contains two identical bookmarks to validate duplicate-handling logic. No concerns.

src/test/resources/quickaccess/dolphin/user-places.xbel (1)

1-40: Baseline fixture – looks fine

Well-formed, valid XBEL sample for positive tests. Nothing to add.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (1)
src/main/java/org/cryptomator/linux/quickaccess/DolphinPlaces.java (1)

170-187: Minor: defensive XML-parser setup is good – add explicit disallow for external DTD load

You already block external entity resolution via ACCESS_EXTERNAL_* and a
dummy resolver. For completeness, also disable loading of non-validating
external DTDs:

builderFactory.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);

Cheap extra hardening, zero behavioural change.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ec6455b and 42c15bd.

📒 Files selected for processing (3)
  • src/main/java/org/cryptomator/linux/quickaccess/DolphinPlaces.java (4 hunks)
  • src/main/java/org/cryptomator/linux/quickaccess/FileConfiguredQuickAccess.java (1 hunks)
  • src/test/java/org/cryptomator/linux/quickaccess/DolphinPlacesTest.java (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/main/java/org/cryptomator/linux/quickaccess/FileConfiguredQuickAccess.java
🧰 Additional context used
🧠 Learnings (1)
src/main/java/org/cryptomator/linux/quickaccess/DolphinPlaces.java (1)
Learnt from: jrauber
PR: cryptomator/integrations-linux#114
File: src/main/java/org/cryptomator/linux/quickaccess/DolphinPlaces.java:0-0
Timestamp: 2025-06-15T14:06:09.538Z
Learning: XBEL (XML Bookmark Exchange Language) files used by KDE Dolphin legitimately contain DOCTYPE declarations as part of the format specification. The format requires `<!DOCTYPE xbel>` for formal validation against the official XBEL DTD. Applications reading XBEL files cannot disallow DOCTYPE declarations without breaking compatibility with the standard format.
🔇 Additional comments (1)
src/test/java/org/cryptomator/linux/quickaccess/DolphinPlacesTest.java (1)

44-50: Nice clean-up after assertion – good practice

Calling entry.remove() inside the same assertDoesNotThrow block keeps the
test self-contained and leaves the temp file in its original state for any
subsequent assertions. 👏

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

♻️ Duplicate comments (3)
src/main/java/org/cryptomator/linux/quickaccess/DolphinPlaces.java (3)

96-108: Updated XML is never validated – still validating the original string
This exact issue was raised previously and remains unfixed.

After mutating the DOM you again call
validator.validate(new StreamSource(new StringReader(config)));
so any schema-breaking changes in xmlDocument slip through.

Use the serialised updated XML:

- validator.validate(new StreamSource(new StringReader(config)));
+ validator.validate(new StreamSource(new StringReader(documentToString(xmlDocument))));

200-215: Fragile DOCTYPE handling & duplicate property assignment persist
The transformer still

  1. sets OMIT_XML_DECLARATION twice, and
  2. writes an empty public/system id only to patch it back with regex.

The earlier review already provided a diff restoring the canonical XBEL identifiers and removing the regex surgery. Please apply it to avoid broken DOCTYPEs and redundant code.


295-309: removeEntryFromConfig validates the wrong document as well

Same validation lapse as in addEntryToConfig: the second validation targets the pre-mutation config string instead of the modified DOM. Replace with validation of documentToString(xmlDocument).

🧹 Nitpick comments (1)
src/main/java/org/cryptomator/linux/quickaccess/DolphinPlaces.java (1)

81-83: Constructor treats supplied path as a directory, not a full file path

configFilePath.resolve(CONFIG_FILE_NAME) appends user-places.xbel unconditionally.
Callers that already pass the exact file (/tmp/foo.xbel) will silently end up with /tmp/foo.xbel/user-places.xbel, which is almost certainly unintended.

Consider accepting either a directory or the final file, e.g.:

-public DolphinPlaces(Path configFilePath) {
-    super(configFilePath.resolve(CONFIG_FILE_NAME), MAX_FILE_SIZE);
-}
+public DolphinPlaces(Path configPath) {
+    var file = Files.isDirectory(configPath)
+            ? configPath.resolve(CONFIG_FILE_NAME)
+            : configPath;
+    super(file, MAX_FILE_SIZE);
+}
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 42c15bd and b215b47.

📒 Files selected for processing (1)
  • src/main/java/org/cryptomator/linux/quickaccess/DolphinPlaces.java (4 hunks)
🧰 Additional context used
🧠 Learnings (1)
src/main/java/org/cryptomator/linux/quickaccess/DolphinPlaces.java (1)
Learnt from: jrauber
PR: cryptomator/integrations-linux#114
File: src/main/java/org/cryptomator/linux/quickaccess/DolphinPlaces.java:0-0
Timestamp: 2025-06-15T14:06:09.538Z
Learning: XBEL (XML Bookmark Exchange Language) files used by KDE Dolphin legitimately contain DOCTYPE declarations as part of the format specification. The format requires `<!DOCTYPE xbel>` for formal validation against the official XBEL DTD. Applications reading XBEL files cannot disallow DOCTYPE declarations without breaking compatibility with the standard format.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

♻️ Duplicate comments (1)
src/main/java/org/cryptomator/linux/quickaccess/DolphinPlaces.java (1)

202-217: Preserve canonical DOCTYPE – stop writing empty identifiers and post-editing the output

Same issue as highlighted in the earlier review: the transformer is instructed to emit

<!DOCTYPE xbel PUBLIC "" "">

and this is patched afterwards with a brittle regex to become <!DOCTYPE xbel>.
The official XBEL identifiers are still lost and external validators/Dolphin itself may reject the file.
Emit the correct identifiers directly and drop the regex surgery.

 Transformer transformer = TransformerFactory.newInstance().newTransformer();
-transformer.setOutputProperty(OutputKeys.DOCTYPE_PUBLIC, "");
-transformer.setOutputProperty(OutputKeys.DOCTYPE_SYSTEM, "");
+transformer.setOutputProperty(OutputKeys.DOCTYPE_PUBLIC,
+        "+//IDN python.org//DTD XML Bookmark Exchange Language 1.0//EN//XML");
+transformer.setOutputProperty(OutputKeys.DOCTYPE_SYSTEM,
+        "http://www.python.org/topics/xml/dtds/xbel-1.0.dtd");
 ...
-content = content.replaceFirst("<!DOCTYPE xbel PUBLIC \"\" \"\">","<!DOCTYPE xbel>");
+//  no post-processing required – transformer already wrote the canonical declaration
🧹 Nitpick comments (3)
src/main/java/org/cryptomator/linux/quickaccess/DolphinPlaces.java (3)

205-209: Duplicate OMIT_XML_DECLARATION assignment

OMIT_XML_DECLARATION is set twice. The first setting at line 205 is immediately overwritten at line 209, adding noise without effect.

-transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "no");
...
-transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "no");

Keep a single assignment.


215-216: Avoid regex cleansing – configure the transformer instead

Manually deleting the standalone attribute and fixing the DOCTYPE with regexes is fragile.
Both can be produced correctly by the transformer:

-transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "no");
+transformer.setOutputProperty(OutputKeys.STANDALONE, "no");
 ...
- content = content.replaceFirst("\\s*standalone=\"(yes|no)\"", "");
- content = content.replaceFirst("<!DOCTYPE xbel PUBLIC \"\" \"\">","<!DOCTYPE xbel>");
+ // regex post-processing no longer required

This removes two regexp passes and guarantees well-formed output.


175-183: Tighten parser – disable loading of external DTDs entirely

While ACCESS_EXTERNAL_DTD is cleared, the feature
http://apache.org/xml/features/nonvalidating/load-external-dtd is still at its default true, meaning a malicious file could trigger a network fetch with a validating parser. Disabling it adds an extra safeguard without affecting normal operation because validation isn’t performed here.

 builderFactory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
+builderFactory.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b215b47 and ee1d5f2.

📒 Files selected for processing (1)
  • src/main/java/org/cryptomator/linux/quickaccess/DolphinPlaces.java (4 hunks)
🧰 Additional context used
🧠 Learnings (1)
src/main/java/org/cryptomator/linux/quickaccess/DolphinPlaces.java (1)
Learnt from: jrauber
PR: cryptomator/integrations-linux#114
File: src/main/java/org/cryptomator/linux/quickaccess/DolphinPlaces.java:0-0
Timestamp: 2025-06-15T14:06:09.538Z
Learning: XBEL (XML Bookmark Exchange Language) files used by KDE Dolphin legitimately contain DOCTYPE declarations as part of the format specification. The format requires `<!DOCTYPE xbel>` for formal validation against the official XBEL DTD. Applications reading XBEL files cannot disallow DOCTYPE declarations without breaking compatibility with the standard format.

@jrauber
Copy link
Contributor Author

jrauber commented Jun 16, 2025

@infeo Not sure if this is good enough, could you please review the PR?

Copy link
Member

@overheadhunter overheadhunter left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the PR, I support the idea of using XPath.

Just a formatting issue: can you please get rid of blank lines inside method bodies unless they explicitly group lines to improve readability?

- removed line-breaks
- increased usage of 'var'
@jrauber
Copy link
Contributor Author

jrauber commented Jun 17, 2025

Thanks for the PR, I support the idea of using XPath.

Just a formatting issue: can you please get rid of blank lines inside method bodies unless they explicitly group lines to improve readability?

@overheadhunter Sure, adjusted the code to the existing style.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

♻️ Duplicate comments (1)
src/main/java/org/cryptomator/linux/quickaccess/DolphinPlaces.java (1)

157-170: Fragile DOCTYPE post-processing

  1. Setting DOCTYPE_PUBLIC/_SYSTEM to empty strings relies on the
    Transformer emitting PUBLIC "" "", which is implementation-specific.
  2. The subsequent replaceFirst("<!DOCTYPE xbel PUBLIC \"\" \"\">", …) will
    fail if the Transformer adds whitespace or a line break.

A safer, implementation-agnostic approach:

- transformer.setOutputProperty(OutputKeys.DOCTYPE_PUBLIC, "");
- transformer.setOutputProperty(OutputKeys.DOCTYPE_SYSTEM, "");
+ // Let the original DocumentType pass through unchanged.

and replace the brittle regex with a tolerant one:

- content = content.replaceFirst("<!DOCTYPE xbel PUBLIC \"\" \"\">","<!DOCTYPE xbel>");
+ content = content.replaceFirst("<!DOCTYPE\\s+xbel[^>]*>","<!DOCTYPE xbel>");

This keeps the shortened DOCTYPE while avoiding dependency on a specific JDK
serialisation.

🧹 Nitpick comments (2)
src/test/java/org/cryptomator/linux/quickaccess/DolphinPlacesTest.java (1)

134-142: Specify charset in Files.readString to avoid platform-dependent behaviour

Files.readString(Path) uses the JVM default charset, which may differ between environments and could break the assertions when the file contains non-ASCII characters. Pass StandardCharsets.UTF_8 explicitly – your test resources are UTF-8.

- return Files.readString(file);
+ return Files.readString(file, java.nio.charset.StandardCharsets.UTF_8);
src/main/java/org/cryptomator/linux/quickaccess/DolphinPlaces.java (1)

111-123: XPath equality on the raw URI is brittle

The expression [@href=$uri] requires an exact string match. Minor
differences—e.g. presence/absence of a trailing slash, URL-encoded spaces,
case sensitivity on case-insensitive filesystems—will cause duplicates to
slip through.

Consider normalising before comparison or switching to a more tolerant XPath,
e.g. starts-with(@href, $uri) or comparing on java.nio.file.Path#toRealPath
normalised strings prior to insertion.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ee1d5f2 and 32522a4.

📒 Files selected for processing (3)
  • src/main/java/org/cryptomator/linux/quickaccess/DolphinPlaces.java (4 hunks)
  • src/main/java/org/cryptomator/linux/quickaccess/FileConfiguredQuickAccess.java (1 hunks)
  • src/test/java/org/cryptomator/linux/quickaccess/DolphinPlacesTest.java (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/main/java/org/cryptomator/linux/quickaccess/FileConfiguredQuickAccess.java
🧰 Additional context used
🧠 Learnings (1)
src/main/java/org/cryptomator/linux/quickaccess/DolphinPlaces.java (2)
Learnt from: jrauber
PR: cryptomator/integrations-linux#114
File: src/main/java/org/cryptomator/linux/quickaccess/DolphinPlaces.java:0-0
Timestamp: 2025-06-16T18:40:46.632Z
Learning: KDE Dolphin generates XBEL files with a shortened DOCTYPE declaration format `<!DOCTYPE xbel>` rather than the canonical XBEL format with public and system identifiers. For compatibility with Dolphin, XBEL files should use this shortened format when integrating with KDE Dolphin's bookmark system.
Learnt from: jrauber
PR: cryptomator/integrations-linux#114
File: src/main/java/org/cryptomator/linux/quickaccess/DolphinPlaces.java:0-0
Timestamp: 2025-06-15T14:06:09.538Z
Learning: XBEL (XML Bookmark Exchange Language) files used by KDE Dolphin legitimately contain DOCTYPE declarations as part of the format specification. The format requires `<!DOCTYPE xbel>` for formal validation against the official XBEL DTD. Applications reading XBEL files cannot disallow DOCTYPE declarations without breaking compatibility with the standard format.

@jrauber jrauber requested a review from overheadhunter June 17, 2025 17:21
Copy link
Member

@overheadhunter overheadhunter left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

looks promising, just some minor remarks. sorry that it took me so long to review it again

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

♻️ Duplicate comments (1)
src/main/java/org/cryptomator/linux/quickaccess/DolphinPlaces.java (1)

76-78: Constructor parameter name should reflect its purpose.

The parameter configFilePath is misleading because it's used as a directory path in the parent constructor, not a file path. This could lead to confusion and incorrect usage.

-	public DolphinPlaces(Path configFilePath) {
-		super(configFilePath, MAX_FILE_SIZE);
+	public DolphinPlaces(Path configDir) {
+		super(configDir, MAX_FILE_SIZE);

Or alternatively, if you want to accept the full file path:

-	public DolphinPlaces(Path configFilePath) {
-		super(configFilePath, MAX_FILE_SIZE);
+	public DolphinPlaces(Path configFilePath) {
+		super(configFilePath.getParent(), MAX_FILE_SIZE);
🧹 Nitpick comments (1)
src/test/java/org/cryptomator/linux/quickaccess/DolphinPlacesTest.java (1)

3-3: Missing import organization.

The import org.cryptomator.integrations.quickaccess.QuickAccessServiceException was added but the imports aren't properly organized or optimized.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 32522a4 and 700fc49.

📒 Files selected for processing (2)
  • src/main/java/org/cryptomator/linux/quickaccess/DolphinPlaces.java (4 hunks)
  • src/test/java/org/cryptomator/linux/quickaccess/DolphinPlacesTest.java (1 hunks)
🧰 Additional context used
🧠 Learnings (3)
📓 Common learnings
Learnt from: jrauber
PR: cryptomator/integrations-linux#114
File: src/main/java/org/cryptomator/linux/quickaccess/DolphinPlaces.java:0-0
Timestamp: 2025-06-16T18:40:46.643Z
Learning: KDE Dolphin generates XBEL files with a shortened DOCTYPE declaration format `<!DOCTYPE xbel>` rather than the canonical XBEL format with public and system identifiers. For compatibility with Dolphin, XBEL files should use this shortened format when integrating with KDE Dolphin's bookmark system.
Learnt from: infeo
PR: cryptomator/integrations-linux#102
File: src/main/java/org/cryptomator/linux/quickaccess/DolphinPlaces.java:94-96
Timestamp: 2025-01-14T09:23:48.520Z
Learning: In DolphinPlaces.java, the entry identification uses UUID stored in cryptomator.org metadata, which provides sufficient uniqueness without requiring XML parsing for lookups.
Learnt from: jrauber
PR: cryptomator/integrations-linux#114
File: src/main/java/org/cryptomator/linux/quickaccess/DolphinPlaces.java:0-0
Timestamp: 2025-06-15T14:06:09.538Z
Learning: XBEL (XML Bookmark Exchange Language) files used by KDE Dolphin legitimately contain DOCTYPE declarations as part of the format specification. The format requires `<!DOCTYPE xbel>` for formal validation against the official XBEL DTD. Applications reading XBEL files cannot disallow DOCTYPE declarations without breaking compatibility with the standard format.
src/test/java/org/cryptomator/linux/quickaccess/DolphinPlacesTest.java (3)
Learnt from: infeo
PR: cryptomator/integrations-linux#102
File: src/main/java/org/cryptomator/linux/quickaccess/DolphinPlaces.java:94-96
Timestamp: 2025-01-14T09:23:48.520Z
Learning: In DolphinPlaces.java, the entry identification uses UUID stored in cryptomator.org metadata, which provides sufficient uniqueness without requiring XML parsing for lookups.
Learnt from: jrauber
PR: cryptomator/integrations-linux#114
File: src/test/java/org/cryptomator/linux/quickaccess/DolphinPlacesTest.java:162-177
Timestamp: 2025-06-16T18:20:27.440Z
Learning: In JUnit tests, the @TempDir annotation provides each test method with its own isolated temporary directory, so test helper methods that write to the same filename within these directories don't cause race conditions or overwrites during parallel test execution.
Learnt from: infeo
PR: cryptomator/integrations-linux#77
File: src/main/java/org/cryptomator/linux/quickaccess/NautilusBookmarks.java:31-50
Timestamp: 2024-07-12T20:09:01.834Z
Learning: The `add` method in `NautilusBookmarks` handles the case where the `BOOKMARKS_FILE` does not exist by catching the IOException and wrapping it in a `QuickAccessServiceException`.
src/main/java/org/cryptomator/linux/quickaccess/DolphinPlaces.java (6)
Learnt from: infeo
PR: cryptomator/integrations-linux#102
File: src/main/java/org/cryptomator/linux/quickaccess/DolphinPlaces.java:94-96
Timestamp: 2025-01-14T09:23:48.520Z
Learning: In DolphinPlaces.java, the entry identification uses UUID stored in cryptomator.org metadata, which provides sufficient uniqueness without requiring XML parsing for lookups.
Learnt from: jrauber
PR: cryptomator/integrations-linux#114
File: src/main/java/org/cryptomator/linux/quickaccess/DolphinPlaces.java:0-0
Timestamp: 2025-06-16T18:40:46.643Z
Learning: KDE Dolphin generates XBEL files with a shortened DOCTYPE declaration format `<!DOCTYPE xbel>` rather than the canonical XBEL format with public and system identifiers. For compatibility with Dolphin, XBEL files should use this shortened format when integrating with KDE Dolphin's bookmark system.
Learnt from: infeo
PR: cryptomator/integrations-linux#77
File: src/main/java/org/cryptomator/linux/quickaccess/NautilusBookmarks.java:31-50
Timestamp: 2024-07-12T20:09:01.834Z
Learning: The `add` method in `NautilusBookmarks` handles the case where the `BOOKMARKS_FILE` does not exist by catching the IOException and wrapping it in a `QuickAccessServiceException`.
Learnt from: jrauber
PR: cryptomator/integrations-linux#114
File: src/main/java/org/cryptomator/linux/quickaccess/DolphinPlaces.java:0-0
Timestamp: 2025-06-15T14:06:09.538Z
Learning: XBEL (XML Bookmark Exchange Language) files used by KDE Dolphin legitimately contain DOCTYPE declarations as part of the format specification. The format requires `<!DOCTYPE xbel>` for formal validation against the official XBEL DTD. Applications reading XBEL files cannot disallow DOCTYPE declarations without breaking compatibility with the standard format.
Learnt from: infeo
PR: cryptomator/integrations-linux#77
File: src/main/java/org/cryptomator/linux/quickaccess/NautilusBookmarks.java:31-50
Timestamp: 2024-07-12T20:09:01.834Z
Learning: In `NautilusBookmarks`, file operations are handled by the JDK, which manages the closing of any opened resources, so try-with-resources is not necessary.
Learnt from: infeo
PR: cryptomator/integrations-linux#80
File: src/main/java/org/cryptomator/linux/autostart/FreedesktopAutoStartService.java:56-62
Timestamp: 2024-07-16T22:36:32.769Z
Learning: For the `FreedesktopAutoStartService` in the Cryptomator project, exceptions are preferred to contain all necessary debugging information without additional logging before throwing them.
🔇 Additional comments (22)
src/test/java/org/cryptomator/linux/quickaccess/DolphinPlacesTest.java (11)

17-25: Well-structured test constants for comprehensive coverage.

The constant definitions provide good coverage for testing different scenarios including UUIDs, captions, paths, and various XML resource files representing different states (valid, invalid, malformed).


29-31: Improved test structure with lambda expression.

The change to use assertDoesNotThrow with a lambda expression is a good improvement over the previous implementation, making the test more explicit about what should not throw.


33-46: Comprehensive test for replacement behavior.

This test effectively verifies that adding an identical entry replaces the existing one by checking UUID and caption presence before and after the operation. The test properly uses temporary directories and validates the DOM-based replacement logic.


48-63: Thorough test for multiple identical entries replacement.

This test covers the important edge case where multiple identical bookmarks exist and verifies that all are properly replaced with a single new entry. The use of countOccurrences provides precise verification of the replacement behavior.


65-76: Proper error handling test for invalid XML.

This test correctly verifies that invalid XML files are not modified and that the appropriate exception is thrown, ensuring robustness of the XML validation logic.


78-89: Good test coverage for malformed XML handling.

This test ensures that malformed XML files are handled gracefully without modification, which is crucial for maintaining file integrity when XML parsing fails.


91-100: Essential test for XML character escaping.

This test verifies that invalid XML characters are properly escaped when using DOM-based serialization, which is important for preventing XML parsing errors in the target application.


102-119: Critical test for XML root preservation.

This test addresses the concern mentioned in the PR comments about ensuring the XML root and DOCTYPE declaration are not accidentally modified. The test validates that the DOM manipulation preserves the document structure integrity.


122-132: Helper method implementation is correct.

The loadResourceToDir method correctly loads test resources into temporary directories. Based on the retrieved learnings, the use of the same filename across tests is not an issue because @TempDir provides isolated directories for each test.


134-143: Solid file loading helper method.

The loadFile method provides proper error handling and resource management for reading test files, with appropriate exception wrapping.


145-154: Efficient string occurrence counting utility.

The countOccurrences method provides an efficient way to count substring occurrences, which is useful for validating XML content changes in the tests.

src/main/java/org/cryptomator/linux/quickaccess/DolphinPlaces.java (11)

9-15: Appropriate imports for DOM-based XML processing.

The new imports support the transition from string-based to DOM-based XML manipulation, including proper logging, DOM processing, and XPath support.


53-55: Good logging and namespace constant additions.

The logger and XBEL namespace constant improve maintainability and provide proper debugging capabilities for the XML processing logic.


81-99: Well-structured DOM-based bookmark addition.

The refactored addEntryToConfig method properly uses DOM parsing, XPath queries, and XML validation. The error handling is comprehensive and the logging provides good traceability.


101-106: Correct node removal implementation.

The removeStaleBookmarks method properly handles the live NodeList by iterating backwards, avoiding the skip-every-second-node issue that would occur with forward iteration.


108-120: Secure XPath implementation with variable resolution.

The XPath implementation properly uses variable resolution to avoid injection attacks. The exception handling is comprehensive and provides clear error messages.


122-134: Consistent XPath pattern for ID-based extraction.

The extractBookmarksById method follows the same secure pattern as extractBookmarksByPath, using variable resolution and proper exception handling.


136-152: Proper XML security configuration.

The XML document loading includes appropriate security measures to prevent XXE attacks while preserving the ability to parse XBEL files with DOCTYPE declarations, which is essential for compatibility with KDE Dolphin.


154-171: DOCTYPE handling preserves Dolphin compatibility.

The documentToString method correctly handles the DOCTYPE declaration by converting the canonical format to the shortened format that KDE Dolphin expects (<!DOCTYPE xbel>), ensuring compatibility with the target application.


173-222: Comprehensive bookmark creation with proper structure.

The createBookmark method creates the complete XBEL bookmark structure with proper namespaces, metadata, and attributes. The DOM-based approach ensures proper XML escaping and structure validation.


233-246: Consistent removal implementation.

The removeEntryFromConfig method in the inner class follows the same pattern as the addition logic, using DOM parsing and proper validation to ensure XML integrity.


248-274: Clean XPath variable resolver implementation.

The SimpleVariableResolver inner class provides a clean, thread-safe implementation for XPath variable resolution, supporting the secure XPath expressions used throughout the class.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (1)
src/main/java/org/cryptomator/linux/quickaccess/DolphinPlaces.java (1)

88-88: Consider using debug level for production logging.

The trace-level logging for bookmark operations might be too verbose for production environments. Consider using debug level for this operational information.

- LOG.trace("Adding bookmark for target: '{}', displayName: '{}', id: '{}'", target, displayName, id);
+ LOG.debug("Adding bookmark for target: '{}', displayName: '{}', id: '{}'", target, displayName, id);
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 743b00f and f65d2c4.

📒 Files selected for processing (1)
  • src/main/java/org/cryptomator/linux/quickaccess/DolphinPlaces.java (4 hunks)
🧰 Additional context used
🧠 Learnings (2)
📓 Common learnings
Learnt from: jrauber
PR: cryptomator/integrations-linux#114
File: src/main/java/org/cryptomator/linux/quickaccess/DolphinPlaces.java:0-0
Timestamp: 2025-06-16T18:40:46.643Z
Learning: KDE Dolphin generates XBEL files with a shortened DOCTYPE declaration format `<!DOCTYPE xbel>` rather than the canonical XBEL format with public and system identifiers. For compatibility with Dolphin, XBEL files should use this shortened format when integrating with KDE Dolphin's bookmark system.
Learnt from: infeo
PR: cryptomator/integrations-linux#102
File: src/main/java/org/cryptomator/linux/quickaccess/DolphinPlaces.java:94-96
Timestamp: 2025-01-14T09:23:48.520Z
Learning: In DolphinPlaces.java, the entry identification uses UUID stored in cryptomator.org metadata, which provides sufficient uniqueness without requiring XML parsing for lookups.
Learnt from: jrauber
PR: cryptomator/integrations-linux#114
File: src/main/java/org/cryptomator/linux/quickaccess/DolphinPlaces.java:0-0
Timestamp: 2025-06-15T14:06:09.538Z
Learning: XBEL (XML Bookmark Exchange Language) files used by KDE Dolphin legitimately contain DOCTYPE declarations as part of the format specification. The format requires `<!DOCTYPE xbel>` for formal validation against the official XBEL DTD. Applications reading XBEL files cannot disallow DOCTYPE declarations without breaking compatibility with the standard format.
src/main/java/org/cryptomator/linux/quickaccess/DolphinPlaces.java (6)
Learnt from: infeo
PR: cryptomator/integrations-linux#102
File: src/main/java/org/cryptomator/linux/quickaccess/DolphinPlaces.java:94-96
Timestamp: 2025-01-14T09:23:48.520Z
Learning: In DolphinPlaces.java, the entry identification uses UUID stored in cryptomator.org metadata, which provides sufficient uniqueness without requiring XML parsing for lookups.
Learnt from: jrauber
PR: cryptomator/integrations-linux#114
File: src/main/java/org/cryptomator/linux/quickaccess/DolphinPlaces.java:0-0
Timestamp: 2025-06-16T18:40:46.643Z
Learning: KDE Dolphin generates XBEL files with a shortened DOCTYPE declaration format `<!DOCTYPE xbel>` rather than the canonical XBEL format with public and system identifiers. For compatibility with Dolphin, XBEL files should use this shortened format when integrating with KDE Dolphin's bookmark system.
Learnt from: infeo
PR: cryptomator/integrations-linux#77
File: src/main/java/org/cryptomator/linux/quickaccess/NautilusBookmarks.java:31-50
Timestamp: 2024-07-12T20:09:01.834Z
Learning: The `add` method in `NautilusBookmarks` handles the case where the `BOOKMARKS_FILE` does not exist by catching the IOException and wrapping it in a `QuickAccessServiceException`.
Learnt from: jrauber
PR: cryptomator/integrations-linux#114
File: src/main/java/org/cryptomator/linux/quickaccess/DolphinPlaces.java:0-0
Timestamp: 2025-06-15T14:06:09.538Z
Learning: XBEL (XML Bookmark Exchange Language) files used by KDE Dolphin legitimately contain DOCTYPE declarations as part of the format specification. The format requires `<!DOCTYPE xbel>` for formal validation against the official XBEL DTD. Applications reading XBEL files cannot disallow DOCTYPE declarations without breaking compatibility with the standard format.
Learnt from: infeo
PR: cryptomator/integrations-linux#77
File: src/main/java/org/cryptomator/linux/quickaccess/NautilusBookmarks.java:31-50
Timestamp: 2024-07-12T20:09:01.834Z
Learning: In `NautilusBookmarks`, file operations are handled by the JDK, which manages the closing of any opened resources, so try-with-resources is not necessary.
Learnt from: infeo
PR: cryptomator/integrations-linux#80
File: src/main/java/org/cryptomator/linux/autostart/FreedesktopAutoStartService.java:56-62
Timestamp: 2024-07-16T22:36:32.769Z
Learning: For the `FreedesktopAutoStartService` in the Cryptomator project, exceptions are preferred to contain all necessary debugging information without additional logging before throwing them.
🔇 Additional comments (6)
src/main/java/org/cryptomator/linux/quickaccess/DolphinPlaces.java (6)

115-117: XPath variable resolution properly prevents injection attacks.

The implementation correctly uses XPath variable resolution instead of string concatenation, effectively preventing XPath injection vulnerabilities. This is a significant security improvement over the previous string-based approach.


141-151: XML security configuration is comprehensive and appropriate.

The XML parser configuration properly prevents XXE attacks while maintaining compatibility with XBEL format requirements. The security features are well-balanced:

  • Prevents external entity resolution
  • Blocks external DTD/schema access
  • Allows required DOCTYPE declarations for XBEL compatibility
  • Custom EntityResolver returns empty content for safety

161-169: DOCTYPE handling maintains Dolphin compatibility.

The DOCTYPE post-processing correctly transforms the XML output to match KDE Dolphin's expected format (<!DOCTYPE xbel>) while preserving the XML structure. This approach maintains compatibility with Dolphin's specific XBEL implementation.


200-224: Comprehensive bookmark creation with proper DOM manipulation.

The bookmark creation method correctly constructs the complete XBEL bookmark structure including:

  • Proper namespace handling for the icon element
  • Correct metadata organization with owner attributes
  • Appropriate exception handling for DOM operations

238-244: Entry removal follows the same robust pattern as addition.

The removal logic correctly mirrors the addition pattern with validation before and after DOM manipulation, ensuring consistent XML integrity throughout the bookmark management process.


254-276: XPath variable resolver implementation is clean and functional.

The SimpleVariableResolver class provides a straightforward implementation for XPath parameterization. The HashMap-based storage and simple interface make it easy to use and understand.

@jrauber jrauber requested a review from overheadhunter July 16, 2025 18:44
Copy link
Member

@infeo infeo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good, but i have some open questions.

…d instead providing a lambda into the xpath

- Removed the unnecessary validation before deleting
@jrauber jrauber requested a review from infeo July 22, 2025 18:41
@infeo infeo added the bugfix label Jul 23, 2025
@infeo
Copy link
Member

infeo commented Jul 24, 2025

@jrauber Can you merge the current develop branch into yours? i updated the workflows to also execute the maven test phase.

@jrauber
Copy link
Contributor Author

jrauber commented Jul 25, 2025

@jrauber Can you merge the current develop branch into yours? i updated the workflows to also execute the maven test phase.

@infeo Did merge it, the github action awaits confirmation by the maintainer.

Checked on my branch, the build is now running:
https://github.com/jrauber/integrations-linux/actions/runs/16518687257

@infeo infeo merged commit 48d0261 into cryptomator:develop Jul 25, 2025
5 checks passed
@infeo infeo added this to the nex milestone Jul 25, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Multiple quickaccess entries on KDE Dolphin

4 participants