Skip to content

Commit 91eadb5

Browse files
UniFFI don't panic on failed lift (#373)
## 🎟️ Tracking <!-- Paste the link to the Jira or GitHub issue or otherwise describe / point to where this change is coming from. --> ## 📔 Objective UniFFI uses the `custom_type!` macro to convert request/response types. The request conversion is allowed to fail which should produce an error in the apps, but there are cases where it would produce a panic instead. The cases are: - If the FFI function doesn't return a result, then UniFFI produces a panic. - If the Error type of the function is different than the Error type in `custom_type!`, then UniFFI produces a panic. One way to fix this is to have the `custom_type!` calls return `bitwarden_uniffi::error::BitwardenError`, but this isn't possible as core and crypto can't depend on uniffi due to circular dependency issues. This PR makes the uniffi crate register an error conversion function during client initialization, thanks to the use of a new `uniffi-error` crate. It also updates all the calls to `custom_type!` to use this new error conversion. ## ⏰ Reminders before review - Contributor guidelines followed - All formatters and local linters executed and passed - Written new unit and / or integration tests where applicable - Protected functional changes with optionality (feature flags) - Used internationalization (i18n) for all UI strings - CI builds passed - Communicated to DevOps any deployment requirements - Updated any necessary documentation (Confluence, contributing docs) or informed the documentation team ## 🦮 Reviewer guidelines <!-- Suggested interactions but feel free to use (or not) as you desire! --> - 👍 (`:+1:`) or similar for great changes - 📝 (`:memo:`) or ℹ️ (`:information_source:`) for notes or general info - ❓ (`:question:`) for questions - 🤔 (`:thinking:`) or 💭 (`:thought_balloon:`) for more open inquiry that's not quite a confirmed issue and could potentially benefit from discussion - 🎨 (`:art:`) for suggestions / improvements - ❌ (`:x:`) or ⚠️ (`:warning:`) for more significant problems or concerns needing attention - 🌱 (`:seedling:`) or ♻️ (`:recycle:`) for future improvements or indications of technical debt - ⛏ (`:pick:`) for minor or nitpick changes --------- Co-authored-by: Thomas Avery <[email protected]>
1 parent f52e521 commit 91eadb5

File tree

15 files changed

+121
-19
lines changed

15 files changed

+121
-19
lines changed

Cargo.lock

Lines changed: 12 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ bitwarden-ssh = { path = "crates/bitwarden-ssh", version = "=1.0.0" }
3939
bitwarden-state = { path = "crates/bitwarden-state", version = "=1.0.0" }
4040
bitwarden-test = { path = "crates/bitwarden-test", version = "=1.0.0" }
4141
bitwarden-threading = { path = "crates/bitwarden-threading", version = "=1.0.0" }
42+
bitwarden-uniffi-error = { path = "crates/bitwarden-uniffi-error", version = "=1.0.0" }
4243
bitwarden-uuid = { path = "crates/bitwarden-uuid", version = "=1.0.0" }
4344
bitwarden-uuid-macro = { path = "crates/bitwarden-uuid-macro", version = "=1.0.0" }
4445
bitwarden-vault = { path = "crates/bitwarden-vault", version = "=1.0.0" }

crates/bitwarden-core/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ bitwarden-crypto = { workspace = true }
3737
bitwarden-encoding = { workspace = true }
3838
bitwarden-error = { workspace = true }
3939
bitwarden-state = { workspace = true }
40+
bitwarden-uniffi-error = { workspace = true }
4041
bitwarden-uuid = { workspace = true }
4142
chrono = { workspace = true, features = ["std"] }
4243
# We don't use this directly (it's used by rand), but we need it here to enable WASM support

crates/bitwarden-core/src/uniffi_support.rs

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
33
use std::{num::NonZeroU32, str::FromStr};
44

5-
use bitwarden_crypto::CryptoError;
5+
use bitwarden_uniffi_error::convert_result;
66
use uuid::Uuid;
77

88
use crate::key_management::{PasswordProtectedKeyEnvelope, SignedSecurityState};
@@ -14,7 +14,7 @@ uniffi::custom_type!(DateTime, std::time::SystemTime, { remote });
1414

1515
uniffi::custom_type!(Uuid, String, {
1616
remote,
17-
try_lift: |val| Uuid::parse_str(val.as_str()).map_err(|e| e.into()),
17+
try_lift: |val| convert_result(Uuid::parse_str(&val)),
1818
lower: |obj| obj.to_string(),
1919
});
2020

