breadclip: privacy hardening + event-driven daemon
- history.db and images/*.png are now created with 0600 permissions (owner-only) instead of default umask, since clipboard history can contain plaintext passwords/tokens. - breadclipd never persists clipboard content flagged with the x-kde-passwordManagerHint MIME type (the convention KeePassXC, Bitwarden, etc. use to mark content they own). - Replaced breadclipd's 500ms busy-poll loop (2-3 wl-paste forks per cycle, forever) with wl-paste --watch, so it only reacts on actual clipboard changes. - Documented both behaviors in the README.
This commit is contained in:
parent
86ebe5d050
commit
8097d1944c
3 changed files with 108 additions and 33 deletions
|
|
@ -1,6 +1,7 @@
|
|||
use rusqlite::{params, Connection, Result as SqlResult};
|
||||
use sha2::{Digest, Sha256};
|
||||
use std::path::PathBuf;
|
||||
use std::os::unix::fs::PermissionsExt;
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct ClipEntry {
|
||||
|
|
@ -20,7 +21,8 @@ impl HistoryDb {
|
|||
pub fn open() -> SqlResult<Self> {
|
||||
let dir = data_dir();
|
||||
std::fs::create_dir_all(&dir).ok();
|
||||
let conn = Connection::open(dir.join("history.db"))?;
|
||||
let db_path = dir.join("history.db");
|
||||
let conn = Connection::open(&db_path)?;
|
||||
conn.execute_batch(
|
||||
"CREATE TABLE IF NOT EXISTS history (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
|
|
@ -32,6 +34,9 @@ impl HistoryDb {
|
|||
);
|
||||
CREATE INDEX IF NOT EXISTS history_ts ON history(timestamp DESC);",
|
||||
)?;
|
||||
// history.db can contain plaintext secrets copied to the clipboard
|
||||
// (passwords, tokens, TOTP codes); restrict it to owner-only, every open.
|
||||
restrict_permissions(&db_path);
|
||||
Ok(Self { conn })
|
||||
}
|
||||
|
||||
|
|
@ -55,6 +60,7 @@ impl HistoryDb {
|
|||
let path = images_dir.join(format!("{}.png", &hash[..16]));
|
||||
if !path.exists() {
|
||||
std::fs::write(&path, png_bytes).ok();
|
||||
restrict_permissions(&path);
|
||||
}
|
||||
let path_str = path.to_string_lossy().to_string();
|
||||
let ts = unix_now();
|
||||
|
|
@ -145,6 +151,17 @@ impl HistoryDb {
|
|||
}
|
||||
}
|
||||
|
||||
/// Restrict a file to owner-only read/write (0600). Clipboard history can
|
||||
/// contain passwords and other secrets, so this must not be world/group
|
||||
/// readable regardless of the process umask.
|
||||
fn restrict_permissions(path: &Path) {
|
||||
if let Ok(meta) = std::fs::metadata(path) {
|
||||
let mut perms = meta.permissions();
|
||||
perms.set_mode(0o600);
|
||||
let _ = std::fs::set_permissions(path, perms);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn sha256_hex(data: &[u8]) -> String {
|
||||
let mut hasher = Sha256::new();
|
||||
hasher.update(data);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue