Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
81 changes: 52 additions & 29 deletions src/keyfile.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@ use std::collections::HashMap;
use std::env;
use std::fs;
use std::io::{Read, Write};
#[cfg(unix)]
use std::os::unix::fs::PermissionsExt;
// No extra imports needed for Windows
use std::path::PathBuf;
use std::str::from_utf8;

Expand Down Expand Up @@ -549,16 +551,23 @@ impl Keyfile {
return Ok(false);
}

// get file metadata
let metadata = fs::metadata(&self._path).map_err(|e| {
KeyFileError::MetadataError(format!("Failed to get metadata for file: {}.", e))
})?;

// check permissions
let permissions = metadata.permissions();
let readable = permissions.mode() & 0o444 != 0; // check readability

Ok(readable)
#[cfg(unix)]
{
let metadata = fs::metadata(&self._path).map_err(|e| {
KeyFileError::MetadataError(format!("Failed to get metadata for file: {}.", e))
})?;
let permissions = metadata.permissions();
let readable = permissions.mode() & 0o444 != 0; // check readability
Ok(readable)
}
#[cfg(windows)]
{
// On Windows, check if the file is readable by trying to open it for reading
match fs::File::open(&self._path) {
Ok(_) => Ok(true),
Err(_) => Ok(false),
}
}
}

/// Returns ``True`` if the file under path is writable.
Expand All @@ -568,16 +577,23 @@ impl Keyfile {
return Ok(false);
}

// get file metadata
let metadata = fs::metadata(&self._path).map_err(|e| {
KeyFileError::MetadataError(format!("Failed to get metadata for file: {}", e))
})?;

// check the permissions
let permissions = metadata.permissions();
let writable = permissions.mode() & 0o222 != 0; // check if file is writable

Ok(writable)
#[cfg(unix)]
{
let metadata = fs::metadata(&self._path).map_err(|e| {
KeyFileError::MetadataError(format!("Failed to get metadata for file: {}", e))
})?;
let permissions = metadata.permissions();
let writable = permissions.mode() & 0o222 != 0; // check if file is writable
Ok(writable)
}
#[cfg(windows)]
{
// On Windows, check if the file is writable by trying to open it for writing
match fs::OpenOptions::new().write(true).open(&self._path) {
Ok(_) => Ok(true),
Err(_) => Ok(false),
}
}
}

/// Returns ``True`` if the file under path is encrypted.
Expand Down Expand Up @@ -881,15 +897,22 @@ impl Keyfile {
.map_err(|e| KeyFileError::FileWrite(format!("Failed to write to file: {}.", e)))?;

// set permissions
let mut permissions = fs::metadata(&self._path)
.map_err(|e| {
KeyFileError::MetadataError(format!("Failed to get metadata for file: {}.", e))
})?
.permissions();
permissions.set_mode(0o600); // just for owner
fs::set_permissions(&self._path, permissions).map_err(|e| {
KeyFileError::PermissionError(format!("Failed to set permissions: {}.", e))
})?;
#[cfg(unix)]
{
let mut permissions = fs::metadata(&self._path)
.map_err(|e| {
KeyFileError::MetadataError(format!("Failed to get metadata for file: {}.", e))
})?
.permissions();
permissions.set_mode(0o600); // just for owner
fs::set_permissions(&self._path, permissions).map_err(|e| {
KeyFileError::PermissionError(format!("Failed to set permissions: {}.", e))
})?;
}
#[cfg(windows)]
{
// On Windows, do nothing for now (permissions are handled differently)
}
Ok(())
}

Expand Down
13 changes: 8 additions & 5 deletions src/python_bindings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ impl PyKeyfile {
}

#[getter(data)]
fn data_py(&self) -> PyResult<Option<Cow<[u8]>>> {
fn data_py(&self) -> PyResult<Option<Cow<'_, [u8]>>> {
self.inner
.data()
.map(|vec| Some(Cow::Owned(vec)))
Expand Down Expand Up @@ -266,7 +266,7 @@ impl PyKeypair {
}

#[pyo3(signature = (data))]
fn sign(&self, data: Py<PyAny>, py: Python) -> PyResult<Cow<[u8]>> {
fn sign(&self, data: Py<PyAny>, py: Python) -> PyResult<Cow<'_, [u8]>> {
// Convert data to bytes (data can be a string, hex, or bytes)
let data_bound = data.bind(py);
let data_bytes = if let Ok(s) = data_bound.extract::<String>() {
Expand Down Expand Up @@ -348,7 +348,7 @@ impl PyKeypair {
}

#[getter]
fn public_key(&self) -> PyResult<Option<Cow<[u8]>>> {
fn public_key(&self) -> PyResult<Option<Cow<'_, [u8]>>> {
self.inner
.public_key()
.map(|opt| opt.map(Cow::from))
Expand Down Expand Up @@ -555,7 +555,10 @@ fn py_get_password_from_environment(env_var_name: String) -> PyResult<Option<Str

#[pyfunction(name = "encrypt_keyfile_data")]
#[pyo3(signature = (keyfile_data, password=None))]
fn py_encrypt_keyfile_data(keyfile_data: &[u8], password: Option<String>) -> PyResult<Cow<[u8]>> {
fn py_encrypt_keyfile_data(
keyfile_data: &[u8],
password: Option<String>,
) -> PyResult<Cow<'_, [u8]>> {
keyfile::encrypt_keyfile_data(keyfile_data, password)
.map(Cow::from)
.map_err(|e| PyErr::new::<PyKeyFileError, _>(e))
Expand All @@ -567,7 +570,7 @@ fn py_decrypt_keyfile_data(
keyfile_data: &[u8],
password: Option<String>,
password_env_var: Option<String>,
) -> PyResult<Cow<[u8]>> {
) -> PyResult<Cow<'_, [u8]>> {
keyfile::decrypt_keyfile_data(keyfile_data, password, password_env_var)
.map(Cow::from)
.map_err(|e| PyErr::new::<PyKeyFileError, _>(e))
Expand Down