db: allow explicitly skipping sensitive entries

Signed-off-by: NotAShelf <raf@notashelf.dev>
Change-Id: I6a6a6964ed1deaac0215ae9c6f4c70cfdc50164d
This commit is contained in:
raf 2025-08-14 17:01:43 +03:00
commit f3089148e0
Signed by: NotAShelf
GPG key ID: 29D95B64378DB4BF
3 changed files with 46 additions and 2 deletions

1
Cargo.lock generated
View file

@ -1115,6 +1115,7 @@ dependencies = [
"imagesize", "imagesize",
"inquire", "inquire",
"log", "log",
"regex",
"rmp-serde", "rmp-serde",
"rusqlite", "rusqlite",
"serde", "serde",

View file

@ -14,7 +14,9 @@ clap-verbosity-flag = "3.0.3"
dirs = "6.0.0" dirs = "6.0.0"
rmp-serde = "1.3.0" rmp-serde = "1.3.0"
imagesize = "0.14.0" imagesize = "0.14.0"
inquire = { default-features = false, version = "0.7.5", features = [ "crossterm" ] } inquire = { default-features = false, version = "0.7.5", features = [
"crossterm",
] }
log = "0.4.27" log = "0.4.27"
env_logger = "0.11.8" env_logger = "0.11.8"
thiserror = "2.0.14" thiserror = "2.0.14"
@ -24,6 +26,7 @@ smol = "2.0.2"
serde = { version = "1.0.219", features = ["derive"] } serde = { version = "1.0.219", features = ["derive"] }
serde_json = "1.0.142" serde_json = "1.0.142"
base64 = "0.22.1" base64 = "0.22.1"
regex = "1.11.1"
[profile.release] [profile.release]

View file

@ -1,9 +1,12 @@
use std::env;
use std::fmt; use std::fmt;
use std::fs;
use std::io::{BufRead, BufReader, Read, Write}; use std::io::{BufRead, BufReader, Read, Write};
use std::str; use std::str;
use imagesize::{ImageSize, ImageType}; use imagesize::{ImageSize, ImageType};
use log::{error, info}; use log::{error, info, warn};
use regex::Regex;
use rusqlite::{Connection, OptionalExtension, params}; use rusqlite::{Connection, OptionalExtension, params};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
@ -176,6 +179,18 @@ impl ClipboardDb for SqliteClipboardDb {
other => other, other => other,
}; };
// Try to load regex from systemd credential file, then env var
let regex = load_sensitive_regex();
if let Some(re) = regex {
// Only check text data
if let Ok(s) = std::str::from_utf8(&buf) {
if re.is_match(s) {
warn!("Clipboard entry matches sensitive regex, skipping store.");
return Err(StashError::Store("Filtered by sensitive regex".to_string()));
}
}
}
self.deduplicate(&buf, max_dedupe_search)?; self.deduplicate(&buf, max_dedupe_search)?;
self.conn self.conn
@ -375,6 +390,31 @@ impl ClipboardDb for SqliteClipboardDb {
} }
// Helper functions // Helper functions
/// Try to load a sensitive regex from systemd credential or env.
///
/// # Returns
/// `Some(Regex)` if present and valid, `None` otherwise.
fn load_sensitive_regex() -> Option<Regex> {
if let Ok(regex_path) = env::var("CREDENTIALS_DIRECTORY") {
let file = format!("{}/clipboard_filter", regex_path);
if let Ok(contents) = fs::read_to_string(&file) {
if let Ok(re) = Regex::new(contents.trim()) {
return Some(re);
}
}
}
// Fallback to an environment variable
if let Ok(pattern) = env::var("STASH_SENSITIVE_REGEX") {
if let Ok(re) = Regex::new(&pattern) {
return Some(re);
}
}
None
}
pub fn extract_id(input: &str) -> Result<u64, &'static str> { pub fn extract_id(input: &str) -> Result<u64, &'static str> {
let id_str = input.split('\t').next().unwrap_or(""); let id_str = input.split('\t').next().unwrap_or("");
id_str.parse().map_err(|_| "invalid id") id_str.parse().map_err(|_| "invalid id")