fix(rust): Address cargo fmt and clippy warnings

- Fix code formatting with cargo fmt
- Remove unnecessary type casts
- Use range contains instead of manual comparison
- Prefix unused variables with underscore
- Remove unused imports
- Add allow(dead_code) for development phase

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Manav Rathi
2025-08-21 12:24:04 +05:30
parent b845f4d893
commit ea843eba7a
20 changed files with 108 additions and 90 deletions

View File

@@ -1,5 +1,7 @@
use crate::{Error, Result};
use reqwest::{Client, Response};
#![allow(dead_code)]
use crate::Result;
use reqwest::Client;
use std::time::Duration;
const ENTE_API_ENDPOINT: &str = "https://api.ente.io";
@@ -13,15 +15,13 @@ pub struct ApiClient {
impl ApiClient {
pub fn new(base_url: Option<String>) -> Result<Self> {
let client = Client::builder()
.timeout(Duration::from_secs(30))
.build()?;
let client = Client::builder().timeout(Duration::from_secs(30)).build()?;
Ok(Self {
client,
base_url: base_url.unwrap_or_else(|| ENTE_API_ENDPOINT.to_string()),
})
}
// TODO: Implement API methods
}
}

View File

@@ -1,3 +1,3 @@
pub mod client;
pub use client::ApiClient;
pub use client::ApiClient;

View File

@@ -10,33 +10,33 @@ pub struct AccountCommand {
pub enum AccountSubcommands {
/// List configured accounts
List,
/// Login into existing account
Add,
/// Update an existing account's export directory
Update {
/// Email address of the account
#[arg(long)]
email: String,
/// Export directory path
#[arg(long)]
dir: String,
/// Specify the app (photos, locker, auth)
#[arg(long, default_value = "photos")]
app: String,
},
/// Get token for an account for a specific app
GetToken {
/// Email address of the account
#[arg(long)]
email: String,
/// Specify the app (photos, locker, auth)
#[arg(long, default_value = "photos")]
app: String,
},
}
}

View File

@@ -5,16 +5,16 @@ pub struct ExportCommand {
/// Include shared albums (pass --shared=false to exclude)
#[arg(long, default_value = "true")]
pub shared: bool,
/// Include hidden albums (pass --hidden=false to exclude)
#[arg(long, default_value = "true")]
pub hidden: bool,
/// Comma-separated list of album names to export
#[arg(long, value_delimiter = ',')]
pub albums: Option<Vec<String>>,
/// Comma-separated list of emails to export files shared with
#[arg(long, value_delimiter = ',')]
pub emails: Option<Vec<String>>,
}
}

View File

@@ -16,10 +16,10 @@ pub struct Cli {
pub enum Commands {
/// Manage account settings
Account(account::AccountCommand),
/// Export photos and files
Export(export::ExportCommand),
/// Print version information
Version,
}
}

View File

@@ -1 +1 @@
pub const VERSION: &str = env!("CARGO_PKG_VERSION");
pub const VERSION: &str = env!("CARGO_PKG_VERSION");

View File