@@ -29,17 +29,14 @@ struct UniffiConverterDummyRecord {
2929

3030
uniffi::custom_type!(SignedSecurityState, String, {
3131
try_lift: |val| {
32-
val.parse().map_err(|e| {
33-
CryptoError::EncodingError(e).into()
34-
})
32+
convert_result(SignedSecurityState::from_str(&val))
3533
},
3634
lower: |obj| obj.into(),
3735
});
3836

3937
uniffi::custom_type!(PasswordProtectedKeyEnvelope, String, {
4038
remote,
41-
try_lift: |val| bitwarden_crypto::safe::PasswordProtectedKeyEnvelope::from_str(val.as_str())
42-
.map_err(|e| e.into())
43-
.map(PasswordProtectedKeyEnvelope),
39+
try_lift: |val| convert_result(bitwarden_crypto::safe::PasswordProtectedKeyEnvelope::from_str(&val)
40+
.map(PasswordProtectedKeyEnvelope)),
4441
lower: |obj| obj.0.into(),
4542
});

crates/bitwarden-crypto/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ argon2 = { version = ">=0.5.0, <0.6", features = [
3030
base64 = ">=0.22.1, <0.23"
3131
bitwarden-encoding = { workspace = true }
3232
bitwarden-error = { workspace = true }
33+
bitwarden-uniffi-error = { workspace = true }
3334
cbc = { version = ">=0.1.2, <0.2", features = ["alloc", "zeroize"] }
3435
chacha20poly1305 = { version = "0.10.1" }
3536
ciborium = { version = ">=0.2.2, <0.3" }
Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,34 @@
11
use std::{num::NonZeroU32, str::FromStr};
22

3+
use bitwarden_uniffi_error::convert_result;
4+
35
use crate::{CryptoError, EncString, SignedPublicKey, UnsignedSharedKey};
46

57
uniffi::custom_type!(NonZeroU32, u32, {
68
remote,
79
try_lift: |val| {
8-
NonZeroU32::new(val).ok_or(CryptoError::ZeroNumber.into())
10+
convert_result(NonZeroU32::new(val).ok_or(CryptoError::ZeroNumber))
911
},
1012
lower: |obj| obj.get(),
1113
});
1214

1315
uniffi::custom_type!(EncString, String, {
1416
try_lift: |val| {
15-
EncString::from_str(&val).map_err(|e: CryptoError| e.into())
17+
convert_result(EncString::from_str(&val))
1618
},
1719
lower: |obj| obj.to_string(),
1820
});
1921

2022
uniffi::custom_type!(UnsignedSharedKey, String, {
2123
try_lift: |val| {
22-
UnsignedSharedKey::from_str(&val).map_err(|e: CryptoError| e.into())
24+
convert_result(UnsignedSharedKey::from_str(&val))
2325
},
2426
lower: |obj| obj.to_string(),
2527
});
2628

2729
uniffi::custom_type!(SignedPublicKey, String, {
2830
try_lift: |val| {
29-
val.parse().map_err(|e| {
30-
CryptoError::EncodingError(e).into()
31-
})
31+
convert_result(SignedPublicKey::from_str(&val))
3232
},
3333
lower: |obj| obj.into(),
3434
});

crates/bitwarden-encoding/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ uniffi = ["dep:uniffi"]
1919
wasm = ["dep:tsify", "dep:wasm-bindgen"]
2020

2121
[dependencies]
22+
bitwarden-uniffi-error = { workspace = true }
2223
data-encoding = { workspace = true }
2324
data-encoding-macro = "0.1.18"
2425
serde = { workspace = true }
Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,19 @@
1-
use crate::{b64::NotB64Encoded, b64url::NotB64UrlEncoded, B64Url, B64};
1+
use std::str::FromStr;
2+
3+
use bitwarden_uniffi_error::convert_result;
4+
5+
use crate::{B64Url, B64};
26

37
uniffi::custom_type!(B64, String, {
48
try_lift: |val| {
5-
val.parse().map_err(|e: NotB64Encoded| e.into())
9+
convert_result(B64::from_str(&val))
610
},
711
lower: |obj| obj.to_string(),
812
});
913

1014
uniffi::custom_type!(B64Url, String, {
1115
try_lift: |val| {
12-
val.parse().map_err(|e: NotB64UrlEncoded| e.into())
16+
convert_result(B64Url::from_str(&val))
1317
},
1418
lower: |obj| obj.to_string(),
1519
});
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
[package]
2+
name = "bitwarden-uniffi-error"
3+
description = """
4+
Internal crate for the bitwarden crate. Do not use.
5+
"""
6+
7+
version.workspace = true
8+
authors.workspace = true
9+
edition.workspace = true
10+
rust-version.workspace = true
11+
readme.workspace = true
12+
homepage.workspace = true
13+
repository.workspace = true
14+
license-file.workspace = true
15+
keywords.workspace = true
16+
17+
[features]
18+
uniffi = ["dep:uniffi"]
19+
20+
[dependencies]
21+
anyhow = { version = ">=1.0, <2.0" }
22+
uniffi = { workspace = true, optional = true }
23+
24+
[lints]
25+
workspace = true
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
# Bitwarden UniFFI error
2+
3+
This crate provides some utilities to convert results inside `uniffi::custom_type!` calls, so that
4+
they don't produce panics when there is a parsing error.

0 commit comments

Comments
 (0)