Skip to content

Hub host trust validation#626

Merged
SailReal merged 5 commits intodevelopfrom
feature/hub-host-trust-validation
Mar 12, 2026
Merged

Hub host trust validation#626
SailReal merged 5 commits intodevelopfrom
feature/hub-host-trust-validation

Conversation

@SailReal
Copy link
Member

No description provided.

@coderabbitai
Copy link

coderabbitai bot commented Mar 12, 2026

Walkthrough

Adds HUB host validation and trust flows to the vault unlock process: new public handlers onHubCheckHostsAllowed and allowedHubHosts in UnlockVaultPresenter, multiple private helpers for config consistency, host/HTTP detection and authority extraction, and logic to record trusted hosts. Introduces HubCheckHostAuthenticityDialog and activity callbacks in UnlockVaultActivity, a settings preference to clear trusted hosts with backing SharedPreferencesHandler methods (add/get/clear), new layout and string resources for the dialog and messages, and a minor formatting tweak.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~35 minutes

Possibly related PRs

  • Hub support #560 — Directly modifies the Hub unlock flow in the same presentation layer components (UnlockVaultPresenter and UnlockVaultActivity) with overlapping Hub handling logic.

Suggested reviewers

  • JaniruTEC
🚥 Pre-merge checks | ✅ 1 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Description check ⚠️ Warning No description was provided, making it impossible to assess whether the author explained the changeset. Add a pull request description explaining the purpose, changes, and testing approach for the Hub host trust validation feature.
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (1 passed)
Check name Status Explanation
Title check ✅ Passed The title 'Hub host trust validation' accurately summarizes the main change—adding host authentication and trust management for Hub connections.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feature/hub-host-trust-validation

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 and usage tips.

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: 2

🧹 Nitpick comments (1)
presentation/src/main/java/org/cryptomator/presentation/ui/dialog/HubCheckHostAuthenticityDialog.kt (1)

48-53: Narrow newInstance() to UnverifiedHubVaultConfig.

setupDialog() immediately casts this argument back to UnverifiedHubVaultConfig, so the wider type just turns misuse into a runtime cast failure.