@@ -3,14 +3,21 @@ use libsodium_sys as sodium;
/// Derive a key using Argon2id algorithm
/// This matches the Go implementation using libsodium
pub fn derive_argon_key(password: &str, salt: &str, mem_limit: u32, ops_limit: u32) -> Result<Vec<u8>> {
pub fn derive_argon_key(
password: &str,
salt: &str,
mem_limit: u32,
ops_limit: u32,
) -> Result<Vec<u8>> {
if mem_limit < 1024 || ops_limit < 1 {
return Err(Error::InvalidInput("Invalid memory or operation limits".into()));
return Err(Error::InvalidInput(
"Invalid memory or operation limits".into(),
));
}
// Decode salt from base64
let salt_bytes = super::decode_base64(salt)?;
// libsodium requires salt to be exactly crypto_pwhash_SALTBYTES
if salt_bytes.len() != sodium::crypto_pwhash_SALTBYTES as usize {
return Err(Error::Crypto(format!(
@@ -21,16 +28,16 @@ pub fn derive_argon_key(password: &str, salt: &str, mem_limit: u32, ops_limit: u
}
let mut key = vec![0u8; 32]; // 32 bytes output
let result = unsafe {
sodium::crypto_pwhash(
key.as_mut_ptr(),
key.len() as u64,
password.as_ptr() as *const u8,
password.as_ptr(),
password.len() as u64,
salt_bytes.as_ptr() as *const u8,
salt_bytes.as_ptr(),
ops_limit as u64,
(mem_limit as usize * 1024) as usize, // Convert from KB to bytes
mem_limit as usize * 1024, // Convert from KB to bytes
sodium::crypto_pwhash_ALG_ARGON2ID13 as i32,
)
};
@@ -40,4 +47,4 @@ pub fn derive_argon_key(password: &str, salt: &str, mem_limit: u32, ops_limit: u
}
Ok(key)
}
}

View File

@@ -19,7 +19,8 @@ pub fn decrypt_chacha(ciphertext: &[u8], nonce: &[u8], key: &[u8]) -> Result<Vec
)));
}
let mut plaintext = vec![0u8; ciphertext.len() - sodium::crypto_aead_xchacha20poly1305_ietf_ABYTES as usize];
let mut plaintext =
vec![0u8; ciphertext.len() - sodium::crypto_aead_xchacha20poly1305_ietf_ABYTES as usize];
let mut plaintext_len: u64 = 0;
let result = unsafe {
@@ -37,7 +38,9 @@ pub fn decrypt_chacha(ciphertext: &[u8], nonce: &[u8], key: &[u8]) -> Result<Vec
};
if result != 0 {
return Err(Error::Crypto("Failed to decrypt with ChaCha20-Poly1305".into()));
return Err(Error::Crypto(
"Failed to decrypt with ChaCha20-Poly1305".into(),
));
}
plaintext.truncate(plaintext_len as usize);
@@ -62,7 +65,8 @@ pub fn encrypt_chacha(plaintext: &[u8], nonce: &[u8], key: &[u8]) -> Result<Vec<
)));
}
let mut ciphertext = vec![0u8; plaintext.len() + sodium::crypto_aead_xchacha20poly1305_ietf_ABYTES as usize];
let mut ciphertext =
vec![0u8; plaintext.len() + sodium::crypto_aead_xchacha20poly1305_ietf_ABYTES as usize];
let mut ciphertext_len: u64 = 0;
let result = unsafe {
@@ -80,7 +84,9 @@ pub fn encrypt_chacha(plaintext: &[u8], nonce: &[u8], key: &[u8]) -> Result<Vec<
};
if result != 0 {
return Err(Error::Crypto("Failed to encrypt with ChaCha20-Poly1305".into()));
return Err(Error::Crypto(
"Failed to encrypt with ChaCha20-Poly1305".into(),
));
}
ciphertext.truncate(ciphertext_len as usize);
@@ -159,4 +165,4 @@ pub fn secret_box_seal(plaintext: &[u8], nonce: &[u8], key: &[u8]) -> Result<Vec
}
Ok(ciphertext)
}
}

View File

