Skip to content

Commit bc51972

Browse files
committed
Restrict the access module to its actual API surface
Everything the CLI does not name is now pub(super). In wire only the item DTOs stay public, because model::Item exposes them through its fields; the auth and session DTOs are internal. Also drops three imports the blanket allow had been hiding.
1 parent 178b7b8 commit bc51972

17 files changed

Lines changed: 96 additions & 92 deletions

File tree

crates/bitwarden-importers/src/importers/onepassword/access/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,3 +35,4 @@ into Bitwarden collections. 1P doesn't have folders, only tags.
3535
- The sign-in domain is taken as a raw string and never validated
3636
- A vault we hold no key for is skipped silently, and one undecryptable item aborts the whole import
3737
- The module is under a blanket `allow(dead_code, unused_imports)` until the conversion layer lands
38+
- Only the item DTOs in `wire` are public; the auth and session ones are `pub(super)`

crates/bitwarden-importers/src/importers/onepassword/access/account_key.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use super::{error::OnePasswordError, kdf};
66

77
/// A parsed 1Password Account Key (also called the Secret Key), split into its format, uuid, and
88
/// key.
9-
pub struct AccountKey {
9+
pub(super) struct AccountKey {
1010
pub format: String,
1111
pub uuid: String,
1212
pub key: String,
@@ -21,7 +21,7 @@ impl Drop for AccountKey {
2121
impl AccountKey {
2222
/// Parses a key string such as `A3-RTN9SA-DY9445Y5FF96X6E7B5GPFA95R9`. The string is uppercased
2323
/// and its dashes removed before splitting into `format` (2), `uuid` (6), and `key` (the rest).
24-
pub fn parse(input: &str) -> Result<AccountKey, OnePasswordError> {
24+
pub(super) fn parse(input: &str) -> Result<AccountKey, OnePasswordError> {
2525
let s = input.to_uppercase().replace('-', "");
2626

2727
let Some(format) = s.get(..2) else {
@@ -64,12 +64,12 @@ impl AccountKey {
6464
}
6565

6666
/// `HKDF-SHA256(ikm = key, salt = uuid, info = format)`, 32 bytes.
67-
pub fn hash(&self) -> [u8; 32] {
67+
pub(super) fn hash(&self) -> [u8; 32] {
6868
kdf::hkdf_sha256(&self.format, self.key.as_bytes(), self.uuid.as_bytes())
6969
}
7070

7171
/// XORs the hash with `bytes`, which must be exactly 32 bytes long.
72-
pub fn combine_with(&self, bytes: &[u8]) -> Result<[u8; 32], OnePasswordError> {
72+
pub(super) fn combine_with(&self, bytes: &[u8]) -> Result<[u8; 32], OnePasswordError> {
7373
let mut h = self.hash();
7474
if h.len() != bytes.len() {
7575
return Err(OnePasswordError::Internal(

crates/bitwarden-importers/src/importers/onepassword/access/client.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ use super::{
1414
two_factor::TwoFactorUi,
1515
wire::{
1616
AccountInfo, EncryptedEnvelope, KeysetsInfo, VaultAccess, VaultAttributes, VaultItem,
17-
VaultItemDetails, VaultItemOverview, VaultItemsBatch,
17+
VaultItemsBatch,
1818
},
1919
};
2020

crates/bitwarden-importers/src/importers/onepassword/access/device.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ pub fn generate_device_uuid() -> String {
2626
}
2727

2828
/// Client identity headers sent with every request.
29-
pub struct ClientInfo {
29+
pub(super) struct ClientInfo {
3030
client_name: String,
3131
client_version: String,
3232
pub user_agent: String,
@@ -36,7 +36,7 @@ pub struct ClientInfo {
3636

3737
impl ClientInfo {
3838
/// Impersonates the 1Password desktop client for the current platform.
39-
pub fn for_desktop(device_uuid: &str) -> ClientInfo {
39+
pub(super) fn for_desktop(device_uuid: &str) -> ClientInfo {
4040
let platform = PLATFORM;
4141

4242
ClientInfo {
@@ -51,7 +51,7 @@ impl ClientInfo {
5151
}
5252
}
5353

54-
pub fn client_id(&self) -> String {
54+
pub(super) fn client_id(&self) -> String {
5555
format!("{}/{}", self.client_name, self.client_version)
5656
}
5757

@@ -60,7 +60,7 @@ impl ClientInfo {
6060
/// The real 1Password clients also send `model` and `osVersion`. The server accepted their
6161
/// removal when this was tested, so they are left out, but add them back if it starts
6262
/// rejecting the request.
63-
pub fn device_body(&self) -> Value {
63+
pub(super) fn device_body(&self) -> Value {
6464
json!({
6565
"uuid": self.device_uuid,
6666
"clientName": self.client_name,
@@ -74,7 +74,7 @@ impl ClientInfo {
7474
}
7575

7676
/// Registers the device with the server.
77-
pub async fn register_device(
77+
pub(super) async fn register_device(
7878
client_info: &ClientInfo,
7979
rest: &RestClient,
8080
) -> Result<(), OnePasswordError> {
@@ -85,7 +85,7 @@ pub async fn register_device(
8585
}
8686

8787
/// Reauthorizes a previously deleted device.
88-
pub async fn reauthorize_device(
88+
pub(super) async fn reauthorize_device(
8989
client_info: &ClientInfo,
9090
rest: &RestClient,
9191
) -> Result<(), OnePasswordError> {

crates/bitwarden-importers/src/importers/onepassword/access/identity.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,16 +13,16 @@
1313
//! an open question. See the development notes in this module's README.
1414
1515
/// The desktop app's build number, sent as the client version and inside the op user agent.
16-
pub const VERSION: &str = "81210036";
16+
pub(super) const VERSION: &str = "81210036";
1717

1818
/// The HTTP library the desktop app reports. That app is itself written in Rust, so this is *its*
1919
/// reqwest version, not ours. Do not sync it with the workspace's reqwest pin; it is part of the
2020
/// fingerprint, and the two are unrelated.
21-
pub const HTTP_LIB: &str = "reqwest|0.12.24";
21+
pub(super) const HTTP_LIB: &str = "reqwest|0.12.24";
2222

2323
/// The per-platform half of the identity. The version and HTTP library above are the same
2424
/// everywhere, so only these four fields vary.
25-
pub struct Platform {
25+
pub(super) struct Platform {
2626
/// Names the client: `1Password for Mac`.
2727
pub os: &'static str,
2828
/// Single-letter platform code, the second field of the op user agent.
@@ -34,15 +34,15 @@ pub struct Platform {
3434
}
3535

3636
#[cfg(target_os = "macos")]
37-
pub const PLATFORM: Platform = Platform {
37+
pub(super) const PLATFORM: Platform = Platform {
3838
os: "Mac",
3939
op_code: "M",
4040
os_suffix: "MacOSX|26.3.1|aarch64",
4141
os_name: "macOS",
4242
};
4343

4444
#[cfg(target_os = "linux")]
45-
pub const PLATFORM: Platform = Platform {
45+
pub(super) const PLATFORM: Platform = Platform {
4646
os: "Linux",
4747
op_code: "L",
4848
os_suffix: "Linux|Ubuntu 24.04|x86_64",
@@ -51,7 +51,7 @@ pub const PLATFORM: Platform = Platform {
5151

5252
// Every other target, wasm32 included, presents as the Windows build.
5353
#[cfg(not(any(target_os = "macos", target_os = "linux")))]
54-
pub const PLATFORM: Platform = Platform {
54+
pub(super) const PLATFORM: Platform = Platform {
5555
os: "Windows",
5656
op_code: "W",
5757
os_suffix: "Windows|25H2 11.0.26200|x86_64",

crates/bitwarden-importers/src/importers/onepassword/access/kdf.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use sha2::{Sha256, Sha512};
88
use super::{account_key::AccountKey, error::OnePasswordError};
99

1010
/// HKDF-SHA256 producing 32 bytes, with `method` as the `info` parameter.
11-
pub fn hkdf_sha256(method: &str, ikm: &[u8], salt: &[u8]) -> [u8; 32] {
11+
pub(super) fn hkdf_sha256(method: &str, ikm: &[u8], salt: &[u8]) -> [u8; 32] {
1212
let hk = Hkdf::<Sha256>::new(Some(salt), ikm);
1313
let mut okm = [0u8; 32];
1414
hk.expand(method.as_bytes(), &mut okm)
@@ -20,7 +20,7 @@ pub fn hkdf_sha256(method: &str, ikm: &[u8], salt: &[u8]) -> [u8; 32] {
2020
///
2121
/// `PBES2[g]-HS256` uses PBKDF2-HMAC-SHA256, `PBES2[g]-HS512` uses PBKDF2-HMAC-SHA512, both 32
2222
/// bytes.
23-
pub fn pbes2(
23+
pub(super) fn pbes2(
2424
method: &str,
2525
password: &str,
2626
salt: &[u8],
@@ -48,7 +48,7 @@ pub fn pbes2(
4848
///
4949
/// `k1 = HKDF(info = algorithm, ikm = salt, salt = lower(username))`; `k2 = PBES2(algorithm,
5050
/// NFC(password), k1, iterations)`; result `= account_key.combine_with(k2)`.
51-
pub fn derive_master_key(
51+
pub(super) fn derive_master_key(
5252
algorithm: &str,
5353
iterations: u32,
5454
salt: &[u8],

crates/bitwarden-importers/src/importers/onepassword/access/keychain.rs

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ use super::{
1010
kdf,
1111
opdata::{AesKey, Encrypted, decode64_loose},
1212
rsa::RsaKey,
13-
wire::{AesKeyJson, EncryptedEnvelope, KeysetInfo, KeysetsInfo, RsaKeyJwk},
13+
wire::{AesKeyJson, EncryptedEnvelope, KeysetInfo, RsaKeyJwk},
1414
};
1515

1616
const AES_SCHEME: &str = "A256GCM";
@@ -19,21 +19,21 @@ const MASTER_KEY_ID: &str = "mp";
1919

2020
/// A store of AES and RSA keys keyed by their kid.
2121
#[derive(Default)]
22-
pub struct Keychain {
22+
pub(super) struct Keychain {
2323
aes: HashMap<String, AesKey>,
2424
rsa: HashMap<String, RsaKey>,
2525
}
2626

2727
impl Keychain {
28-
pub fn new() -> Keychain {
28+
pub(super) fn new() -> Keychain {
2929
Keychain::default()
3030
}
3131

32-
pub fn add_aes(&mut self, key: AesKey) {
32+
pub(super) fn add_aes(&mut self, key: AesKey) {
3333
self.aes.insert(key.id.clone(), key);
3434
}
3535

36-
pub fn add_rsa(&mut self, key: RsaKey) {
36+
pub(super) fn add_rsa(&mut self, key: RsaKey) {
3737
self.rsa.insert(key.id.clone(), key);
3838
}
3939

@@ -48,7 +48,7 @@ impl Keychain {
4848
}
4949

5050
/// Decrypts an envelope by dispatching on its scheme to the AES or RSA key named by its kid.
51-
pub fn decrypt(&self, encrypted: &Encrypted) -> Result<Vec<u8>, OnePasswordError> {
51+
pub(super) fn decrypt(&self, encrypted: &Encrypted) -> Result<Vec<u8>, OnePasswordError> {
5252
if encrypted.scheme == AES_SCHEME {
5353
let key = self.aes.get(&encrypted.key_id).ok_or_else(|| {
5454
OnePasswordError::Internal(format!("AES key '{}' not found", encrypted.key_id))
@@ -73,7 +73,7 @@ impl Keychain {
7373
///
7474
/// A scheme this module does not implement is an error, not a `false`: the caller cannot tell
7575
/// "we lack the key" from "we cannot read this format" otherwise, and would silently drop data.
76-
pub fn can_decrypt(&self, encrypted: &Encrypted) -> Result<bool, OnePasswordError> {
76+
pub(super) fn can_decrypt(&self, encrypted: &Encrypted) -> Result<bool, OnePasswordError> {
7777
if encrypted.scheme == AES_SCHEME {
7878
return Ok(self.aes.contains_key(&encrypted.key_id));
7979
}
@@ -89,7 +89,7 @@ impl Keychain {
8989
}
9090

9191
/// Decrypts an envelope and parses its JSON plaintext.
92-
pub fn decrypt_json<T: DeserializeOwned>(
92+
pub(super) fn decrypt_json<T: DeserializeOwned>(
9393
&self,
9494
envelope: &EncryptedEnvelope,
9595
) -> Result<T, OnePasswordError> {
@@ -98,7 +98,7 @@ impl Keychain {
9898
}
9999

100100
/// Derives the master key from the credentials, then decrypts every keyset into the keychain.
101-
pub fn decrypt_keysets(
101+
pub(super) fn decrypt_keysets(
102102
&mut self,
103103
keysets: &[KeysetInfo],
104104
username: &str,
@@ -132,7 +132,7 @@ impl Keychain {
132132
}
133133

134134
/// Decrypts an encrypted AES key and adds it to the keychain.
135-
pub fn decrypt_aes_key(
135+
pub(super) fn decrypt_aes_key(
136136
&mut self,
137137
envelope: &EncryptedEnvelope,
138138
) -> Result<(), OnePasswordError> {
@@ -229,7 +229,7 @@ fn encrypted_by(keyset: &KeysetInfo) -> &str {
229229
mod tests {
230230
use data_encoding::HEXLOWER;
231231

232-
use super::*;
232+
use super::{super::wire::KeysetsInfo, *};
233233

234234
fn hex(s: &str) -> Vec<u8> {
235235
HEXLOWER.decode(s.as_bytes()).expect("valid hex")

crates/bitwarden-importers/src/importers/onepassword/access/login.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,15 +29,15 @@ const AUTH_COMPLETE_ENDPOINT: &str = "v2/auth/complete";
2929

3030
/// The result of a single login attempt: a finished session, or a rejected OTP that asks for a full
3131
/// restart.
32-
pub enum LoginOutcome {
32+
pub(super) enum LoginOutcome {
3333
/// Authentication succeeded.
3434
Success(Box<Session>),
3535
/// The submitted TOTP code was rejected; the caller should retry from the start.
3636
BadOtp,
3737
}
3838

3939
/// Confirms the account offers a given auth method.
40-
pub async fn fetch_auth_methods(
40+
pub(super) async fn fetch_auth_methods(
4141
username: &str,
4242
rest: &RestClient,
4343
) -> Result<LoginInfo, OnePasswordError> {
@@ -47,7 +47,7 @@ pub async fn fetch_auth_methods(
4747

4848
/// Runs one full login sequence: start a session, exchange SRP, verify the key, and drive 2FA if
4949
/// the server asks for it.
50-
pub async fn login_attempt(
50+
pub(super) async fn login_attempt(
5151
credentials: &Credentials,
5252
account_key: &AccountKey,
5353
client_info: &ClientInfo,

crates/bitwarden-importers/src/importers/onepassword/access/mac.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,15 +13,15 @@ use super::{error::OnePasswordError, opdata::AesKey};
1313
const SESSION_HMAC_SECRET: &str = "He never wears a Mac, in the pouring rain. Very strange.";
1414

1515
/// Signs requests with the per-session MAC header, bumping the request id on each signature.
16-
pub struct MacSigner {
16+
pub(super) struct MacSigner {
1717
session_id: String,
1818
salt: [u8; 32],
1919
request_id: AtomicU32,
2020
}
2121

2222
impl MacSigner {
2323
/// Creates a signer from the session key, starting from a random request id.
24-
pub fn new(session_key: &AesKey) -> MacSigner {
24+
pub(super) fn new(session_key: &AesKey) -> MacSigner {
2525
Self::with_request_id(session_key, bitwarden_random::rng().next_u32())
2626
}
2727

@@ -36,7 +36,7 @@ impl MacSigner {
3636
/// Returns the `X-AgileBits-MAC` header value for a request and takes the next request id.
3737
///
3838
/// The id only has to differ between requests, so nothing needs ordering against other threads.
39-
pub fn sign(&self, url: &str, method: &str) -> Result<String, OnePasswordError> {
39+
pub(super) fn sign(&self, url: &str, method: &str) -> Result<String, OnePasswordError> {
4040
let id = self.request_id.fetch_add(1, Ordering::Relaxed);
4141

4242
let message = self.calculate_auth_message(url, method, id)?;

crates/bitwarden-importers/src/importers/onepassword/access/model.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ pub enum ItemCategory {
8686
impl ItemCategory {
8787
/// Maps a 1Password template id to a category. Extends the `TemplateId` handling in
8888
/// `Client.ConvertVaultItem` to the full standard template set.
89-
pub fn from_template_id(id: &str) -> ItemCategory {
89+
pub(super) fn from_template_id(id: &str) -> ItemCategory {
9090
match id {
9191
"001" => ItemCategory::Login,
9292
"002" => ItemCategory::CreditCard,

0 commit comments

Comments
 (0)