♻️ Suggested change
-import org.cryptomator.domain.UnverifiedVaultConfig
@@
-		fun newInstance(hostnames: Array<String>, unverifiedVaultConfig: UnverifiedVaultConfig, vault: Vault): HubCheckHostAuthenticityDialog {
+		fun newInstance(hostnames: Array<String>, unverifiedHubVaultConfig: UnverifiedHubVaultConfig, vault: Vault): HubCheckHostAuthenticityDialog {
 			val dialog = HubCheckHostAuthenticityDialog()
 			val args = Bundle()
 			args.putSerializable(HOSTNAMES_ARG, hostnames)
-			args.putSerializable(UNVERIFIED_VAULT_CONFIG_ARG, unverifiedVaultConfig)
+			args.putSerializable(UNVERIFIED_VAULT_CONFIG_ARG, unverifiedHubVaultConfig)
 			args.putSerializable(VAULT_ARG, vault)
 			dialog.arguments = args
 			return dialog
 		}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@presentation/src/main/java/org/cryptomator/presentation/ui/dialog/HubCheckHostAuthenticityDialog.kt`
around lines 48 - 53, The factory method newInstance currently accepts a broad
UnverifiedVaultConfig but setupDialog always casts it to
UnverifiedHubVaultConfig, causing potential runtime cast failures; change the
newInstance signature to accept UnverifiedHubVaultConfig (instead of
UnverifiedVaultConfig), update the args.putSerializable call to pass that typed
value, and update any callers of HubCheckHostAuthenticityDialog.newInstance(...)
to supply an UnverifiedHubVaultConfig so the runtime cast in setupDialog no
longer fails (refer to the newInstance function and the
UNVERIFIED_VAULT_CONFIG_ARG/HubCheckHostAuthenticityDialog class).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@presentation/src/main/java/org/cryptomator/presentation/presenter/UnlockVaultPresenter.kt`:
- Around line 167-177: The branch ordering makes trusted HTTPS hosts hit the
dialog because configContainsAllowedHosts(...) can be true while isHttpHost(...)
is false; update the conditional logic in UnlockVaultPresenter (around the calls
to allowedHubHosts, configContainsAllowedHosts, isHttpHost, and
isCryptomatorCloud) so that if
configContainsAllowedHosts(unverifiedHubVaultConfig) is true you immediately
call allowedHubHosts(unverifiedHubVaultConfig, vault) (i.e., remove the
isHttpHost() requirement), keeping the existing Cryptomator Cloud/http error
branch and the HubCheckHostAuthenticityDialog.newInstance fallback otherwise.

In `@presentation/src/main/res/values/strings.xml`:
- Around line 337-340: Update the user-facing strings so they reflect the actual
flow: change the value of the string resource named
"screen_hub_clear_unknown_hub_hosts_title" from "Clear Unknown Hub Hosts" to
wording that clearly indicates it clears previously approved hosts (e.g., "Clear
Approved Hub Hosts" or "Clear Previously Approved Hosts"), and locate any string
entries whose text is "Trust this hosts?" (and duplicates mentioned elsewhere)
and correct the grammar to "Trust these hosts?". Edit the corresponding string
resource values in strings.xml for those identifiers to ensure consistency
across the file.

---

Nitpick comments:
In
`@presentation/src/main/java/org/cryptomator/presentation/ui/dialog/HubCheckHostAuthenticityDialog.kt`:
- Around line 48-53: The factory method newInstance currently accepts a broad
UnverifiedVaultConfig but setupDialog always casts it to
UnverifiedHubVaultConfig, causing potential runtime cast failures; change the
newInstance signature to accept UnverifiedHubVaultConfig (instead of
UnverifiedVaultConfig), update the args.putSerializable call to pass that typed
value, and update any callers of HubCheckHostAuthenticityDialog.newInstance(...)
to supply an UnverifiedHubVaultConfig so the runtime cast in setupDialog no
longer fails (refer to the newInstance function and the
UNVERIFIED_VAULT_CONFIG_ARG/HubCheckHostAuthenticityDialog class).

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: ed413e42-ef77-4b38-a98f-7e3121d56df9

📥 Commits

Reviewing files that changed from the base of the PR and between add3c80 and 5a7fa9e.

📒 Files selected for processing (8)
  • presentation/src/main/java/org/cryptomator/presentation/presenter/UnlockVaultPresenter.kt
  • presentation/src/main/java/org/cryptomator/presentation/ui/activity/UnlockVaultActivity.kt
  • presentation/src/main/java/org/cryptomator/presentation/ui/dialog/HubCheckHostAuthenticityDialog.kt
  • presentation/src/main/java/org/cryptomator/presentation/ui/fragment/SettingsFragment.kt
  • presentation/src/main/res/layout/dialog_hub_check_host_authenticity.xml
  • presentation/src/main/res/values/strings.xml
  • presentation/src/main/res/xml/preferences.xml
  • util/src/main/java/org/cryptomator/util/SharedPreferencesHandler.kt

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: 2

🧹 Nitpick comments (2)
presentation/src/main/java/org/cryptomator/presentation/presenter/UnlockVaultPresenter.kt (2)

226-233: Consider null safety for uri.scheme and uri.host.

Both URI.scheme and URI.host can return null for malformed URIs, which would produce authority strings like "null://null". While such configs should fail consistency checks earlier, adding defensive handling would prevent unexpected behavior.

♻️ Suggested defensive implementation
 private fun getAuthority(uri: URI): String {
+    val scheme = uri.scheme ?: return ""
+    val host = uri.host ?: return ""
     return when (uri.port) {
-        -1 -> "%s://%s".format(uri.scheme, uri.host)
-        80 -> "http://%s".format(uri.host)
-        443 -> "https://%s".format(uri.host)
-        else -> "%s://%s:%s".format(uri.scheme, uri.host, uri.port)
+        -1 -> "%s://%s".format(scheme, host)
+        80 -> "http://%s".format(host)
+        443 -> "https://%s".format(host)
+        else -> "%s://%s:%s".format(scheme, host, uri.port)
     }
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@presentation/src/main/java/org/cryptomator/presentation/presenter/UnlockVaultPresenter.kt`
around lines 226 - 233, The getAuthority function can produce "null" parts when
URI.scheme or URI.host are null; update getAuthority to defensively handle nulls
by using safe defaults or throwing a clear IllegalArgumentException: check
uri.scheme and uri.host at the start of getAuthority (or inside each when
branch) and either substitute a safe value (e.g., empty string or "unknown") or
raise an error with context including the URI; keep decision consistent across
branches that reference uri.scheme, uri.host, and uri.port so authority strings
are never constructed with literal "null" values.

218-218: Remove trailing semicolon.

Semicolons are not idiomatic in Kotlin.

✏️ Fix
-    return allowedHubHosts.contains(canonicalHubHost) && allowedHubHosts.contains(canonicalAuthHost);
+    return allowedHubHosts.contains(canonicalHubHost) && allowedHubHosts.contains(canonicalAuthHost)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@presentation/src/main/java/org/cryptomator/presentation/presenter/UnlockVaultPresenter.kt`
at line 218, The return statement in UnlockVaultPresenter (the line returning
allowedHubHosts.contains(canonicalHubHost) &&
allowedHubHosts.contains(canonicalAuthHost)) has an unnecessary trailing
semicolon; remove the semicolon so the Kotlin idiomatic statement is just:
return allowedHubHosts.contains(canonicalHubHost) &&
allowedHubHosts.contains(canonicalAuthHost) to fix the style issue.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@presentation/src/main/java/org/cryptomator/presentation/presenter/UnlockVaultPresenter.kt`:
- Around line 205-208: The isCryptomatorCloud check can NPE because URI.host may
be null; update the method (isCryptomatorCloud in UnlockVaultPresenter) to
null-safe-check the hosts from UnverifiedHubVaultConfig.apiBaseUrl.host and
.authEndpoint.host before calling endsWith(trustedCryptomatorCloudDomain) (e.g.,
guard each host with an explicit null check or use a null-safe endsWith check
and only return true if both hosts are non-null and end with
trustedCryptomatorCloudDomain).
- Around line 164-179: The Timber logging tag is inconsistent: replace the
incorrect "VaultListPresenter" tag usages inside UnlockVaultPresenter with
"UnlockVaultPresenter" so all Timber.tag(...) calls in this class (the calls
that currently read Timber.tag("VaultListPresenter").e(...)) consistently use
Timber.tag("UnlockVaultPresenter").e(...), ensuring the log statements in the
hub config handling block and any related error branches match the class name
used elsewhere in UnlockVaultPresenter.

---

Nitpick comments:
In
`@presentation/src/main/java/org/cryptomator/presentation/presenter/UnlockVaultPresenter.kt`:
- Around line 226-233: The getAuthority function can produce "null" parts when
URI.scheme or URI.host are null; update getAuthority to defensively handle nulls
by using safe defaults or throwing a clear IllegalArgumentException: check
uri.scheme and uri.host at the start of getAuthority (or inside each when
branch) and either substitute a safe value (e.g., empty string or "unknown") or
raise an error with context including the URI; keep decision consistent across
branches that reference uri.scheme, uri.host, and uri.port so authority strings
are never constructed with literal "null" values.
- Line 218: The return statement in UnlockVaultPresenter (the line returning
allowedHubHosts.contains(canonicalHubHost) &&
allowedHubHosts.contains(canonicalAuthHost)) has an unnecessary trailing
semicolon; remove the semicolon so the Kotlin idiomatic statement is just:
return allowedHubHosts.contains(canonicalHubHost) &&
allowedHubHosts.contains(canonicalAuthHost) to fix the style issue.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 701843d1-beb4-450a-a9d9-16c252287ba4

📥 Commits

Reviewing files that changed from the base of the PR and between 5a7fa9e and c3df11a.

📒 Files selected for processing (1)
  • presentation/src/main/java/org/cryptomator/presentation/presenter/UnlockVaultPresenter.kt

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 (1)
presentation/src/main/res/values/strings.xml (1)

254-254: ⚠️ Potential issue | 🟡 Minor

Copy still doesn't match the trust flow.

This setting clears previously trusted hosts, so “Reset Unknown Hub Hosts” reads backwards. The dialog title also still has the grammar issue “Trust this hosts?”. Please rename them to reflect trusted hosts / “Trust these hosts?”.

Also applies to: 564-565

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@presentation/src/main/res/values/strings.xml` at line 254, The string
"screen_hub_reset_unknown_hub_hosts_title" and the dialog copy that reads "Trust
this hosts?" are incorrect for the trust flow; change the title to reflect that
this clears previously trusted hosts (e.g., "Reset Trusted Hub Hosts" or "Reset
Trusted Hosts") and fix the confirmation grammar by replacing "Trust this
hosts?" with "Trust these hosts?" — update the resource value for
screen_hub_reset_unknown_hub_hosts_title and the related confirmation string
resource (search for the resource containing "Trust this hosts?") accordingly.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@presentation/src/main/java/org/cryptomator/presentation/presenter/UnlockVaultPresenter.kt`:
- Around line 215-218: The current containsAllowedHosts() logic trusts hosts
individually which allows mixing approved api/auth pairs (e.g., (apiA,authA) and
(apiB,authB) to validate (apiA,authB)); change the model to validate the exact
approved pair/fingerprint instead: replace the flat host-set check in
containsAllowedHosts(UnverifiedHubVaultConfig) (and the similar check at the
other occurrence) with a lookup against stored approved-pair identifiers (e.g.,
a canonical pair key or fingerprint derived from apiBaseUrl+authEndpoint) and
update the preference helper to store and retrieve that single canonical
pair/fingerprint instead of two independent host entries so only the exact
approved api+auth combination is accepted.
- Around line 161-183: Short-circuit unsupported Hub vault actions by validating
intent.vaultAction() before showing the hub-host authenticity dialog or
persisting allowed hosts: check the action (e.g. CHANGE_PASSWORD,
ENCRYPT_PASSWORD, UNLOCK_FOR_BIOMETRIC_AUTH) at the start of the branch handling
unverifiedVaultConfig (the same place that calls isConsistentHubConfig and
before invoking
view?.showDialog(HubCheckHostAuthenticityDialog.newInstance(...))), and if the
action is not supported for hub operations, call finish() / show the existing
error flow instead of calling allowedHubHosts(...) or letting
onHubCheckHostsAllowed() persist to SharedPreferences; ensure
allowedHubHosts(...) and onHubCheckHostsAllowed() only run for supported
intent.vaultAction() values.
- Around line 201-203: isConsistentHubConfig currently uses getAuthority which
normalizes ports to schemes and can conflate different schemes; change it to
compare scheme, host, and port explicitly (or normalize by removing the port
only when it equals the default for that same scheme) so that https://host:443
and http://host:443 are not treated as equal, and ensure the HTTP-check logic
(isHttpHost or equivalent) inspects tokenEndpoint as well; update the logic in
isConsistentHubConfig and the related hub endpoint canonicalization (the code
around isConsistentHubConfig and the block referenced at 221-232) to perform
scheme+host+port-aware comparison rather than relying on getAuthority.

---

Duplicate comments:
In `@presentation/src/main/res/values/strings.xml`:
- Line 254: The string "screen_hub_reset_unknown_hub_hosts_title" and the dialog
copy that reads "Trust this hosts?" are incorrect for the trust flow; change the
title to reflect that this clears previously trusted hosts (e.g., "Reset Trusted
Hub Hosts" or "Reset Trusted Hosts") and fix the confirmation grammar by
replacing "Trust this hosts?" with "Trust these hosts?" — update the resource
value for screen_hub_reset_unknown_hub_hosts_title and the related confirmation
string resource (search for the resource containing "Trust this hosts?")
accordingly.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 50d3ae8e-8122-4ebf-b726-ee68175785dd

📥 Commits

Reviewing files that changed from the base of the PR and between c3df11a and b8f841f.

📒 Files selected for processing (3)
  • presentation/src/main/java/org/cryptomator/presentation/presenter/UnlockVaultPresenter.kt
  • presentation/src/main/res/values/strings.xml
  • presentation/src/main/res/xml/preferences.xml

@SailReal SailReal merged commit a9faa2b into develop Mar 12, 2026
3 checks passed
@SailReal SailReal deleted the feature/hub-host-trust-validation branch March 12, 2026 12:24
@SailReal SailReal added this to the 1.12.3 milestone Mar 12, 2026
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