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:
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
pub mod client;
|
||||
|
||||
pub use client::ApiClient;
|
||||
pub use client::ApiClient;
|
||||
|
||||
@@ -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,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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>>,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1 +1 @@
|
||||
pub const VERSION: &str = env!("CARGO_PKG_VERSION");
|
||||
pub const VERSION: &str = env!("CARGO_PKG_VERSION");
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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};
|
||||
|
||||
@@ -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(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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>,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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>;
|
||||
|
||||
@@ -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,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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};
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1 +1 @@
|
||||
// TODO: Implement sync functionality
|
||||
// TODO: Implement sync functionality
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user