mirror of
https://github.com/storytold/figcraft.git
synced 2026-11-08 13:00:08 +00:00
fix(figcraft): write the recovery copy's online note owner-only
The .online note beside a recovery copy holds the secret the client resumes its identity with, but it was written with the default mode while the copy itself was created 0600. Both now go through one owner-only writer, which also narrows a note that already existed.
This commit is contained in:
@@ -217,7 +217,8 @@ impl Recovery {
|
||||
return false;
|
||||
}
|
||||
let _ = match online {
|
||||
Some(text) => std::fs::write(¬e, text),
|
||||
// The note holds the secret the client resumes with: owner-only, as the copy.
|
||||
Some(text) => write_private(¬e, text.as_bytes()),
|
||||
None => std::fs::remove_file(¬e),
|
||||
};
|
||||
true
|
||||
@@ -326,24 +327,29 @@ fn rejoin_online(file: &Path, s: &mut Session) -> Option<u64> {
|
||||
fn write_atomic(path: &Path, doc: &figcraft_engine::doc::Document, versions: &[Version], branches: &[Branch]) -> bool {
|
||||
let Ok(bytes) = figcraft_format::save_bytes_with_history(doc, None, versions, branches) else { return false };
|
||||
let tmp = path.with_extension("tmp");
|
||||
if write_private(&tmp, &bytes).is_err() {
|
||||
let _ = std::fs::remove_file(&tmp);
|
||||
return false;
|
||||
}
|
||||
std::fs::rename(&tmp, path).is_ok()
|
||||
}
|
||||
|
||||
/// Write `bytes` to `path`, created (or cut back) readable by its owner only on Unix.
|
||||
fn write_private(path: &Path, bytes: &[u8]) -> std::io::Result<()> {
|
||||
#[cfg(unix)]
|
||||
{
|
||||
use std::os::unix::fs::OpenOptionsExt;
|
||||
use std::os::unix::fs::{OpenOptionsExt, PermissionsExt};
|
||||
let mut opts = std::fs::OpenOptions::new();
|
||||
opts.write(true).create(true).truncate(true).mode(0o600);
|
||||
let Ok(mut f) = opts.open(&tmp) else { return false };
|
||||
if std::io::Write::write_all(&mut f, &bytes).is_err() {
|
||||
let _ = std::fs::remove_file(&tmp);
|
||||
return false;
|
||||
}
|
||||
let mut f = opts.open(path)?;
|
||||
// `mode` applies to a new file only: one that was there keeps its mode unless set.
|
||||
f.set_permissions(std::fs::Permissions::from_mode(0o600))?;
|
||||
std::io::Write::write_all(&mut f, bytes)
|
||||
}
|
||||
#[cfg(not(unix))]
|
||||
{
|
||||
if std::fs::write(&tmp, bytes).is_err() {
|
||||
return false;
|
||||
}
|
||||
std::fs::write(path, bytes)
|
||||
}
|
||||
std::fs::rename(&tmp, path).is_ok()
|
||||
}
|
||||
|
||||
/// [`recover_all`], for a start that keeps nothing waiting: how many documents came back as
|
||||
|
||||
Reference in New Issue
Block a user