node/systemd: Fix reading credentials

In `cb57e6560fe7767e79b87473a11261fbb82ce84c` the loading of systemd
credentials was refactored. The idea was to only change the accepted IDs
slightly after switching from radicle.xyz to radicle.dev. Unfortunately,
this was done in a sloppy way. The two cases for passphrase and secret
actually differ in ways that was overlooked.

Rectify these mistakes and restore the old behavior:
 1. The logic to read the passphrase from the file that contains the
    credential is moved out of `load_credential` since it only applies
    to the passphrase, not the secret.
 2. The warnings printed are now generic, and will not mention the
    passphrase in case reading the path for the secret fails.
This commit is contained in:
Lorenz Leutgeb 2026-05-07 15:19:50 +02:00
parent 6b460c4429
commit 0a0e70b1d1
No known key found for this signature in database
1 changed files with 27 additions and 29 deletions

View File

@ -213,7 +213,7 @@ enum ExecutionError {
},
}
/// Loads a credential from systemd, if available.
/// Loads the path to a credential from systemd, if available.
///
/// The credential ID should only be given as a suffix, as this function will
/// try different prefixes for backwards compatibility reasons.
@ -222,44 +222,34 @@ enum ExecutionError {
/// for new credentials, while the prefix `xyz.radicle.node` is deprecated and
/// should be migrated away from. If it is used, a warning is logged.
#[cfg(all(feature = "systemd", target_os = "linux"))]
fn load_credential(id_suffix: &str) -> Option<String> {
fn load_credential(id_suffix: &str) -> Option<PathBuf> {
const INFIX_NODE: &str = ".radicle.node.";
const PREFIX_DEV: &str = "dev";
const PREFIX_XYZ: &str = "xyz";
let id_dev = format!("{}{}{}", PREFIX_DEV, INFIX_NODE, id_suffix);
let credential = match radicle_systemd::credential::path(&id_dev) {
Ok(option) => option,
match radicle_systemd::credential::path(&id_dev) {
Ok(option @ Some(_)) => return option,
Ok(None) => {
// Fall through and try `PREFIX_XYZ` for backwards compatibility.
}
Err(err) => {
log::warn!(target: "node", "Failed to obtain path of the passphrase file via systemd credential with '{id_dev}': {err}");
None
log::warn!(target: "node", "Failed to obtain of the systemd credential with ID '{id_dev}': {err}");
}
};
let credential = credential.or_else(|| {
let id_xyz = format!("{}{}{}", PREFIX_XYZ, INFIX_NODE, id_suffix);
match radicle_systemd::credential::path(&id_xyz) {
Ok(option) => {
log::warn!(target: "node", "Obtain path of the passphrase file via systemd credential with '{id_xyz}'. Using this credential ID is discouraged. Please change the ID to '{id_dev}'.");
option
},
Err(err) => {
log::warn!(target: "node", "Failed to obtain path of the passphrase file via systemd credential with '{id_xyz}': {err}");
None
}
let id_xyz = format!("{}{}{}", PREFIX_XYZ, INFIX_NODE, id_suffix);
match radicle_systemd::credential::path(&id_xyz) {
Ok(option) => {
log::warn!(target: "node", "Obtained path of the systemd credential with ID '{id_xyz}'. Using this credential ID is discouraged. Please change the ID to '{id_dev}'.");
option
}
});
credential.and_then(|ref path| {
match std::fs::read_to_string(path) {
Ok(passphrase) => Some(passphrase),
Err(err) => {
log::warn!(target: "node", "Failed to read passphrase from '{}': {err}", path.display());
None
}
Err(err) => {
log::warn!(target: "node", "Failed to obtain path of the systemd credential with ID '{id_xyz}': {err}");
None
}
})
}
}
fn execute(options: Options) -> Result<(), ExecutionError> {
@ -293,14 +283,22 @@ fn execute(options: Options) -> Result<(), ExecutionError> {
let passphrase = None;
#[cfg(all(feature = "systemd", target_os = "linux"))]
let passphrase = passphrase.or_else(|| load_credential("passphrase").map(|s| s.into()));
let passphrase = passphrase.or_else(|| load_credential("passphrase").and_then(|path| {
match std::fs::read_to_string(&path) {
Ok(passphrase) => Some(passphrase.into()),
Err(err) => {
log::warn!(target: "node", "Failed to read passphrase from '{}': {err}", path.display());
None
}
}
}));
let passphrase = passphrase.or_else(profile::env::passphrase);
let secret_path = options.secret;
#[cfg(all(feature = "systemd", target_os = "linux"))]
let secret_path = secret_path.or_else(|| load_credential("secret").map(PathBuf::from));
let secret_path = secret_path.or_else(|| load_credential("secret"));
let secret_path = secret_path
.or_else(|| config.node.secret.clone())