Skip to content

Add SMB support#650

Open
Goldmaster wants to merge 12 commits into
cryptomator:developfrom
Goldmaster:smb
Open

Add SMB support#650
Goldmaster wants to merge 12 commits into
cryptomator:developfrom
Goldmaster:smb

Conversation

@Goldmaster

@Goldmaster Goldmaster commented Jul 19, 2026

Copy link
Copy Markdown

This pull request aims to add SMB support into the app and closes issue #85

Currently, got the UI and ability to input SMB details. But do need to work on the SMB icon and further testing ensure SMB works correctly.

@Goldmaster Goldmaster changed the title #85 SMB support Add SMB support Jul 20, 2026

@SailReal SailReal left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Thank you very much for the contribution 💚!

Before looking any further into the PR, it looks like your added dependency https://github.com/hierynomus/smbj/tags is pretty unmaintained. Do you know any more details about it?

@Goldmaster

Copy link
Copy Markdown
Author

Hi there,

Thank you for your help.

I chose smbj primarily because it provides the necessary support for SMB 2 and SMB 3, and it seemed like the most reliable choice to get modern SMB support off the ground for the app.

Regarding the maintenance, while the last tagged release was in early 2024, the repository remains active there was a commit last week, which suggests it is still active.

That said, if you have a different option in mind, then I can look into switching it. I’ve enabled maintainer write access for this pull request, so any maintainer can make direct adjustments if needed, or I can update it based on your recommendations.

I have tested this pull request out myself over SMB, and I am now able to unlock and update a vault via SMB by creating a text file with a written comment. The newly created text file with written text shows up when the vault is unlocked again using the desktop app. Folder create and file upload also works without issue.

Furthermore, I have recreated the SMB icons as best as I can using existing assets from the source code.

@Goldmaster
Goldmaster marked this pull request as ready for review July 24, 2026 21:00
@coderabbitai

coderabbitai Bot commented Jul 24, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 81bdb6eb-87dd-4c06-a31a-e6a2871d8408

📥 Commits

Reviewing files that changed from the base of the PR and between b060108 and 56168ee.

📒 Files selected for processing (1)
  • data/src/main/java/org/cryptomator/data/cloud/smb/SmbCloudContentRepository.kt
🚧 Files skipped from review as they are similar to previous changes (1)
  • data/src/main/java/org/cryptomator/data/cloud/smb/SmbCloudContentRepository.kt

Walkthrough

The change adds SMB as a cloud type with domain modeling, database mapping, SMBJ repository operations, factory wiring, authentication, presentation models, add/edit UI flows, validation, persistence, resources, and icons. Project configuration adds SMB dependencies, Gradle toolchain settings, IDE metadata, and build updates.

Estimated code review effort: 4 (Complex) | ~60 minutes

Possibly related issues

  • cryptomator/ios#266 — Concerns adding SMB support, matching this change’s SMB integration.
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 8.05% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title is concise and accurately summarizes the main change: adding SMB support.
Description check ✅ Passed The description is directly related to the changes and correctly describes the SMB support work.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 10

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
presentation/src/main/java/org/cryptomator/presentation/ui/adapter/CloudSettingsAdapter.kt (1)

44-50: 🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

Reset recycled username state for SMB rows.

When a holder previously displayed a logged-in provider, the SMB branch leaves cloudUsername visible with the previous row’s username. Clear and hide it before the when block, while the fallback branch explicitly shows it when appropriate.

Proposed fix
 val cloudModel = getItem(position)

 binding.cloudImage.setImageResource(cloudModel.cloudType().cloudImageResource)
