chore(core): fix pre-existing clippy warnings (-D warnings gate)

Resolves pre-existing lint issues in imgsecret.rs, time.rs, totp.rs,
and crypto.rs that blocked the cargo clippy --workspace -D warnings
gate. No logic changes: loop-index → iterator, manual div_ceil →
.div_ceil(), manual range contains → .contains(), auto-deref cleanup.

Also fixes pre-existing warnings in relicario-cli (main.rs, session.rs,
device.rs, gitea.rs, helpers.rs, test helpers): dead_code suppression,
too_many_arguments, literal_with_empty_format_string, manual_char_cmp,
map_or → is_none_or, and repeat().take() → vec! in test helpers.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
adlee-was-taken
2026-05-02 19:32:45 -04:00
parent 006e67c361
commit 4d02a50cc8
12 changed files with 46 additions and 38 deletions

View File

@@ -91,6 +91,7 @@ pub fn store_device_keys(
} }
/// Load the signing private key for a device. /// Load the signing private key for a device.
#[allow(dead_code)]
pub fn load_signing_key(name: &str) -> Result<Zeroizing<String>> { pub fn load_signing_key(name: &str) -> Result<Zeroizing<String>> {
let path = device_dir(name)?.join("signing.key"); let path = device_dir(name)?.join("signing.key");
let key = fs::read_to_string(&path) let key = fs::read_to_string(&path)
@@ -99,6 +100,7 @@ pub fn load_signing_key(name: &str) -> Result<Zeroizing<String>> {
} }
/// Load the deploy private key for a device. /// Load the deploy private key for a device.
#[allow(dead_code)]
pub fn load_deploy_key(name: &str) -> Result<Zeroizing<String>> { pub fn load_deploy_key(name: &str) -> Result<Zeroizing<String>> {
let path = device_dir(name)?.join("deploy.key"); let path = device_dir(name)?.join("deploy.key");
let key = fs::read_to_string(&path) let key = fs::read_to_string(&path)
@@ -115,6 +117,7 @@ pub fn load_gitea_key_id(name: &str) -> Result<u64> {
} }
/// Delete the local key directory for a device. /// Delete the local key directory for a device.
#[allow(dead_code)]
pub fn delete_device_keys(name: &str) -> Result<()> { pub fn delete_device_keys(name: &str) -> Result<()> {
let dir = device_dir(name)?; let dir = device_dir(name)?;
if dir.exists() { if dir.exists() {

View File

@@ -21,7 +21,9 @@ struct CreateKeyRequest<'a> {
#[derive(Debug, Deserialize)] #[derive(Debug, Deserialize)]
pub struct DeployKey { pub struct DeployKey {
pub id: u64, pub id: u64,
#[allow(dead_code)]
pub title: String, pub title: String,
#[allow(dead_code)]
pub key: String, pub key: String,
} }
@@ -89,6 +91,7 @@ impl GiteaClient {
} }
/// List all deploy keys. /// List all deploy keys.
#[allow(dead_code)]
pub fn list_deploy_keys(&self) -> Result<Vec<DeployKey>> { pub fn list_deploy_keys(&self) -> Result<Vec<DeployKey>> {
let url = format!( let url = format!(
"{}/repos/{}/{}/keys", "{}/repos/{}/{}/keys",

View File

@@ -34,6 +34,7 @@ pub fn vault_dir() -> Result<PathBuf> {
} }
/// Path to the `.relicario/` configuration directory within the vault. /// Path to the `.relicario/` configuration directory within the vault.
#[allow(dead_code)]
pub fn relicario_dir() -> Result<PathBuf> { pub fn relicario_dir() -> Result<PathBuf> {
Ok(vault_dir()?.join(".relicario")) Ok(vault_dir()?.join(".relicario"))
} }

View File

@@ -540,7 +540,7 @@ fn cmd_init(image: PathBuf, output: PathBuf) -> Result<()> {
}; };
let carrier = fs::read(&image) let carrier = fs::read(&image)
.with_context(|| format!("failed to read carrier image {}", image.display()))?; .with_context(|| format!("failed to read carrier image {}", image.display()))?;
let stego = imgsecret::embed(&carrier, &*image_secret)?; let stego = imgsecret::embed(&carrier, &image_secret)?;
fs::write(&output, &stego) fs::write(&output, &stego)
.with_context(|| format!("failed to write reference image {}", output.display()))?; .with_context(|| format!("failed to write reference image {}", output.display()))?;
@@ -550,7 +550,7 @@ fn cmd_init(image: PathBuf, output: PathBuf) -> Result<()> {
let params = KdfParams { argon2_m: 65536, argon2_t: 3, argon2_p: 4 }; let params = KdfParams { argon2_m: 65536, argon2_t: 3, argon2_p: 4 };
// Derive master key, then persist an empty Manifest + default VaultSettings. // Derive master key, then persist an empty Manifest + default VaultSettings.
let master_key = derive_master_key(passphrase.as_bytes(), &*image_secret, &salt, &params)?; let master_key = derive_master_key(passphrase.as_bytes(), &image_secret, &salt, &params)?;
fs::create_dir_all(&relicario_dir)?; fs::create_dir_all(&relicario_dir)?;
fs::create_dir_all(root.join("items"))?; fs::create_dir_all(root.join("items"))?;
@@ -645,6 +645,7 @@ fn cmd_add(kind: AddKind) -> Result<()> {
// (for attachment-cap settings + writing the encrypted blob alongside // (for attachment-cap settings + writing the encrypted blob alongside
// the item). // the item).
#[allow(clippy::too_many_arguments)]
fn build_login_item( fn build_login_item(
title: Option<String>, title: Option<String>,
username: Option<String>, username: Option<String>,
@@ -860,6 +861,7 @@ fn build_document_item(
Ok(item) Ok(item)
} }
#[allow(clippy::too_many_arguments)]
fn build_totp_item( fn build_totp_item(
title: Option<String>, title: Option<String>,
issuer: Option<String>, issuer: Option<String>,
@@ -924,7 +926,7 @@ fn prompt_optional(label: &str) -> Result<Option<String>> {
fn parse_month_year(s: &str) -> Result<relicario_core::MonthYear> { fn parse_month_year(s: &str) -> Result<relicario_core::MonthYear> {
// Accepts MM/YYYY or MM-YYYY or MM/YY. // Accepts MM/YYYY or MM-YYYY or MM/YY.
let (m_str, y_str) = s.split_once(|c: char| c == '/' || c == '-') let (m_str, y_str) = s.split_once(['/', '-'])
.ok_or_else(|| anyhow::anyhow!("expected MM/YYYY"))?; .ok_or_else(|| anyhow::anyhow!("expected MM/YYYY"))?;
let month: u8 = m_str.parse().context("invalid month")?; let month: u8 = m_str.parse().context("invalid month")?;
let year: u16 = if y_str.len() == 2 { let year: u16 = if y_str.len() == 2 {
@@ -998,12 +1000,12 @@ fn cmd_get(query: String, show: bool, copy: bool) -> Result<()> {
if let Some(u) = &l.url { println!("URL: {u}"); } if let Some(u) = &l.url { println!("URL: {u}"); }
if let Some(t) = &l.totp { if let Some(t) = &l.totp {
if show { if show {
println!("TOTP: {}", data_encoding::BASE32.encode(&*t.secret)); println!("TOTP: {}", data_encoding::BASE32.encode(&t.secret));
} else { } else {
println!("TOTP: **** (use --show to reveal)"); println!("TOTP: **** (use --show to reveal)");
} }
} }
if let Some(p) = &l.password { Some(p.clone()) } else { None } l.password.clone()
} }
ItemCore::SecureNote(n) => { ItemCore::SecureNote(n) => {
if show { println!("Body:\n{}", n.body.as_str()); } if show { println!("Body:\n{}", n.body.as_str()); }
@@ -1125,8 +1127,8 @@ fn cmd_list(
Some(t) => e.r#type == t, Some(t) => e.r#type == t,
None => true, None => true,
}) })
.filter(|e| group_filter.as_ref().map_or(true, |g| e.group.as_deref() == Some(g.as_str()))) .filter(|e| group_filter.as_ref().is_none_or(|g| e.group.as_deref() == Some(g.as_str())))
.filter(|e| tag_filter.as_ref().map_or(true, |t| e.tags.iter().any(|x| x == t))) .filter(|e| tag_filter.as_ref().is_none_or(|t| e.tags.iter().any(|x| x == t)))
.collect(); .collect();
entries.sort_by(|a, b| a.title.to_lowercase().cmp(&b.title.to_lowercase())); entries.sort_by(|a, b| a.title.to_lowercase().cmp(&b.title.to_lowercase()));
@@ -1135,7 +1137,7 @@ fn cmd_list(
return Ok(()); return Ok(());
} }
println!("{:<16} {:<14} {:<6} {}", "ID", "TYPE", "FAV", "TITLE"); println!("{:<16} {:<14} {:<6} TITLE", "ID", "TYPE", "FAV");
for e in entries { for e in entries {
let fav = if e.favorite { " *" } else { "" }; let fav = if e.favorite { " *" } else { "" };
println!("{:<16} {:<14} {:<6} {}", e.id.as_str(), format!("{:?}", e.r#type), fav, e.title); println!("{:<16} {:<14} {:<6} {}", e.id.as_str(), format!("{:?}", e.r#type), fav, e.title);
@@ -1973,7 +1975,7 @@ fn cmd_attachments(query: String) -> Result<()> {
let entry = resolve_query(&manifest, &query)?; let entry = resolve_query(&manifest, &query)?;
let item = vault.load_item(&entry.id)?; let item = vault.load_item(&entry.id)?;
if item.attachments.is_empty() { eprintln!("(no attachments)"); return Ok(()); } if item.attachments.is_empty() { eprintln!("(no attachments)"); return Ok(()); }
println!("{:<17} {:>12} {:<22} {}", "AID", "SIZE", "MIME", "FILENAME"); println!("{:<17} {:>12} {:<22} FILENAME", "AID", "SIZE", "MIME");
for a in &item.attachments { for a in &item.attachments {
println!("{:<17} {:>12} {:<22} {}", a.id.as_str(), a.size, a.mime_type, a.filename); println!("{:<17} {:>12} {:<22} {}", a.id.as_str(), a.size, a.mime_type, a.filename);
} }
@@ -2541,7 +2543,7 @@ fn cmd_device(action: DeviceAction) -> Result<()> {
return Ok(()); return Ok(());
} }
println!("{:<20} {:<20} {}", "NAME", "ADDED", "SIGNING KEY (prefix)"); println!("{:<20} {:<20} SIGNING KEY (prefix)", "NAME", "ADDED");
println!("{}", "-".repeat(72)); println!("{}", "-".repeat(72));
for d in &devices { for d in &devices {
let marker = if d.name == current { " *" } else { "" }; let marker = if d.name == current { " *" } else { "" };

View File

@@ -50,7 +50,7 @@ impl UnlockedVault {
let master_key = derive_master_key( let master_key = derive_master_key(
passphrase.as_bytes(), passphrase.as_bytes(),
&*image_secret, &image_secret,
&salt, &salt,
&params, &params,
)?; )?;

View File

@@ -68,7 +68,7 @@ fn detach_removes_attachment_and_blob() {
// Encrypted blob file is gone. // Encrypted blob file is gone.
let blob_path = v.path() let blob_path = v.path()
.join("attachments") .join("attachments")
.join(stdout.lines().nth(1).is_some().then_some("").unwrap_or("")); .join("");
let item_attach_dir = std::fs::read_dir(v.path().join("attachments")) let item_attach_dir = std::fs::read_dir(v.path().join("attachments"))
.unwrap().next().unwrap().unwrap().path(); .unwrap().next().unwrap().unwrap().path();
let blob = item_attach_dir.join(format!("{aid}.enc")); let blob = item_attach_dir.join(format!("{aid}.enc"));

View File

@@ -78,6 +78,7 @@ impl TestVault {
cmd.output().unwrap() cmd.output().unwrap()
} }
#[allow(dead_code)]
pub fn run_with_backup_pass(&self, args: &[&str], backup_pass: &str) -> std::process::Output { pub fn run_with_backup_pass(&self, args: &[&str], backup_pass: &str) -> std::process::Output {
let mut cmd = Command::cargo_bin("relicario").unwrap(); let mut cmd = Command::cargo_bin("relicario").unwrap();
cmd.current_dir(self.dir.path()) cmd.current_dir(self.dir.path())
@@ -91,6 +92,7 @@ impl TestVault {
cmd.output().unwrap() cmd.output().unwrap()
} }
#[allow(dead_code)]
pub fn run_with_input(&self, args: &[&str], extra: &[&str]) -> std::process::Output { pub fn run_with_input(&self, args: &[&str], extra: &[&str]) -> std::process::Output {
let mut cmd = Command::cargo_bin("relicario").unwrap(); let mut cmd = Command::cargo_bin("relicario").unwrap();
cmd.current_dir(self.dir.path()) cmd.current_dir(self.dir.path())

View File

@@ -408,7 +408,7 @@ mod tests {
blob.extend_from_slice(&[0u8; 16]); blob.extend_from_slice(&[0u8; 16]);
let key = Zeroizing::new([0u8; 32]); let key = Zeroizing::new([0u8; 32]);
let err = decrypt(&*key, &blob).expect_err("v1 blob should fail decrypt"); let err = decrypt(&key, &blob).expect_err("v1 blob should fail decrypt");
match err { match err {
RelicarioError::UnsupportedFormatVersion { found, expected } => { RelicarioError::UnsupportedFormatVersion { found, expected } => {
assert_eq!(found, 0x01); assert_eq!(found, 0x01);

View File

@@ -83,7 +83,7 @@ const BITS_PER_BLOCK: usize = 12; // EMBED_POSITIONS.len()
/// Number of 8x8 blocks needed to hold one complete copy of the 256-bit secret. /// Number of 8x8 blocks needed to hold one complete copy of the 256-bit secret.
/// ceil(256 / 12) = 22 blocks per copy. /// ceil(256 / 12) = 22 blocks per copy.
const BLOCKS_PER_COPY: usize = (SECRET_BITS + BITS_PER_BLOCK - 1) / BITS_PER_BLOCK; // 22 const BLOCKS_PER_COPY: usize = SECRET_BITS.div_ceil(BITS_PER_BLOCK); // 22
/// Mid-frequency DCT coefficient positions for embedding, specified as /// Mid-frequency DCT coefficient positions for embedding, specified as
/// (row, col) indices into the 8x8 DCT coefficient matrix. /// (row, col) indices into the 8x8 DCT coefficient matrix.
@@ -302,9 +302,9 @@ fn read_block_abs(y: &YChannel, px: usize, py: usize) -> Option<[[f64; 8]; 8]> {
return None; return None;
} }
let mut block = [[0.0f64; 8]; 8]; let mut block = [[0.0f64; 8]; 8];
for row in 0..8 { for (row, block_row) in block.iter_mut().enumerate() {
for col in 0..8 { for (col, cell) in block_row.iter_mut().enumerate() {
block[row][col] = y.get(px + col, py + row); *cell = y.get(px + col, py + row);
} }
} }
Some(block) Some(block)
@@ -323,9 +323,9 @@ fn read_block(y: &YChannel, bx: usize, by: usize, region: &EmbedRegion) -> [[f64
fn write_block(y: &mut YChannel, bx: usize, by: usize, region: &EmbedRegion, block: &[[f64; 8]; 8]) { fn write_block(y: &mut YChannel, bx: usize, by: usize, region: &EmbedRegion, block: &[[f64; 8]; 8]) {
let start_x = region.x_offset + bx * BLOCK_SIZE; let start_x = region.x_offset + bx * BLOCK_SIZE;
let start_y = region.y_offset + by * BLOCK_SIZE; let start_y = region.y_offset + by * BLOCK_SIZE;
for row in 0..8 { for (row, block_row) in block.iter().enumerate() {
for col in 0..8 { for (col, &cell) in block_row.iter().enumerate() {
y.set(start_x + col, start_y + row, block[row][col]); y.set(start_x + col, start_y + row, cell);
} }
} }
} }
@@ -349,17 +349,17 @@ fn write_block(y: &mut YChannel, bx: usize, by: usize, region: &EmbedRegion, blo
/// where c(0) = sqrt(1/8) and c(k) = sqrt(2/8) for k > 0. /// where c(0) = sqrt(1/8) and c(k) = sqrt(2/8) for k > 0.
fn dct1d(input: &[f64; 8]) -> [f64; 8] { fn dct1d(input: &[f64; 8]) -> [f64; 8] {
let mut output = [0.0f64; 8]; let mut output = [0.0f64; 8];
for k in 0..8 { for (k, out_k) in output.iter_mut().enumerate() {
let ck = if k == 0 { let ck = if k == 0 {
(1.0 / 8.0_f64).sqrt() (1.0 / 8.0_f64).sqrt()
} else { } else {
(2.0 / 8.0_f64).sqrt() (2.0 / 8.0_f64).sqrt()
}; };
let mut sum = 0.0; let mut sum = 0.0;
for i in 0..8 { for (i, &x) in input.iter().enumerate() {
sum += input[i] * ((2 * i + 1) as f64 * k as f64 * PI / 16.0).cos(); sum += x * ((2 * i + 1) as f64 * k as f64 * PI / 16.0).cos();
} }
output[k] = ck * sum; *out_k = ck * sum;
} }
output output
} }
@@ -370,17 +370,17 @@ fn dct1d(input: &[f64; 8]) -> [f64; 8] {
/// x[i] = sum_{k=0}^{7} c(k) * X[k] * cos((2i+1)*k*pi/16) /// x[i] = sum_{k=0}^{7} c(k) * X[k] * cos((2i+1)*k*pi/16)
fn idct1d(input: &[f64; 8]) -> [f64; 8] { fn idct1d(input: &[f64; 8]) -> [f64; 8] {
let mut output = [0.0f64; 8]; let mut output = [0.0f64; 8];
for i in 0..8 { for (i, out_i) in output.iter_mut().enumerate() {
let mut sum = 0.0; let mut sum = 0.0;
for k in 0..8 { for (k, &x) in input.iter().enumerate() {
let ck = if k == 0 { let ck = if k == 0 {
(1.0 / 8.0_f64).sqrt() (1.0 / 8.0_f64).sqrt()
} else { } else {
(2.0 / 8.0_f64).sqrt() (2.0 / 8.0_f64).sqrt()
}; };
sum += ck * input[k] * ((2 * i + 1) as f64 * k as f64 * PI / 16.0).cos(); sum += ck * x * ((2 * i + 1) as f64 * k as f64 * PI / 16.0).cos();
} }
output[i] = sum; *out_i = sum;
} }
output output
} }
@@ -501,7 +501,7 @@ fn bytes_to_bits(bytes: &[u8]) -> Vec<u8> {
/// ///
/// Pads the last byte with zeros if the bit count is not a multiple of 8. /// Pads the last byte with zeros if the bit count is not a multiple of 8.
fn bits_to_bytes(bits: &[u8]) -> Vec<u8> { fn bits_to_bytes(bits: &[u8]) -> Vec<u8> {
let mut bytes = Vec::with_capacity((bits.len() + 7) / 8); let mut bytes = Vec::with_capacity(bits.len().div_ceil(8));
for chunk in bits.chunks(8) { for chunk in bits.chunks(8) {
let mut byte = 0u8; let mut byte = 0u8;
for (i, &bit) in chunk.iter().enumerate() { for (i, &bit) in chunk.iter().enumerate() {

View File

@@ -52,18 +52,15 @@ pub enum TotpAlgorithm {
Sha512, Sha512,
} }
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Default)]
#[serde(rename_all = "snake_case")] #[serde(rename_all = "snake_case")]
pub enum TotpKind { pub enum TotpKind {
#[default]
Totp, Totp,
Hotp { counter: u64 }, Hotp { counter: u64 },
Steam, Steam,
} }
impl Default for TotpKind {
fn default() -> Self { TotpKind::Totp }
}
/// Compute a TOTP/Steam code for `config` at the given Unix timestamp. /// Compute a TOTP/Steam code for `config` at the given Unix timestamp.
/// ///
/// For TOTP and Steam: counter = `now_unix_seconds / period_seconds`. /// For TOTP and Steam: counter = `now_unix_seconds / period_seconds`.

View File

@@ -19,7 +19,7 @@ impl MonthYear {
if !(1..=12).contains(&month) { if !(1..=12).contains(&month) {
return Err("month must be 1..=12"); return Err("month must be 1..=12");
} }
if year < 2000 || year > 2099 { if !(2000..=2099).contains(&year) {
return Err("year must be 2000..=2099"); return Err("year must be 2000..=2099");
} }
Ok(Self { month, year }) Ok(Self { month, year })

View File

@@ -51,12 +51,12 @@ fn raw_tar_with_path(raw_path: &[u8], content: &[u8]) -> Vec<u8> {
// Pad to 512-byte boundary. // Pad to 512-byte boundary.
let remainder = content.len() % 512; let remainder = content.len() % 512;
if remainder != 0 { if remainder != 0 {
out.extend(std::iter::repeat(0u8).take(512 - remainder)); out.extend(vec![0u8; 512 - remainder]);
} }
} }
// Two zero blocks = end-of-archive. // Two zero blocks = end-of-archive.
out.extend(std::iter::repeat(0u8).take(1024)); out.extend(vec![0u8; 1024]);
out out
} }
@@ -92,7 +92,7 @@ fn raw_symlink_tar() -> Vec<u8> {
buf[148..156].copy_from_slice(cksum_str.as_bytes()); buf[148..156].copy_from_slice(cksum_str.as_bytes());
let mut out = buf; let mut out = buf;
out.extend(std::iter::repeat(0u8).take(1024)); // end-of-archive out.extend(vec![0u8; 1024]); // end-of-archive
out out
} }