@@ -14,7 +14,7 @@ pub fn derive_login_key(key_enc_key: &[u8]) -> Result<Vec<u8>> {
LOGIN_SUB_KEY_ID,
LOGIN_SUB_KEY_LEN,
)?;
// Return the first 16 bytes of the derived key
Ok(sub_key[..16].to_vec())
}
@@ -28,8 +28,8 @@ fn derive_sub_key(
) -> Result<Vec<u8>> {
const CRYPTO_KDF_BLAKE2B_BYTES_MIN: usize = 16;
const CRYPTO_KDF_BLAKE2B_BYTES_MAX: usize = 64;
if sub_key_length < CRYPTO_KDF_BLAKE2B_BYTES_MIN || sub_key_length > CRYPTO_KDF_BLAKE2B_BYTES_MAX {
if !(CRYPTO_KDF_BLAKE2B_BYTES_MIN..=CRYPTO_KDF_BLAKE2B_BYTES_MAX).contains(&sub_key_length) {
return Err(Error::Crypto("subKeyLength out of bounds".into()));
}
@@ -45,14 +45,11 @@ fn derive_sub_key(
// Create output buffer
let mut out = vec![0u8; sub_key_length];
// Initialize Blake2b state with salt and personalization
let mut state = std::mem::MaybeUninit::<sodium::crypto_generichash_blake2b_state>::uninit();
let result = unsafe {
sodium::crypto_generichash_blake2b_salt_personal(
out.as_mut_ptr(),
sub_key_length,
std::ptr::null(), // No input data, just using key, salt, and personalization
std::ptr::null(), // No input data, just using key, salt, and personalization
0,
master_key.as_ptr(),
master_key.len(),
@@ -66,4 +63,4 @@ fn derive_sub_key(
}
Ok(out)
}
}

View File

@@ -1,8 +1,7 @@
use crate::Result;
use base64::{engine::general_purpose::STANDARD as BASE64, Engine};
use base64::{Engine, engine::general_purpose::STANDARD as BASE64};
use libsodium_sys as sodium;
use std::sync::Once;
use zeroize::Zeroize;
mod argon;
mod chacha;
@@ -16,11 +15,9 @@ static INIT: Once = Once::new();
/// Initialize libsodium. Must be called before any crypto operations.
pub fn init() -> Result<()> {
INIT.call_once(|| {
unsafe {
if sodium::sodium_init() < 0 {
panic!("Failed to initialize libsodium");
}
INIT.call_once(|| unsafe {
if sodium::sodium_init() < 0 {
panic!("Failed to initialize libsodium");
}
});
Ok(())
@@ -34,4 +31,4 @@ pub fn decode_base64(input: &str) -> Result<Vec<u8>> {
/// Encode bytes to base64 string
pub fn encode_base64(input: &[u8]) -> String {
BASE64.encode(input)
}
}

View File

@@ -6,4 +6,4 @@ pub mod storage;
pub mod sync;
pub mod utils;
pub use models::error::{Error, Result};
pub use models::error::{Error, Result};

View File

@@ -1,31 +1,34 @@
use clap::Parser;
use ente_rs::{cli::{Cli, Commands}, Result};
use ente_rs::{
Result,
cli::{Cli, Commands},
};
#[tokio::main]
async fn main() -> Result<()> {
// Initialize logger
env_logger::init();
// Initialize libsodium
ente_rs::crypto::init()?;
// Parse CLI arguments
let cli = Cli::parse();
// Handle commands
match cli.command {
Commands::Version => {
println!("ente-rs version {}", ente_rs::cli::version::VERSION);
}
Commands::Account(account_cmd) => {
Commands::Account(_account_cmd) => {
// TODO: Implement account commands
println!("Account command not yet implemented");
}
Commands::Export(export_cmd) => {
Commands::Export(_export_cmd) => {
// TODO: Implement export command
println!("Export command not yet implemented");
}
}
Ok(())
}
}

View File

@@ -1,3 +1,5 @@
#![allow(dead_code)]
use serde::{Deserialize, Serialize};
use uuid::Uuid;
use zeroize::Zeroize;
@@ -88,4 +90,4 @@ pub struct AuthResponse {
pub encrypted_token: Option<String>,
#[serde(rename = "keyAttributes")]
pub key_attributes: Option<KeyAttributes>,
}
}

View File

@@ -1,3 +1,5 @@
#![allow(dead_code)]
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize, Deserialize)]
@@ -51,4 +53,4 @@ pub struct PublicURL {
pub device_limit: i32,
#[serde(rename = "validTill")]
pub valid_till: i64,
}
}

View File

@@ -4,39 +4,39 @@ use thiserror::Error;
pub enum Error {
#[error("IO error: {0}")]
Io(#[from] std::io::Error),
#[error("Network error: {0}")]
Network(#[from] reqwest::Error),
#[error("Serialization error: {0}")]
Serialization(#[from] serde_json::Error),
#[error("Database error: {0}")]
Database(#[from] sled::Error),
#[error("Crypto error: {0}")]
Crypto(String),
#[error("Authentication failed: {0}")]
AuthenticationFailed(String),
#[error("Invalid configuration: {0}")]
InvalidConfig(String),
#[error("Not found: {0}")]
NotFound(String),
#[error("Invalid input: {0}")]
InvalidInput(String),
#[error("SRP error: {0}")]
Srp(String),
#[error("Base64 decode error: {0}")]
Base64Decode(#[from] base64::DecodeError),
#[error("{0}")]
Generic(String),
}
pub type Result<T> = std::result::Result<T, Error>;
pub type Result<T> = std::result::Result<T, Error>;

View File

@@ -1,3 +1,5 @@
#![allow(dead_code)]
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize, Deserialize)]
@@ -45,4 +47,4 @@ pub enum FileType {
Video,
LivePhoto,
Other,
}
}

View File

@@ -1,6 +1,6 @@
pub mod error;
pub mod account;
pub mod file;
pub mod collection;
pub mod error;
pub mod file;
pub use error::{Error, Result};
pub use error::{Error, Result};

View File

@@ -1,3 +1,5 @@
#![allow(dead_code)]
use crate::Result;
use sled::Db;
use std::path::Path;
@@ -11,6 +13,6 @@ impl Storage {
let db = sled::open(path)?;
Ok(Self { db })
}
// TODO: Implement storage methods
}
}

View File

@@ -1 +1 @@
// TODO: Implement sync functionality
// TODO: Implement sync functionality

View File

@@ -1,5 +1,5 @@
use std::path::PathBuf;
use dirs;
use std::path::PathBuf;
/// Get the CLI configuration directory
pub fn get_cli_config_dir() -> crate::Result<PathBuf> {
@@ -7,22 +7,22 @@ pub fn get_cli_config_dir() -> crate::Result<PathBuf> {
if let Ok(config_dir) = std::env::var("ENTE_CLI_CONFIG_DIR") {
return Ok(PathBuf::from(config_dir));
}
// For backward compatibility
if let Ok(config_dir) = std::env::var("ENTE_CLI_CONFIG_PATH") {
return Ok(PathBuf::from(config_dir));
}
// Default to ~/.ente
let home_dir = dirs::home_dir()
.ok_or_else(|| crate::Error::Generic("Could not determine home directory".into()))?;
let cli_path = home_dir.join(".ente");
// Create directory if it doesn't exist
if !cli_path.exists() {
std::fs::create_dir_all(&cli_path)?;
}
Ok(cli_path)
}
}