72
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										72
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
								
							| @@ -88,6 +88,15 @@ version = "2.8.0" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "8f68f53c83ab957f72c32642f3868eec03eb974d1fb82e453128456482613d36" | ||||
|  | ||||
| [[package]] | ||||
| name = "block-buffer" | ||||
| version = "0.10.4" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" | ||||
| dependencies = [ | ||||
|  "generic-array", | ||||
| ] | ||||
|  | ||||
| [[package]] | ||||
| name = "bumpalo" | ||||
| version = "3.17.0" | ||||
| @@ -240,6 +249,16 @@ version = "0.8.21" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" | ||||
|  | ||||
| [[package]] | ||||
| name = "crypto-common" | ||||
| version = "0.1.6" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" | ||||
| dependencies = [ | ||||
|  "generic-array", | ||||
|  "typenum", | ||||
| ] | ||||
|  | ||||
| [[package]] | ||||
| name = "deranged" | ||||
| version = "0.3.11" | ||||
| @@ -255,6 +274,16 @@ version = "0.1.13" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8" | ||||
|  | ||||
| [[package]] | ||||
| name = "digest" | ||||
| version = "0.10.7" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" | ||||
| dependencies = [ | ||||
|  "block-buffer", | ||||
|  "crypto-common", | ||||
| ] | ||||
|  | ||||
| [[package]] | ||||
| name = "dns-lookup" | ||||
| version = "2.0.4" | ||||
| @@ -295,6 +324,16 @@ version = "2.3.0" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" | ||||
|  | ||||
| [[package]] | ||||
| name = "generic-array" | ||||
| version = "0.14.7" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" | ||||
| dependencies = [ | ||||
|  "typenum", | ||||
|  "version_check", | ||||
| ] | ||||
|  | ||||
| [[package]] | ||||
| name = "getrandom" | ||||
| version = "0.3.1" | ||||
| @@ -404,6 +443,16 @@ version = "0.4.25" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "04cbf5b083de1c7e0222a7a51dbfdba1cbe1c6ab0b15e29fff3f6c077fd9cd9f" | ||||
|  | ||||
| [[package]] | ||||
| name = "md-5" | ||||
| version = "0.10.6" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "d89e7ee0cfbedfc4da3340218492196241d89eefb6dab27de5df917a6d2e78cf" | ||||
| dependencies = [ | ||||
|  "cfg-if", | ||||
|  "digest", | ||||
| ] | ||||
|  | ||||
| [[package]] | ||||
| name = "memchr" | ||||
| version = "2.7.4" | ||||
| @@ -916,6 +965,12 @@ dependencies = [ | ||||
|  "time-core", | ||||
| ] | ||||
|  | ||||
| [[package]] | ||||
| name = "typenum" | ||||
| version = "1.18.0" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "1dccffe3ce07af9386bfd29e80c0ab1a8205a2fc34e4bcd40364df902cfa8f3f" | ||||
|  | ||||
| [[package]] | ||||
| name = "unicode-ident" | ||||
| version = "1.0.16" | ||||
| @@ -975,6 +1030,7 @@ dependencies = [ | ||||
|  "uu_lscpu", | ||||
|  "uu_lslocks", | ||||
|  "uu_lsmem", | ||||
|  "uu_mcookie", | ||||
|  "uu_mesg", | ||||
|  "uu_mountpoint", | ||||
|  "uu_renice", | ||||
| @@ -1068,6 +1124,16 @@ dependencies = [ | ||||
|  "uucore", | ||||
| ] | ||||
|  | ||||
| [[package]] | ||||
| name = "uu_mcookie" | ||||
| version = "0.0.1" | ||||
| dependencies = [ | ||||
|  "clap", | ||||
|  "md-5", | ||||
|  "rand 0.9.0", | ||||
|  "uucore", | ||||
| ] | ||||
|  | ||||
| [[package]] | ||||
| name = "uu_mesg" | ||||
| version = "0.0.1" | ||||
| @@ -1149,6 +1215,12 @@ version = "0.0.30" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "0bb6d972f580f8223cb7052d8580aea2b7061e368cf476de32ea9457b19459ed" | ||||
|  | ||||
| [[package]] | ||||
| name = "version_check" | ||||
| version = "0.9.5" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" | ||||
|  | ||||
| [[package]] | ||||
| name = "wasi" | ||||
| version = "0.13.3+wasi-0.2.2" | ||||
|   | ||||
| @@ -34,6 +34,7 @@ feat_common_core = [ | ||||
|   "lscpu", | ||||
|   "lslocks", | ||||
|   "lsmem", | ||||
|   "mcookie", | ||||
|   "mesg", | ||||
|   "mountpoint", | ||||
|   "renice", | ||||
| @@ -48,6 +49,7 @@ clap_mangen = "0.2" | ||||
| dns-lookup = "2.0.4" | ||||
| libc = "0.2.152" | ||||
| linux-raw-sys = { version = "0.9.0", features = ["ioctl"] } | ||||
| md-5 = "0.10.6" | ||||
| nix = { version = "0.29", default-features = false } | ||||
| phf = "0.11.2" | ||||
| phf_codegen = "0.11.2" | ||||
| @@ -81,6 +83,7 @@ last = { optional = true, version = "0.0.1", package = "uu_last", path = "src/uu | ||||
| lscpu = { optional = true, version = "0.0.1", package = "uu_lscpu", path = "src/uu/lscpu" } | ||||
| lslocks = { optional = true, version = "0.0.1", package = "uu_lslocks", path = "src/uu/lslocks" } | ||||
| lsmem = { optional = true, version = "0.0.1", package = "uu_lsmem", path = "src/uu/lsmem" } | ||||
| mcookie = { optional = true, version = "0.0.1", package = "uu_mcookie", path = "src/uu/mcookie" } | ||||
| mesg = { optional = true, version = "0.0.1", package = "uu_mesg", path = "src/uu/mesg" } | ||||
| mountpoint = { optional = true, version = "0.0.1", package = "uu_mountpoint", path = "src/uu/mountpoint" } | ||||
| renice = { optional = true, version = "0.0.1", package = "uu_renice", path = "src/uu/renice" } | ||||
|   | ||||
							
								
								
									
										17
									
								
								src/uu/mcookie/Cargo.toml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								src/uu/mcookie/Cargo.toml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,17 @@ | ||||
| [package] | ||||
| name = "uu_mcookie" | ||||
| version = "0.0.1" | ||||
| edition = "2021" | ||||
|  | ||||
| [lib] | ||||
| path = "src/mcookie.rs" | ||||
|  | ||||
| [[bin]] | ||||
| name = "mcookie" | ||||
| path = "src/main.rs" | ||||
|  | ||||
| [dependencies] | ||||
| uucore = { workspace = true } | ||||
| clap = { workspace = true } | ||||
| md-5 = { workspace = true } | ||||
| rand = { workspace = true } | ||||
							
								
								
									
										7
									
								
								src/uu/mcookie/mcookie.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								src/uu/mcookie/mcookie.md
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,7 @@ | ||||
| # mcookie | ||||
|  | ||||
| ``` | ||||
| mcookie [OPTION]... | ||||
| ``` | ||||
|  | ||||
| Generate magic cookies for xauth. | ||||
							
								
								
									
										1
									
								
								src/uu/mcookie/src/main.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								src/uu/mcookie/src/main.rs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1 @@ | ||||
| uucore::bin!(uu_mcookie); | ||||
							
								
								
									
										111
									
								
								src/uu/mcookie/src/mcookie.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										111
									
								
								src/uu/mcookie/src/mcookie.rs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,111 @@ | ||||
| // This file is part of the uutils util-linux package. | ||||
| // | ||||
| // For the full copyright and license information, please view the LICENSE | ||||
| // file that was distributed with this source code. | ||||
|  | ||||
| use std::{fs::File, io::Read}; | ||||
|  | ||||
| use clap::{crate_version, Arg, ArgAction, Command}; | ||||
| use md5::{Digest, Md5}; | ||||
| use rand::RngCore; | ||||
| use uucore::{error::UResult, format_usage, help_about, help_usage}; | ||||
|  | ||||
| mod options { | ||||
|     pub const FILE: &str = "file"; | ||||
|     pub const MAX_SIZE: &str = "max-size"; | ||||
|     pub const VERBOSE: &str = "verbose"; | ||||
| } | ||||
|  | ||||
| const ABOUT: &str = help_about!("mcookie.md"); | ||||
| const USAGE: &str = help_usage!("mcookie.md"); | ||||
|  | ||||
| #[uucore::main] | ||||
| pub fn uumain(args: impl uucore::Args) -> UResult<()> { | ||||
|     let matches: clap::ArgMatches = uu_app().try_get_matches_from(args)?; | ||||
|  | ||||
|     let verbose = matches.get_flag(options::VERBOSE); | ||||
|  | ||||
|     let seed_files: Vec<&str> = matches | ||||
|         .get_many::<String>(options::FILE) | ||||
|         .unwrap_or_default() | ||||
|         .map(|v| v.as_str()) | ||||
|         .collect(); | ||||
|  | ||||
|     // TODO: Parse max size from human-readable strings (KiB, MiB, GiB etc.) | ||||
|     let max_size = matches | ||||
|         .get_one::<String>(options::MAX_SIZE) | ||||
|         .map(|v| v.parse::<u64>().expect("Failed to parse max-size value")); | ||||
|  | ||||
|     let mut hasher = Md5::new(); | ||||
|  | ||||
|     for file in seed_files { | ||||
|         let mut f = File::open(file)?; | ||||
|         let mut buffer: Vec<u8> = Vec::new(); | ||||
|  | ||||
|         if let Some(max_bytes) = &max_size { | ||||
|             let mut handle = f.take(*max_bytes); | ||||
|             handle.read_to_end(&mut buffer)?; | ||||
|         } else { | ||||
|             f.read_to_end(&mut buffer)?; | ||||
|         } | ||||
|  | ||||
|         if verbose { | ||||
|             eprintln!("Got {} bytes from {}", buffer.len(), file); | ||||
|         } | ||||
|  | ||||
|         hasher.update(&buffer); | ||||
|     } | ||||
|  | ||||
|     const RANDOM_BYTES: usize = 128; | ||||
|     let mut rng = rand::rng(); | ||||
|     let mut rand_bytes = [0u8; RANDOM_BYTES]; | ||||
|     rng.fill_bytes(&mut rand_bytes); | ||||
|  | ||||
|     hasher.update(rand_bytes); | ||||
|  | ||||
|     if verbose { | ||||
|         eprintln!("Got {} bytes from randomness source", RANDOM_BYTES); | ||||
|     } | ||||
|  | ||||
|     let result = hasher.finalize(); | ||||
|     let output = result | ||||
|         .iter() | ||||
|         .map(|byte| format!("{:02x}", byte)) | ||||
|         .collect::<Vec<_>>() | ||||
|         .join(""); | ||||
|  | ||||
|     println!("{}", output); | ||||
|  | ||||
|     Ok(()) | ||||
| } | ||||
|  | ||||
| pub fn uu_app() -> Command { | ||||
|     Command::new(uucore::util_name()) | ||||
|         .version(crate_version!()) | ||||
|         .about(ABOUT) | ||||
|         .override_usage(format_usage(USAGE)) | ||||
|         .infer_long_args(true) | ||||
|         .arg( | ||||
|             Arg::new(options::FILE) | ||||
|                 .short('f') | ||||
|                 .long("file") | ||||
|                 .value_name("file") | ||||
|                 .action(ArgAction::Append) | ||||
|                 .help("use file as a cookie seed"), | ||||
|         ) | ||||
|         .arg( | ||||
|             Arg::new(options::MAX_SIZE) | ||||
|                 .short('m') | ||||
|                 .long("max-size") | ||||
|                 .value_name("num") | ||||
|                 .action(ArgAction::Set) | ||||
|                 .help("limit how much is read from seed files"), | ||||
|         ) | ||||
|         .arg( | ||||
|             Arg::new(options::VERBOSE) | ||||
|                 .short('v') | ||||
|                 .long("verbose") | ||||
|                 .action(ArgAction::SetTrue) | ||||
|                 .help("explain what is being done"), | ||||
|         ) | ||||
| } | ||||
							
								
								
									
										65
									
								
								tests/by-util/test_mcookie.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										65
									
								
								tests/by-util/test_mcookie.rs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,65 @@ | ||||
| // This file is part of the uutils util-linux package. | ||||
| // | ||||
| // For the full copyright and license information, please view the LICENSE | ||||
| // file that was distributed with this source code. | ||||
|  | ||||
| use std::io::Write; | ||||
|  | ||||
| use tempfile::{NamedTempFile, TempDir}; | ||||
|  | ||||
| use crate::common::util::TestScenario; | ||||
|  | ||||
| #[test] | ||||
| fn test_invalid_arg() { | ||||
|     new_ucmd!().arg("--definitely-invalid").fails().code_is(1); | ||||
| } | ||||
|  | ||||
| #[test] | ||||
| fn test_basic_usage() { | ||||
|     let res = new_ucmd!().succeeds(); | ||||
|  | ||||
|     let stdout = res.no_stderr().stdout_str(); | ||||
|  | ||||
|     // Expect 32 hex characters for the MD5 hash (after trimming the newline) | ||||
|     assert_eq!(stdout.trim_end().len(), 32); | ||||
|     assert!(stdout.trim_end().chars().all(|c| c.is_ascii_hexdigit())); | ||||
| } | ||||
|  | ||||
| #[test] | ||||
| fn test_verbose() { | ||||
|     let res = new_ucmd!().arg("--verbose").succeeds(); | ||||
|     res.stderr_contains("Got 128 bytes from randomness source"); | ||||
| } | ||||
|  | ||||
| #[test] | ||||
| fn test_seed_files_and_max_size() { | ||||
|     let mut file1 = NamedTempFile::new().unwrap(); | ||||
|     const CONTENT1: &str = "Some seed data"; | ||||
|     file1.write_all(CONTENT1.as_bytes()).unwrap(); | ||||
|  | ||||
|     let mut file2 = NamedTempFile::new().unwrap(); | ||||
|     const CONTENT2: [u8; 2048] = [1; 2048]; | ||||
|     file2.write_all(&CONTENT2).unwrap(); | ||||
|  | ||||
|     let res = new_ucmd!() | ||||
|         .arg("--verbose") | ||||
|         .arg("-f") | ||||
|         .arg(file1.path()) | ||||
|         .arg("-f") | ||||
|         .arg(file2.path()) | ||||
|         .arg("-m") | ||||
|         .arg("1337") | ||||
|         .succeeds(); | ||||
|  | ||||
|     res.stderr_contains(format!( | ||||
|         "Got {} bytes from {}", | ||||
|         CONTENT1.len(), | ||||
|         file1.path().to_str().unwrap() | ||||
|     )); | ||||
|  | ||||
|     // Ensure we only read up to the limit of bytes, despite the file being bigger | ||||
|     res.stderr_contains(format!( | ||||
|         "Got 1337 bytes from {}", | ||||
|         file2.path().to_str().unwrap() | ||||
|     )); | ||||
| } | ||||
| @@ -56,3 +56,7 @@ mod test_dmesg; | ||||
| #[cfg(feature = "fsfreeze")] | ||||
| #[path = "by-util/test_fsfreeze.rs"] | ||||
| mod test_fsfreeze; | ||||
|  | ||||
| #[cfg(feature = "mcookie")] | ||||
| #[path = "by-util/test_mcookie.rs"] | ||||
| mod test_mcookie; | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Sylvestre Ledru
					Sylvestre Ledru