+binding.cloudUsername.text = null
+binding.cloudUsername.visibility = View.GONE

 when (cloudModel.cloudType()) {
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@presentation/src/main/java/org/cryptomator/presentation/ui/adapter/CloudSettingsAdapter.kt`
around lines 44 - 50, In the holder-binding logic around the cloud type when
block, reset the recycled cloudUsername view before evaluating
cloudModel.cloudType(): clear its text and hide it by default. Update the
fallback branch to explicitly show and populate cloudUsername when that provider
requires displaying a username, while preserving the existing provider-specific
names.
presentation/src/main/java/org/cryptomator/presentation/presenter/AuthenticateCloudPresenter.kt (1)

67-76: 🎯 Functional Correctness | 🟠 Major | 🏗️ Heavy lift

Implement SMB authentication before enabling this strategy.

SmbAuthStrategy.resumed() unconditionally calls failAuthentication, so every existing SMB connection fails when the normal AuthenticateCloudPresenter flow is used. The PR’s SMB vault-access path therefore cannot authenticate; wire this strategy to the SMB connection/authentication use case and return the authenticated cloud on success.

Also applies to: 401-410

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@presentation/src/main/java/org/cryptomator/presentation/presenter/AuthenticateCloudPresenter.kt`
around lines 67 - 76, Implement SMB authentication in SmbAuthStrategy before
keeping it enabled in AuthenticateCloudPresenter.strategies. Replace the
unconditional failAuthentication behavior in SmbAuthStrategy.resumed() with the
SMB connection/authentication use case, and return the authenticated cloud on
success while preserving failure handling for unsuccessful authentication.
Ensure both normal authentication and the SMB vault-access flow use this path.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.idea/deploymentTargetSelector.xml:
- Line 10: Remove the machine-specific physical device selection identified by
DeviceId from deploymentTargetSelector.xml, preferably deleting the shared IDE
state file from version control or clearing the device entry before committing.

In
`@data/src/main/java/org/cryptomator/data/cloud/smb/SmbCloudContentRepository.kt`:
- Around line 128-136: Update SmbCloudContentRepository.exists so only SMB
not-found conditions return false; let connection, authentication, and other
non-not-found exceptions propagate to the caller. Preserve the existing
fileExists/folderExists checks within withDiskShare and narrow the catch around
this logic accordingly.
- Around line 250-256: Update SmbCloudContentRepository.read and its copy flow
to emit the download lifecycle through progressAware, including the started
state and incremental progress while bytes are copied. Mirror the established
callback behavior in write(), using the transferred byte count and preserving
the existing stream and resource handling.
- Around line 217-246: Update write so data.open(context) is resolved and
validated before ds.openFile creates or overwrites the destination; fail
immediately when no input stream is available, then use the non-null stream for
copying and preserve the existing progress and file-info behavior.

In `@domain/src/main/java/org/cryptomator/domain/SmbCloud.java`:
- Around line 54-56: Update SmbCloud.configurationMatches to compare the domain
field in addition to url and username, while continuing to exclude password so
password changes do not create a distinct connection.

In
`@presentation/src/main/java/org/cryptomator/presentation/presenter/SmbAddOrChangePresenter.kt`:
- Around line 113-121: Update onCloudAuthenticated and save so finishWithResult
is invoked only from the save operation’s onSuccess callback, after persistence
completes. Handle the save handler’s failure callback without reporting
successful setup, preserving the existing result payload and ensuring
asynchronous write failures reach the caller.

In
`@presentation/src/main/java/org/cryptomator/presentation/ui/activity/CryptomatorVariantsActivity.kt`:
- Around line 21-27: Move the hardcoded variant text assigned to
tvLiteSupported, tvLiteUnsupported, tvFdroidCustomSupported,
tvFdroidCustomUnsupported, and tvWebsiteSupported into complete string resources
in strings.xml. Replace each literal in CryptomatorVariantsActivity with its
corresponding resource reference, preserving the existing wording and
variant-specific lists.

In
`@presentation/src/main/java/org/cryptomator/presentation/ui/fragment/SmbAddOrChangeFragment.kt`:
- Around line 77-82: Update the password extraction in the SMB input flow around
smbAddOrChangePresenter.checkUserInput to preserve the exact contents of
passwordEditText, removing trim() only for the password while retaining trimming
for urlPort, username, and domain.

In `@presentation/src/main/res/drawable/smb_vault.xml`:
- Around line 6-15: Keep presentation/src/main/res/drawable/smb_vault.xml lines
6-15 unchanged as the unselected styling. Update
presentation/src/main/res/drawable/smb_vault_selected.xml lines 6-15 to use the
distinct selected-state styling established by the other vault icons, including
the appropriate selected colors or visual treatment.

In `@presentation/src/main/res/layout/fragment_setup_smb.xml`:
- Around line 2-79: Wrap the root form content in a vertical ScrollView or
NestedScrollView so all SMB fields, including domain_edit_text and
create_cloud_button, remain reachable on compact or landscape screens when the
keyboard is visible. Preserve the existing LinearLayout orientation, sizing,
padding, and child controls within the scroll container.

---

Outside diff comments:
In
`@presentation/src/main/java/org/cryptomator/presentation/presenter/AuthenticateCloudPresenter.kt`:
- Around line 67-76: Implement SMB authentication in SmbAuthStrategy before
keeping it enabled in AuthenticateCloudPresenter.strategies. Replace the
unconditional failAuthentication behavior in SmbAuthStrategy.resumed() with the
SMB connection/authentication use case, and return the authenticated cloud on
success while preserving failure handling for unsuccessful authentication.
Ensure both normal authentication and the SMB vault-access flow use this path.

In
`@presentation/src/main/java/org/cryptomator/presentation/ui/adapter/CloudSettingsAdapter.kt`:
- Around line 44-50: In the holder-binding logic around the cloud type when
block, reset the recycled cloudUsername view before evaluating
cloudModel.cloudType(): clear its text and hide it by default. Update the
fallback branch to explicitly show and populate cloudUsername when that provider
requires displaying a username, while preserving the existing provider-specific
names.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 6ef45cc2-274f-474d-a03c-f8f231f774f4

📥 Commits

Reviewing files that changed from the base of the PR and between aeb2e86 and 11a7fcc.

⛔ Files ignored due to path filters (1)
  • presentation/src/main/res/drawable-xxhdpi/smb.png is excluded by !**/*.png
📒 Files selected for processing (41)
  • .idea/appInsightsSettings.xml
  • .idea/deploymentTargetSelector.xml
  • .idea/misc.xml
  • .idea/planningMode.xml
  • buildsystem/dependencies.gradle
  • data/build.gradle
  • data/src/apkStorePlaystore/java/org/cryptomator/data/cloud/CloudContentRepositoryFactories.java
  • data/src/fdroidAccrescent/java/org/cryptomator/data/cloud/CloudContentRepositoryFactories.java
  • data/src/lite/java/org/cryptomator/data/cloud/CloudContentRepositoryFactories.java
  • data/src/main/java/org/cryptomator/data/cloud/smb/SmbCloudContentRepository.kt
  • data/src/main/java/org/cryptomator/data/cloud/smb/SmbCloudContentRepositoryFactory.java
  • data/src/main/java/org/cryptomator/data/cloud/smb/SmbFile.kt
  • data/src/main/java/org/cryptomator/data/cloud/smb/SmbFolder.kt
  • data/src/main/java/org/cryptomator/data/cloud/smb/SmbNode.kt
  • data/src/main/java/org/cryptomator/data/db/mappers/CloudEntityMapper.java
  • domain/src/main/java/org/cryptomator/domain/CloudType.kt
  • domain/src/main/java/org/cryptomator/domain/SmbCloud.java
  • domain/src/main/java/org/cryptomator/domain/usecases/cloud/ConnectToSmb.java
  • gradle.properties
  • gradle/wrapper/gradle-wrapper.properties
  • presentation/src/main/AndroidManifest.xml
  • presentation/src/main/java/org/cryptomator/presentation/di/component/ActivityComponent.java
  • presentation/src/main/java/org/cryptomator/presentation/intent/SmbAddOrChangeIntent.java
  • presentation/src/main/java/org/cryptomator/presentation/model/CloudTypeModel.kt
  • presentation/src/main/java/org/cryptomator/presentation/model/SmbCloudModel.kt
  • presentation/src/main/java/org/cryptomator/presentation/model/mappers/CloudModelMapper.kt
  • presentation/src/main/java/org/cryptomator/presentation/presenter/AuthenticateCloudPresenter.kt
  • presentation/src/main/java/org/cryptomator/presentation/presenter/CloudConnectionListPresenter.kt
  • presentation/src/main/java/org/cryptomator/presentation/presenter/CloudSettingsPresenter.kt
  • presentation/src/main/java/org/cryptomator/presentation/presenter/SmbAddOrChangePresenter.kt
  • presentation/src/main/java/org/cryptomator/presentation/ui/activity/CryptomatorVariantsActivity.kt
  • presentation/src/main/java/org/cryptomator/presentation/ui/activity/SmbAddOrChangeActivity.kt
  • presentation/src/main/java/org/cryptomator/presentation/ui/activity/view/SmbAddOrChangeView.kt
  • presentation/src/main/java/org/cryptomator/presentation/ui/adapter/CloudSettingsAdapter.kt
  • presentation/src/main/java/org/cryptomator/presentation/ui/bottomsheet/CloudConnectionSettingsBottomSheet.kt
  • presentation/src/main/java/org/cryptomator/presentation/ui/fragment/SmbAddOrChangeFragment.kt
  • presentation/src/main/res/drawable/smb_vault.xml
  • presentation/src/main/res/drawable/smb_vault_selected.xml
  • presentation/src/main/res/layout/fragment_setup_smb.xml
  • presentation/src/main/res/values/strings.xml
  • settings.gradle

Comment thread .idea/deploymentTargetSelector.xml Outdated
Comment thread data/src/main/java/org/cryptomator/data/cloud/smb/SmbCloudContentRepository.kt Outdated
Comment thread domain/src/main/java/org/cryptomator/domain/SmbCloud.java
Comment thread presentation/src/main/res/drawable/smb_vault.xml
Comment thread presentation/src/main/res/layout/fragment_setup_smb.xml Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
data/src/main/java/org/cryptomator/data/cloud/smb/SmbCloudContentRepository.kt (2)

90-130: 🚀 Performance & Scalability | 🟠 Major | 🏗️ Heavy lift

Reconnecting for every single filesystem operation is expensive.

withDiskShare opens a brand-new SMBClient, TCP connection, session (with full NTLM/Kerberos authentication), and tree connect for every call — and it's invoked independently by exists, list, create/mkdirs, move, write, read, and delete. Browsing a folder or unlocking a vault typically issues several sequential calls (e.g., list followed by per-entry exists checks), so each one pays a full negotiate+authenticate+tree-connect round trip. This will noticeably slow down normal usage compared to reusing a single authenticated share/session for the repository's lifetime.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@data/src/main/java/org/cryptomator/data/cloud/smb/SmbCloudContentRepository.kt`
around lines 90 - 130, Refactor withDiskShare so SMBClient, connection,
authenticated session, and DiskShare are established once and reused across
repository operations instead of recreated per call. Preserve the existing
authentication, credential-error mapping, resource cleanup, and action
invocation behavior, while ensuring the shared resources are closed when the
repository lifecycle ends.

90-119: 🩺 Stability & Availability | 🟠 Major | 🏗️ Heavy lift

Bound SMB connect and IO timeouts in withDiskShare.

SMBClient() currently uses the library default config, whose socket timeout defaults to infinite, while SmbConfig does not expose a direct connect timeout in the builder. At least set SmbConfig.builder.withTimeout(...).withSoTimeout(...).build() and wire a bounded SocketFactory/custom connection handling for the TCP connect phase so unreachable SMB hosts or frozen operations don’t block every filesystem call.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@data/src/main/java/org/cryptomator/data/cloud/smb/SmbCloudContentRepository.kt`
around lines 90 - 119, Update withDiskShare to construct SMBClient with an
SmbConfig configured via builder.withTimeout(...) and withSoTimeout(...) using
bounded durations, and provide bounded TCP connect handling through the
supported SocketFactory/custom connection mechanism. Replace the unconfigured
SMBClient() creation while preserving the existing authentication,
share-connection, and resource-lifecycle behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@data/src/main/java/org/cryptomator/data/cloud/smb/SmbCloudContentRepository.kt`:
- Around line 339-372: Update deleteRecursive to track failures from child ds.rm
calls, recursive deleteRecursive calls, and both ds.rmdir attempts, retaining
the relevant exception when possible. Propagate the failure to its caller
instead of swallowing it so delete reports unsuccessful removal when any nested
file or directory remains undeleted.
- Around line 42-49: Update throwWrappedIfRequired so STATUS_ACCESS_DENIED and
STATUS_NETWORK_ACCESS_DENIED are mapped to WrongCredentialsException only for
authenticate() and connectShare() failures, not for general file or folder
operations. Preserve the existing mappings for path-not-found and other
credential-specific statuses, and let resource-level permission errors propagate
as NetworkConnectionException or the established permission error.

---

Outside diff comments:
In
`@data/src/main/java/org/cryptomator/data/cloud/smb/SmbCloudContentRepository.kt`:
- Around line 90-130: Refactor withDiskShare so SMBClient, connection,
authenticated session, and DiskShare are established once and reused across
repository operations instead of recreated per call. Preserve the existing
authentication, credential-error mapping, resource cleanup, and action
invocation behavior, while ensuring the shared resources are closed when the
repository lifecycle ends.
- Around line 90-119: Update withDiskShare to construct SMBClient with an
SmbConfig configured via builder.withTimeout(...) and withSoTimeout(...) using
bounded durations, and provide bounded TCP connect handling through the
supported SocketFactory/custom connection mechanism. Replace the unconfigured
SMBClient() creation while preserving the existing authentication,
share-connection, and resource-lifecycle behavior.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: d734cb56-400d-4db8-aee7-3b30b86b5e8c

📥 Commits

Reviewing files that changed from the base of the PR and between 11a7fcc and b060108.

📒 Files selected for processing (11)
  • .idea/deploymentTargetSelector.xml
  • data/src/main/java/org/cryptomator/data/cloud/smb/SmbCloudContentRepository.kt
  • domain/src/main/java/org/cryptomator/domain/SmbCloud.java
  • presentation/src/main/java/org/cryptomator/presentation/presenter/AuthenticateCloudPresenter.kt
  • presentation/src/main/java/org/cryptomator/presentation/presenter/SmbAddOrChangePresenter.kt
  • presentation/src/main/java/org/cryptomator/presentation/ui/activity/CryptomatorVariantsActivity.kt
  • presentation/src/main/java/org/cryptomator/presentation/ui/adapter/CloudSettingsAdapter.kt
  • presentation/src/main/java/org/cryptomator/presentation/ui/fragment/SmbAddOrChangeFragment.kt
  • presentation/src/main/res/drawable/smb_vault_selected.xml
  • presentation/src/main/res/layout/fragment_setup_smb.xml
  • presentation/src/main/res/values/strings.xml
💤 Files with no reviewable changes (1)
  • .idea/deploymentTargetSelector.xml
🚧 Files skipped from review as they are similar to previous changes (6)
  • presentation/src/main/res/layout/fragment_setup_smb.xml
  • presentation/src/main/java/org/cryptomator/presentation/ui/activity/CryptomatorVariantsActivity.kt
  • presentation/src/main/java/org/cryptomator/presentation/ui/adapter/CloudSettingsAdapter.kt
  • domain/src/main/java/org/cryptomator/domain/SmbCloud.java
  • presentation/src/main/java/org/cryptomator/presentation/ui/fragment/SmbAddOrChangeFragment.kt
  • presentation/src/main/java/org/cryptomator/presentation/presenter/SmbAddOrChangePresenter.kt

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants