phase 6
This commit is contained in:
Generated
+220
@@ -160,6 +160,12 @@ version = "1.5.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8"
|
checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "base16ct"
|
||||||
|
version = "0.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "base64"
|
name = "base64"
|
||||||
version = "0.21.7"
|
version = "0.21.7"
|
||||||
@@ -367,6 +373,18 @@ dependencies = [
|
|||||||
"cfg-if",
|
"cfg-if",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "crypto-bigint"
|
||||||
|
version = "0.5.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76"
|
||||||
|
dependencies = [
|
||||||
|
"generic-array",
|
||||||
|
"rand_core",
|
||||||
|
"subtle",
|
||||||
|
"zeroize",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "crypto-common"
|
name = "crypto-common"
|
||||||
version = "0.1.7"
|
version = "0.1.7"
|
||||||
@@ -396,6 +414,7 @@ dependencies = [
|
|||||||
"cfg-if",
|
"cfg-if",
|
||||||
"cpufeatures",
|
"cpufeatures",
|
||||||
"curve25519-dalek-derive",
|
"curve25519-dalek-derive",
|
||||||
|
"digest",
|
||||||
"fiat-crypto",
|
"fiat-crypto",
|
||||||
"rustc_version",
|
"rustc_version",
|
||||||
"subtle",
|
"subtle",
|
||||||
@@ -453,9 +472,65 @@ dependencies = [
|
|||||||
"age",
|
"age",
|
||||||
"clap",
|
"clap",
|
||||||
"flate2",
|
"flate2",
|
||||||
|
"rand",
|
||||||
|
"ssh-key",
|
||||||
"tar",
|
"tar",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ecdsa"
|
||||||
|
version = "0.16.9"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ee27f32b5c5292967d2d4a9d7f1e0b0aed2c15daded5a60300e4abb9d8020bca"
|
||||||
|
dependencies = [
|
||||||
|
"der",
|
||||||
|
"digest",
|
||||||
|
"elliptic-curve",
|
||||||
|
"rfc6979",
|
||||||
|
"signature",
|
||||||
|
"spki",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ed25519"
|
||||||
|
version = "2.2.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "115531babc129696a58c64a4fef0a8bf9e9698629fb97e9e40767d235cfbcd53"
|
||||||
|
dependencies = [
|
||||||
|
"signature",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ed25519-dalek"
|
||||||
|
version = "2.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "70e796c081cee67dc755e1a36a0a172b897fab85fc3f6bc48307991f64e4eca9"
|
||||||
|
dependencies = [
|
||||||
|
"curve25519-dalek",
|
||||||
|
"ed25519",
|
||||||
|
"sha2",
|
||||||
|
"subtle",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "elliptic-curve"
|
||||||
|
version = "0.13.8"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b5e6043086bf7973472e0c7dff2142ea0b680d30e18d9cc40f267efbf222bd47"
|
||||||
|
dependencies = [
|
||||||
|
"base16ct",
|
||||||
|
"crypto-bigint",
|
||||||
|
"digest",
|
||||||
|
"ff",
|
||||||
|
"generic-array",
|
||||||
|
"group",
|
||||||
|
"pkcs8",
|
||||||
|
"rand_core",
|
||||||
|
"sec1",
|
||||||
|
"subtle",
|
||||||
|
"zeroize",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "errno"
|
name = "errno"
|
||||||
version = "0.3.14"
|
version = "0.3.14"
|
||||||
@@ -466,6 +541,16 @@ dependencies = [
|
|||||||
"windows-sys",
|
"windows-sys",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ff"
|
||||||
|
version = "0.13.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c0b50bfb653653f9ca9095b427bed08ab8d75a137839d9ad64eb11810d5b6393"
|
||||||
|
dependencies = [
|
||||||
|
"rand_core",
|
||||||
|
"subtle",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "fiat-crypto"
|
name = "fiat-crypto"
|
||||||
version = "0.2.9"
|
version = "0.2.9"
|
||||||
@@ -641,6 +726,7 @@ checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"typenum",
|
"typenum",
|
||||||
"version_check",
|
"version_check",
|
||||||
|
"zeroize",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -664,6 +750,17 @@ dependencies = [
|
|||||||
"polyval",
|
"polyval",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "group"
|
||||||
|
version = "0.13.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63"
|
||||||
|
dependencies = [
|
||||||
|
"ff",
|
||||||
|
"rand_core",
|
||||||
|
"subtle",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "heck"
|
name = "heck"
|
||||||
version = "0.5.0"
|
version = "0.5.0"
|
||||||
@@ -927,6 +1024,44 @@ version = "0.3.1"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381"
|
checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "p256"
|
||||||
|
version = "0.13.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c9863ad85fa8f4460f9c48cb909d38a0d689dba1f6f6988a5e3e0d31071bcd4b"
|
||||||
|
dependencies = [
|
||||||
|
"ecdsa",
|
||||||
|
"elliptic-curve",
|
||||||
|
"primeorder",
|
||||||
|
"sha2",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "p384"
|
||||||
|
version = "0.13.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "fe42f1670a52a47d448f14b6a5c61dd78fce51856e68edaa38f7ae3a46b8d6b6"
|
||||||
|
dependencies = [
|
||||||
|
"ecdsa",
|
||||||
|
"elliptic-curve",
|
||||||
|
"primeorder",
|
||||||
|
"sha2",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "p521"
|
||||||
|
version = "0.13.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0fc9e2161f1f215afdfce23677034ae137bbd45016a880c2eb3ba8eb95f085b2"
|
||||||
|
dependencies = [
|
||||||
|
"base16ct",
|
||||||
|
"ecdsa",
|
||||||
|
"elliptic-curve",
|
||||||
|
"primeorder",
|
||||||
|
"rand_core",
|
||||||
|
"sha2",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "parking_lot"
|
name = "parking_lot"
|
||||||
version = "0.12.5"
|
version = "0.12.5"
|
||||||
@@ -960,6 +1095,15 @@ dependencies = [
|
|||||||
"hmac",
|
"hmac",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pem-rfc7468"
|
||||||
|
version = "0.7.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "88b39c9bfcfc231068454382784bb460aae594343fb030d46e9f50a645418412"
|
||||||
|
dependencies = [
|
||||||
|
"base64ct",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pin-project"
|
name = "pin-project"
|
||||||
version = "1.1.12"
|
version = "1.1.12"
|
||||||
@@ -1039,6 +1183,15 @@ dependencies = [
|
|||||||
"zerocopy",
|
"zerocopy",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "primeorder"
|
||||||
|
version = "0.13.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "353e1ca18966c16d9deb1c69278edbc5f194139612772bd9537af60ac231e1e6"
|
||||||
|
dependencies = [
|
||||||
|
"elliptic-curve",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "proc-macro-error-attr2"
|
name = "proc-macro-error-attr2"
|
||||||
version = "2.0.0"
|
version = "2.0.0"
|
||||||
@@ -1118,6 +1271,16 @@ dependencies = [
|
|||||||
"bitflags",
|
"bitflags",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rfc6979"
|
||||||
|
version = "0.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2"
|
||||||
|
dependencies = [
|
||||||
|
"hmac",
|
||||||
|
"subtle",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rsa"
|
name = "rsa"
|
||||||
version = "0.9.10"
|
version = "0.9.10"
|
||||||
@@ -1132,6 +1295,7 @@ dependencies = [
|
|||||||
"pkcs1",
|
"pkcs1",
|
||||||
"pkcs8",
|
"pkcs8",
|
||||||
"rand_core",
|
"rand_core",
|
||||||
|
"sha2",
|
||||||
"signature",
|
"signature",
|
||||||
"spki",
|
"spki",
|
||||||
"subtle",
|
"subtle",
|
||||||
@@ -1247,6 +1411,20 @@ dependencies = [
|
|||||||
"sha2",
|
"sha2",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "sec1"
|
||||||
|
version = "0.7.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc"
|
||||||
|
dependencies = [
|
||||||
|
"base16ct",
|
||||||
|
"der",
|
||||||
|
"generic-array",
|
||||||
|
"pkcs8",
|
||||||
|
"subtle",
|
||||||
|
"zeroize",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "secrecy"
|
name = "secrecy"
|
||||||
version = "0.10.3"
|
version = "0.10.3"
|
||||||
@@ -1362,6 +1540,48 @@ dependencies = [
|
|||||||
"der",
|
"der",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ssh-cipher"
|
||||||
|
version = "0.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "caac132742f0d33c3af65bfcde7f6aa8f62f0e991d80db99149eb9d44708784f"
|
||||||
|
dependencies = [
|
||||||
|
"cipher",
|
||||||
|
"ssh-encoding",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ssh-encoding"
|
||||||
|
version = "0.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "eb9242b9ef4108a78e8cd1a2c98e193ef372437f8c22be363075233321dd4a15"
|
||||||
|
dependencies = [
|
||||||
|
"base64ct",
|
||||||
|
"pem-rfc7468",
|
||||||
|
"sha2",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ssh-key"
|
||||||
|
version = "0.6.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3b86f5297f0f04d08cabaa0f6bff7cb6aec4d9c3b49d87990d63da9d9156a8c3"
|
||||||
|
dependencies = [
|
||||||
|
"ed25519-dalek",
|
||||||
|
"p256",
|
||||||
|
"p384",
|
||||||
|
"p521",
|
||||||
|
"rand_core",
|
||||||
|
"rsa",
|
||||||
|
"sec1",
|
||||||
|
"sha2",
|
||||||
|
"signature",
|
||||||
|
"ssh-cipher",
|
||||||
|
"ssh-encoding",
|
||||||
|
"subtle",
|
||||||
|
"zeroize",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "strsim"
|
name = "strsim"
|
||||||
version = "0.11.1"
|
version = "0.11.1"
|
||||||
|
|||||||
@@ -7,4 +7,6 @@ edition = "2024"
|
|||||||
age = { version = "0.11.3", features = ["ssh"] }
|
age = { version = "0.11.3", features = ["ssh"] }
|
||||||
clap = { version = "4.6.1", features = ["derive"] }
|
clap = { version = "4.6.1", features = ["derive"] }
|
||||||
flate2 = "1.1.9"
|
flate2 = "1.1.9"
|
||||||
|
rand = "0.8"
|
||||||
|
ssh-key = { version = "0.6", features = ["ed25519", "getrandom"] }
|
||||||
tar = "0.4.45"
|
tar = "0.4.45"
|
||||||
|
|||||||
@@ -0,0 +1,12 @@
|
|||||||
|
# Phase 6
|
||||||
|
|
||||||
|
For phase 6, the app is almost finished but I want to include a couple quality of life features:
|
||||||
|
|
||||||
|
- If the user runs `drawer open somedrawer.drawer`, this is currently an error because there is no target path given.
|
||||||
|
If the file basename of the drawer path would be a valid target path (`./somedrawer` in this case) then use that as the
|
||||||
|
target path, but also print to stdout that that's what it's using. This should still not open the drawer if the target
|
||||||
|
path exists and is nonempty, unless the user passes `-f`
|
||||||
|
|
||||||
|
- Add a new command, `drawer key <filename>` which will create a new key and store it in the given filename. Before
|
||||||
|
creating the new key, make sure the filename does not exist and is writable. This will need a good source of entropy to
|
||||||
|
generate a key, so as part of your plan, recommend one.
|
||||||
+5
-1
@@ -17,6 +17,8 @@ pub enum DrawerError {
|
|||||||
EncryptFailed,
|
EncryptFailed,
|
||||||
DecryptFailed(PathBuf, PathBuf),
|
DecryptFailed(PathBuf, PathBuf),
|
||||||
UntarFailed,
|
UntarFailed,
|
||||||
|
KeyOutputFailed(PathBuf),
|
||||||
|
KeyGenerateFailed,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for DrawerError {
|
impl fmt::Display for DrawerError {
|
||||||
@@ -24,7 +26,7 @@ impl fmt::Display for DrawerError {
|
|||||||
match self {
|
match self {
|
||||||
DrawerError::ParseError(s) => write!(f, "{s}"),
|
DrawerError::ParseError(s) => write!(f, "{s}"),
|
||||||
DrawerError::NoKeyPath => write!(f, "no key specified: set $DRAWER_KEY or use -i"),
|
DrawerError::NoKeyPath => write!(f, "no key specified: set $DRAWER_KEY or use -i"),
|
||||||
DrawerError::DrawerFileInvalidExtension(p) => write!(f, "drawer file must have a .drawer extension: {}", p.display()),
|
DrawerError::DrawerFileInvalidExtension(p) => write!(f, "drawer file must end in .drawer: {}", p.display()),
|
||||||
DrawerError::DrawerFileNotFound(p) => write!(f, "drawer file not found: {}", p.display()),
|
DrawerError::DrawerFileNotFound(p) => write!(f, "drawer file not found: {}", p.display()),
|
||||||
DrawerError::TargetInvalid(p) => write!(f, "target path does not exist, is not a directory, or is not readable: {}", p.display()),
|
DrawerError::TargetInvalid(p) => write!(f, "target path does not exist, is not a directory, or is not readable: {}", p.display()),
|
||||||
DrawerError::KeyInvalid(p) => write!(f, "key not found or not readable: {}", p.display()),
|
DrawerError::KeyInvalid(p) => write!(f, "key not found or not readable: {}", p.display()),
|
||||||
@@ -36,6 +38,8 @@ impl fmt::Display for DrawerError {
|
|||||||
DrawerError::EncryptFailed => write!(f, "encryption failed"),
|
DrawerError::EncryptFailed => write!(f, "encryption failed"),
|
||||||
DrawerError::DecryptFailed(drawer, key) => write!(f, "failed to decrypt {} with key {}", drawer.display(), key.display()),
|
DrawerError::DecryptFailed(drawer, key) => write!(f, "failed to decrypt {} with key {}", drawer.display(), key.display()),
|
||||||
DrawerError::UntarFailed => write!(f, "drawer file does not contain a valid archive"),
|
DrawerError::UntarFailed => write!(f, "drawer file does not contain a valid archive"),
|
||||||
|
DrawerError::KeyOutputFailed(p) => write!(f, "cannot create key file: {} (already exists or directory is not writable)", p.display()),
|
||||||
|
DrawerError::KeyGenerateFailed => write!(f, "failed to generate key"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+17
@@ -31,6 +31,7 @@ mod tests {
|
|||||||
drawer_file: "blah.drawer".into(),
|
drawer_file: "blah.drawer".into(),
|
||||||
key: Path("foo.key".into()),
|
key: Path("foo.key".into()),
|
||||||
target_path: "blah".into(),
|
target_path: "blah".into(),
|
||||||
|
target_inferred: false,
|
||||||
force: false,
|
force: false,
|
||||||
}
|
}
|
||||||
))
|
))
|
||||||
@@ -45,6 +46,22 @@ mod tests {
|
|||||||
drawer_file: "blah.drawer".into(),
|
drawer_file: "blah.drawer".into(),
|
||||||
key: Path("foo.key".into()),
|
key: Path("foo.key".into()),
|
||||||
target_path: "blah".into(),
|
target_path: "blah".into(),
|
||||||
|
target_inferred: false,
|
||||||
|
force: false,
|
||||||
|
}
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_inferred_open() {
|
||||||
|
let op = parse_args(vec!["drawer", "open", "blah.drawer", "-i", "foo.key"]);
|
||||||
|
assert_eq!(op, Ok(
|
||||||
|
DrawerOperation {
|
||||||
|
operation_type: Open,
|
||||||
|
drawer_file: "blah.drawer".into(),
|
||||||
|
key: Path("foo.key".into()),
|
||||||
|
target_path: "blah".into(),
|
||||||
|
target_inferred: true,
|
||||||
force: false,
|
force: false,
|
||||||
}
|
}
|
||||||
))
|
))
|
||||||
|
|||||||
+58
-3
@@ -6,6 +6,7 @@ use flate2::Compression;
|
|||||||
use flate2::read::GzDecoder;
|
use flate2::read::GzDecoder;
|
||||||
use flate2::write::GzEncoder;
|
use flate2::write::GzEncoder;
|
||||||
use clap::{Parser, Subcommand};
|
use clap::{Parser, Subcommand};
|
||||||
|
use ssh_key::{Algorithm, LineEnding, PrivateKey};
|
||||||
use crate::error::DrawerError;
|
use crate::error::DrawerError;
|
||||||
use crate::parsing::KeyType::*;
|
use crate::parsing::KeyType::*;
|
||||||
|
|
||||||
@@ -13,6 +14,7 @@ use crate::parsing::KeyType::*;
|
|||||||
pub enum OperationType {
|
pub enum OperationType {
|
||||||
Open,
|
Open,
|
||||||
Close,
|
Close,
|
||||||
|
Key,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq)]
|
||||||
@@ -22,6 +24,7 @@ pub struct DrawerOperation {
|
|||||||
pub key: KeyType,
|
pub key: KeyType,
|
||||||
pub target_path: PathBuf,
|
pub target_path: PathBuf,
|
||||||
pub force: bool,
|
pub force: bool,
|
||||||
|
pub target_inferred: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq)]
|
||||||
@@ -52,6 +55,9 @@ enum Command {
|
|||||||
#[arg(short = 'i')]
|
#[arg(short = 'i')]
|
||||||
key: Option<PathBuf>,
|
key: Option<PathBuf>,
|
||||||
},
|
},
|
||||||
|
Key {
|
||||||
|
filename: PathBuf,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse_args<I, T>(args: I) -> Result<DrawerOperation, DrawerError>
|
pub fn parse_args<I, T>(args: I) -> Result<DrawerOperation, DrawerError>
|
||||||
@@ -65,15 +71,17 @@ where
|
|||||||
match cli.command {
|
match cli.command {
|
||||||
Command::Open { drawer_file, target_path, key, force } => {
|
Command::Open { drawer_file, target_path, key, force } => {
|
||||||
let key = resolve_key(key);
|
let key = resolve_key(key);
|
||||||
let target = target_path.unwrap_or_else(|| {
|
let (target, target_inferred) = match target_path {
|
||||||
PathBuf::from(drawer_file.file_stem().unwrap_or_default())
|
Some(p) => (p, false),
|
||||||
});
|
None => (PathBuf::from(drawer_file.file_stem().unwrap_or_default()), true),
|
||||||
|
};
|
||||||
Ok(DrawerOperation {
|
Ok(DrawerOperation {
|
||||||
operation_type: OperationType::Open,
|
operation_type: OperationType::Open,
|
||||||
drawer_file,
|
drawer_file,
|
||||||
key,
|
key,
|
||||||
target_path: target,
|
target_path: target,
|
||||||
force,
|
force,
|
||||||
|
target_inferred,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
Command::Close { drawer_file, target_path, key } => {
|
Command::Close { drawer_file, target_path, key } => {
|
||||||
@@ -85,6 +93,17 @@ where
|
|||||||
key,
|
key,
|
||||||
target_path: target,
|
target_path: target,
|
||||||
force: false,
|
force: false,
|
||||||
|
target_inferred: false,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
Command::Key { filename } => {
|
||||||
|
Ok(DrawerOperation {
|
||||||
|
operation_type: OperationType::Key,
|
||||||
|
drawer_file: filename,
|
||||||
|
key: KeyType::EnvVar,
|
||||||
|
target_path: PathBuf::from("."),
|
||||||
|
force: false,
|
||||||
|
target_inferred: false,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -103,10 +122,14 @@ impl DrawerOperation {
|
|||||||
match self.operation_type {
|
match self.operation_type {
|
||||||
OperationType::Open => self.perform_open(),
|
OperationType::Open => self.perform_open(),
|
||||||
OperationType::Close => self.perform_close(),
|
OperationType::Close => self.perform_close(),
|
||||||
|
OperationType::Key => self.perform_key(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn perform_open(&self) -> Result<(), DrawerError> {
|
fn perform_open(&self) -> Result<(), DrawerError> {
|
||||||
|
if self.target_inferred {
|
||||||
|
println!("(assuming into {})", self.target_path.display());
|
||||||
|
}
|
||||||
let encrypted = std::fs::read(&self.drawer_file)
|
let encrypted = std::fs::read(&self.drawer_file)
|
||||||
.map_err(|_| DrawerError::DrawerFileNotFound(self.drawer_file.clone()))?;
|
.map_err(|_| DrawerError::DrawerFileNotFound(self.drawer_file.clone()))?;
|
||||||
|
|
||||||
@@ -179,16 +202,39 @@ impl DrawerOperation {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn validate(&self) -> Result<(), DrawerError> {
|
pub fn validate(&self) -> Result<(), DrawerError> {
|
||||||
|
if self.operation_type != OperationType::Key {
|
||||||
if self.drawer_file.extension().and_then(|e| e.to_str()) != Some("drawer") {
|
if self.drawer_file.extension().and_then(|e| e.to_str()) != Some("drawer") {
|
||||||
return Err(DrawerError::DrawerFileInvalidExtension(self.drawer_file.clone()));
|
return Err(DrawerError::DrawerFileInvalidExtension(self.drawer_file.clone()));
|
||||||
}
|
}
|
||||||
self.validate_key()?;
|
self.validate_key()?;
|
||||||
|
}
|
||||||
match self.operation_type {
|
match self.operation_type {
|
||||||
OperationType::Open => self.validate_open(),
|
OperationType::Open => self.validate_open(),
|
||||||
OperationType::Close => self.validate_close(),
|
OperationType::Close => self.validate_close(),
|
||||||
|
OperationType::Key => self.validate_key_gen(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn validate_key_gen(&self) -> Result<(), DrawerError> {
|
||||||
|
if self.drawer_file.exists() {
|
||||||
|
return Err(DrawerError::KeyOutputFailed(self.drawer_file.clone()));
|
||||||
|
}
|
||||||
|
let parent = match self.drawer_file.parent() {
|
||||||
|
None => Path::new("."),
|
||||||
|
Some(p) => {
|
||||||
|
if p == Path::new("") {
|
||||||
|
Path::new(".")
|
||||||
|
} else {
|
||||||
|
p
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
if !parent.exists() {
|
||||||
|
return Err(DrawerError::KeyOutputFailed(self.drawer_file.clone()));
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
fn key_path(&self) -> Result<PathBuf, DrawerError> {
|
fn key_path(&self) -> Result<PathBuf, DrawerError> {
|
||||||
match &self.key {
|
match &self.key {
|
||||||
EnvVar => {
|
EnvVar => {
|
||||||
@@ -225,6 +271,15 @@ impl DrawerOperation {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn perform_key(&self) -> Result<(), DrawerError> {
|
||||||
|
let private_key = PrivateKey::random(&mut rand::rngs::OsRng, Algorithm::Ed25519)
|
||||||
|
.map_err(|_| DrawerError::KeyGenerateFailed)?;
|
||||||
|
let pem = private_key.to_openssh(LineEnding::LF)
|
||||||
|
.map_err(|_| DrawerError::KeyGenerateFailed)?;
|
||||||
|
std::fs::write(&self.drawer_file, pem.as_bytes())
|
||||||
|
.map_err(|_| DrawerError::KeyOutputFailed(self.drawer_file.clone()))
|
||||||
|
}
|
||||||
|
|
||||||
fn validate_close(&self) -> Result<(), DrawerError> {
|
fn validate_close(&self) -> Result<(), DrawerError> {
|
||||||
let meta = std::fs::metadata(&self.target_path)
|
let meta = std::fs::metadata(&self.target_path)
|
||||||
.map_err(|_| DrawerError::TargetInvalid(self.target_path.clone()))?;
|
.map_err(|_| DrawerError::TargetInvalid(self.target_path.clone()))?;
|
||||||
|
|||||||
Reference in New Issue
Block a user