[PM-39239] Surface shareable access URLs in bw send output#1235
Conversation
bw send get --text and the default output of bw send create now emit a shareable access URL (<web-vault>/#/send/<access_id>/<url_b64_key>) instead of the raw access_id. The web-vault base is derived from the client's configured API URL, so self-hosted and cloud both work without hardcoding bitwarden.com.
🤖 Bitwarden Claude Code ReviewOverall Assessment: REQUEST CHANGES Reviewed the change that makes Code Review Details
|
| /// Pure derivation of the web-vault base from an API URL. Strips a trailing `/api` (the suffix the | ||
| /// CLI appends when building `api_url` from a server URL) and any surrounding slashes. Split out | ||
| /// from [`web_vault_url`] so it can be unit-tested without a live client. | ||
| fn web_vault_from_api_url(api_url: &str) -> String { | ||
| let trimmed = api_url.trim_end_matches('/'); | ||
| trimmed | ||
| .strip_suffix("/api") | ||
| .unwrap_or(trimmed) | ||
| .trim_end_matches('/') | ||
| .to_string() |
There was a problem hiding this comment.
Details and fix
web_vault_from_api_url only strips a trailing /api. For the cloud default, the client's api_url is https://api.bitwarden.com (see main.rs:213 and the default when --server is omitted at login). That host has no /api suffix, so it is returned untouched and the assembled URL becomes:
https://api.bitwarden.com/#/send/<access_id>/<url_key>
The API host does not serve the web-vault SPA, so this is not a working recipient link. The web_vault_from_api_url_leaves_non_api_url_untouched test pins this behavior, but the resulting URL is broken for the most common (cloud) case. The same applies to self-hosted deployments that use a distinct API subdomain (e.g. api_url = https://api.example.com).
The legacy CLI does not derive the web vault from the API URL — getSendUrl()/getWebVaultUrl() return the actual configured vault/send host (for cloud, https://vault.bitwarden.com / https://send.bitwarden.com). Consider deriving the web-vault base from a configured web-vault URL (the web_vault config field already exists but is not wired into the client) rather than inverting api_url, and special-casing the cloud api.bitwarden.com host so it maps to the vault host instead of emitting a link to the API origin.
At minimum, the single-domain self-hosted assumption (api_url == <web-vault>/api) should be documented as a known limitation and the cloud default handled.
|
🔍 SDK Breaking Change DetectionSDK Version:
Breaking change detection uses the build of the SDK from this branch, including any incompatibities pre-existing on or merged into this branch. Check the workflow logs to confirm. |
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## tools/pm-34719/add-send-commands-to-rust-cli-2 #1235 +/- ##
==================================================================================
- Coverage 85.13% 85.08% -0.05%
==================================================================================
Files 467 465 -2
Lines 65249 64850 -399
==================================================================================
- Hits 55549 55178 -371
+ Misses 9700 9672 -28 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
|
|
||
| /// Build the shareable Send access URL from a decrypted [`SendView`]. | ||
| /// | ||
| /// Format: `<web-vault>/#/send/<access_id>/<url_b64_key>`. |
There was a problem hiding this comment.
❓ I need to look at this more closely, but this look dangerous and might behave differently across environments.
@itsadrago can you please take a look at this and determine if this will be verifiable before a production release? I think a testing strategy was established during PM-39449.
There was a problem hiding this comment.
My main takeaway from 39449 was that the US production env - and only that env - has a vanity URL that redirects to the vault, but hitting the vault link directly works too. Since that is the case I think the links produced by this code will work as-is, we just won't get the vanity URL in US prod. It would still be good to get confirmation from @itsadrago, that was a messy ticket :D
There was a problem hiding this comment.
@mcamirault is correct. The links should work as-is, but we lose the vanity URL for the US prod env. I believe the CLI client doesn't have an authoritative source for the correct sends hostname and domain to use and so we have to derive it. We need a configuration service in this repo similar to DefaultEnvironmentService in the clients repo, but that's probably out of the scope of this work
| let web_vault = web_vault_url(client); | ||
| let url_key = to_url_b64(key); | ||
|
|
||
| Ok(format!("{web_vault}/#/send/{access_id}/{url_key}")) |
There was a problem hiding this comment.
While the approach itself is likely okay, it does bare risk of being brittle and needed in multiple places. I've started a discussion with the rest of the platform team, to see if there's a way to provide that url in a similar manner as the TS-clients currently do https://github.com/bitwarden/clients/blob/main/libs/common/src/platform/services/default-environment.service.ts#L441



🎟️ Tracking
https://bitwarden.atlassian.net/browse/PM-39239
📔 Objective
For Rust CLI
bw send get --text and the default output of bw send create now emit a shareable access URL that a user can paste to a recipient, instead of the raw access_id.
Previously --text emitted only the raw access_id and the create default output omitted the URL entirely — both because bw had no access to the configured web-vault base URL.