commit 032432f775a0584d3b3921b728851f054bb64434 Author: Spectre Date: Thu Sep 25 19:28:39 2025 +0200 Started project diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ea8c4bf --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/target diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..5c19a80 --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,850 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "android_system_properties" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", +] + +[[package]] +name = "anstream" +version = "0.6.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ae563653d1938f79b1ab1b5e668c87c76a9930414574a6583a7b7e11a8e6192" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "is_terminal_polyfill", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "862ed96ca487e809f1c8e5a8447f6ee2cf102f846893800b20cebdf541fc6bbd" + +[[package]] +name = "anstyle-parse" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e7644824f0aa2c7b9384579234ef10eb7efb6a0deb83f9630a49594dd9c15c2" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e231f6134f61b71076a3eab506c379d4f36122f2af15a9ff04415ea4c3339e2" +dependencies = [ + "windows-sys 0.60.2", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e0633414522a32ffaac8ac6cc8f748e090c5717661fddeea04219e2344f5f2a" +dependencies = [ + "anstyle", + "once_cell_polyfill", + "windows-sys 0.60.2", +] + +[[package]] +name = "anyhow" +version = "1.0.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61" + +[[package]] +name = "autocfg" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" + +[[package]] +name = "bitflags" +version = "2.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2261d10cca569e4643e526d8dc2e62e433cc8aba21ab764233731f8d369bf394" + +[[package]] +name = "bumpalo" +version = "3.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43" + +[[package]] +name = "cc" +version = "1.2.38" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "80f41ae168f955c12fb8960b057d70d0ca153fb83182b57d86380443527be7e9" +dependencies = [ + "find-msvc-tools", + "shlex", +] + +[[package]] +name = "cfg-if" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fd1289c04a9ea8cb22300a459a72a385d7c73d3259e2ed7dcb2af674838cfa9" + +[[package]] +name = "chrono" +version = "0.4.42" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "145052bdd345b87320e369255277e3fb5152762ad123a901ef5c262dd38fe8d2" +dependencies = [ + "iana-time-zone", + "js-sys", + "num-traits", + "wasm-bindgen", + "windows-link 0.2.0", +] + +[[package]] +name = "clap" +version = "4.5.48" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2134bb3ea021b78629caa971416385309e0131b351b25e01dc16fb54e1b5fae" +dependencies = [ + "clap_builder", + "clap_derive", +] + +[[package]] +name = "clap_builder" +version = "4.5.48" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2ba64afa3c0a6df7fa517765e31314e983f51dda798ffba27b988194fb65dc9" +dependencies = [ + "anstream", + "anstyle", + "clap_lex", + "strsim", +] + +[[package]] +name = "clap_derive" +version = "4.5.47" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbfd7eae0b0f1a6e63d4b13c9c478de77c2eb546fba158ad50b4203dc24b9f9c" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "clap_lex" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b94f61472cee1439c0b966b47e3aca9ae07e45d070759512cd390ea2bebc6675" + +[[package]] +name = "colorchoice" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75" + +[[package]] +name = "colored" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "117725a109d387c937a1533ce01b450cbde6b88abceea8473c4d7a85853cda3c" +dependencies = [ + "lazy_static", + "windows-sys 0.59.0", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" + +[[package]] +name = "errno" +version = "0.3.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" +dependencies = [ + "libc", + "windows-sys 0.61.0", +] + +[[package]] +name = "fastrand" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" + +[[package]] +name = "filetime" +version = "0.2.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc0505cd1b6fa6580283f6bdf70a73fcf4aba1184038c90902b92b3dd0df63ed" +dependencies = [ + "cfg-if", + "libc", + "libredox", + "windows-sys 0.60.2", +] + +[[package]] +name = "find-msvc-tools" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ced73b1dacfc750a6db6c0a0c3a3853c8b41997e2e2c563dc90804ae6867959" + +[[package]] +name = "foreign-types" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" +dependencies = [ + "foreign-types-shared", +] + +[[package]] +name = "foreign-types-shared" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" + +[[package]] +name = "getrandom" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4" +dependencies = [ + "cfg-if", + "libc", + "r-efi", + "wasi", +] + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[package]] +name = "iana-time-zone" +version = "0.1.64" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33e57f83510bb73707521ebaffa789ec8caf86f9657cad665b092b581d40e9fb" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "log", + "wasm-bindgen", + "windows-core", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +dependencies = [ + "cc", +] + +[[package]] +name = "is_terminal_polyfill" +version = "1.70.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" + +[[package]] +name = "js-sys" +version = "0.3.81" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec48937a97411dcb524a265206ccd4c90bb711fca92b2792c407f268825b9305" +dependencies = [ + "once_cell", + "wasm-bindgen", +] + +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + +[[package]] +name = "libc" +version = "0.2.176" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58f929b4d672ea937a23a1ab494143d968337a5f47e56d0815df1e0890ddf174" + +[[package]] +name = "libredox" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "416f7e718bdb06000964960ffa43b4335ad4012ae8b99060261aa4a8088d5ccb" +dependencies = [ + "bitflags", + "libc", + "redox_syscall", +] + +[[package]] +name = "linux-raw-sys" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df1d3c3b53da64cf5760482273a98e575c651a67eec7f77df96b5b642de8f039" + +[[package]] +name = "log" +version = "0.4.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432" + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] + +[[package]] +name = "once_cell" +version = "1.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" + +[[package]] +name = "once_cell_polyfill" +version = "1.70.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4895175b425cb1f87721b59f0f286c2092bd4af812243672510e1ac53e2e0ad" + +[[package]] +name = "openssl" +version = "0.10.73" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8505734d46c8ab1e19a1dce3aef597ad87dcb4c37e7188231769bd6bd51cebf8" +dependencies = [ + "bitflags", + "cfg-if", + "foreign-types", + "libc", + "once_cell", + "openssl-macros", + "openssl-sys", +] + +[[package]] +name = "openssl-macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "openssl-src" +version = "300.5.2+3.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d270b79e2926f5150189d475bc7e9d2c69f9c4697b185fa917d5a32b792d21b4" +dependencies = [ + "cc", +] + +[[package]] +name = "openssl-sys" +version = "0.9.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90096e2e47630d78b7d1c20952dc621f957103f8bc2c8359ec81290d75238571" +dependencies = [ + "cc", + "libc", + "openssl-src", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "oxylos" +version = "0.1.0" +dependencies = [ + "anyhow", + "chrono", + "clap", + "colored", + "filetime", + "openssl", + "tempfile", + "thiserror", + "uuid", +] + +[[package]] +name = "pkg-config" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" + +[[package]] +name = "proc-macro2" +version = "1.0.101" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89ae43fd86e4158d6db51ad8e2b80f313af9cc74f5c0e03ccb87de09998732de" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "r-efi" +version = "5.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" + +[[package]] +name = "redox_syscall" +version = "0.5.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5407465600fb0548f1442edf71dd20683c6ed326200ace4b1ef0763521bb3b77" +dependencies = [ + "bitflags", +] + +[[package]] +name = "rustix" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd15f8a2c5551a84d56efdc1cd049089e409ac19a3072d5037a17fd70719ff3e" +dependencies = [ + "bitflags", + "errno", + "libc", + "linux-raw-sys", + "windows-sys 0.61.0", +] + +[[package]] +name = "rustversion" +version = "1.0.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" + +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + +[[package]] +name = "syn" +version = "2.0.106" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ede7c438028d4436d71104916910f5bb611972c5cfd7f89b8300a8186e6fada6" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "tempfile" +version = "3.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d31c77bdf42a745371d260a26ca7163f1e0924b64afa0b688e61b5a9fa02f16" +dependencies = [ + "fastrand", + "getrandom", + "once_cell", + "rustix", + "windows-sys 0.61.0", +] + +[[package]] +name = "thiserror" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "unicode-ident" +version = "1.0.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f63a545481291138910575129486daeaf8ac54aee4387fe7906919f7830c7d9d" + +[[package]] +name = "utf8parse" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" + +[[package]] +name = "uuid" +version = "1.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f87b8aa10b915a06587d0dec516c282ff295b475d94abf425d62b57710070a2" +dependencies = [ + "getrandom", + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + +[[package]] +name = "wasi" +version = "0.14.7+wasi-0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "883478de20367e224c0090af9cf5f9fa85bed63a95c1abf3afc5c083ebc06e8c" +dependencies = [ + "wasip2", +] + +[[package]] +name = "wasip2" +version = "1.0.1+wasi-0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0562428422c63773dad2c345a1882263bbf4d65cf3f42e90921f787ef5ad58e7" +dependencies = [ + "wit-bindgen", +] + +[[package]] +name = "wasm-bindgen" +version = "0.2.104" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1da10c01ae9f1ae40cbfac0bac3b1e724b320abfcf52229f80b547c0d250e2d" +dependencies = [ + "cfg-if", + "once_cell", + "rustversion", + "wasm-bindgen-macro", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.104" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "671c9a5a66f49d8a47345ab942e2cb93c7d1d0339065d4f8139c486121b43b19" +dependencies = [ + "bumpalo", + "log", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.104" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ca60477e4c59f5f2986c50191cd972e3a50d8a95603bc9434501cf156a9a119" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.104" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f07d2f20d4da7b26400c9f4a0511e6e0345b040694e8a75bd41d578fa4421d7" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.104" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bad67dc8b2a1a6e5448428adec4c3e84c43e561d8c9ee8a9e5aabeb193ec41d1" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "windows-core" +version = "0.62.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57fe7168f7de578d2d8a05b07fd61870d2e73b4020e9f49aa00da8471723497c" +dependencies = [ + "windows-implement", + "windows-interface", + "windows-link 0.2.0", + "windows-result", + "windows-strings", +] + +[[package]] +name = "windows-implement" +version = "0.60.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a47fddd13af08290e67f4acabf4b459f647552718f683a7b415d290ac744a836" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "windows-interface" +version = "0.59.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd9211b69f8dcdfa817bfd14bf1c97c9188afa36f4750130fcdf3f400eca9fa8" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "windows-link" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a" + +[[package]] +name = "windows-link" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45e46c0661abb7180e7b9c281db115305d49ca1709ab8242adf09666d2173c65" + +[[package]] +name = "windows-result" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7084dcc306f89883455a206237404d3eaf961e5bd7e0f312f7c91f57eb44167f" +dependencies = [ + "windows-link 0.2.0", +] + +[[package]] +name = "windows-strings" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7218c655a553b0bed4426cf54b20d7ba363ef543b52d515b3e48d7fd55318dda" +dependencies = [ + "windows-link 0.2.0", +] + +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-sys" +version = "0.60.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" +dependencies = [ + "windows-targets 0.53.3", +] + +[[package]] +name = "windows-sys" +version = "0.61.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e201184e40b2ede64bc2ea34968b28e33622acdbbf37104f0e4a33f7abe657aa" +dependencies = [ + "windows-link 0.2.0", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", + "windows_i686_gnullvm 0.52.6", + "windows_i686_msvc 0.52.6", + "windows_x86_64_gnu 0.52.6", + "windows_x86_64_gnullvm 0.52.6", + "windows_x86_64_msvc 0.52.6", +] + +[[package]] +name = "windows-targets" +version = "0.53.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5fe6031c4041849d7c496a8ded650796e7b6ecc19df1a431c1a363342e5dc91" +dependencies = [ + "windows-link 0.1.3", + "windows_aarch64_gnullvm 0.53.0", + "windows_aarch64_msvc 0.53.0", + "windows_i686_gnu 0.53.0", + "windows_i686_gnullvm 0.53.0", + "windows_i686_msvc 0.53.0", + "windows_x86_64_gnu 0.53.0", + "windows_x86_64_gnullvm 0.53.0", + "windows_x86_64_msvc 0.53.0", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnu" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1dc67659d35f387f5f6c479dc4e28f1d4bb90ddd1a5d3da2e5d97b42d6272c3" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_i686_msvc" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486" + +[[package]] +name = "wit-bindgen" +version = "0.46.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f17a85883d4e6d00e8a97c586de764dabcc06133f7f1d55dce5cdc070ad7fe59" diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..0a31003 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,17 @@ +[package] +name = "oxylos" +version = "0.1.0" +edition = "2021" + +[dependencies] +anyhow = "1" +thiserror = "1" +chrono = { version = "0.4", features = ["clock"] } +clap = { version = "4", features = ["derive"] } +colored = "2" +openssl = { version = "0.10", features = ["vendored"] } +uuid = { version = "1", features = ["v4"] } +filetime = "0.2.26" + +[dev-dependencies] +tempfile = "3" diff --git a/src/cli.rs b/src/cli.rs new file mode 100644 index 0000000..b073a73 --- /dev/null +++ b/src/cli.rs @@ -0,0 +1,33 @@ +use clap::Parser; +use std::path::PathBuf; + +use crate::config::{DEFAULT_PRIVKEY, DEFAULT_PUBKEY}; + +#[derive(Parser, Debug)] +#[command(version, about, long_about=None)] +pub struct Args { + #[arg(short = 'e', long = "encrypt", conflicts_with_all = ["decrypt", "inbox"])] + pub encrypt: bool, + + #[arg(short = 'd', long = "decrypt", conflicts_with_all = ["encrypt", "inbox"])] + pub decrypt: bool, + + #[arg(long = "inbox", conflicts_with_all = ["encrypt", "decrypt"])] + pub inbox: bool, + + #[arg(short = 'p', long = "path")] + pub path: Option, + + #[arg(short = 'g', long = "generate-new-keys", conflicts_with_all = ["encrypt", "decrypt", "inbox"])] + pub generate_new_keys: bool, + + #[arg(long = "public-key", default_value = DEFAULT_PUBKEY)] + pub public_key: PathBuf, + + #[arg(long = "private-key", default_value = DEFAULT_PRIVKEY)] + pub private_key: PathBuf, + + #[arg(long = "passphrase")] + pub passphrase: Option, +} + diff --git a/src/commands/decrypt.rs b/src/commands/decrypt.rs new file mode 100644 index 0000000..87fb61d --- /dev/null +++ b/src/commands/decrypt.rs @@ -0,0 +1,19 @@ +use anyhow::{bail, Context, Result}; +use std::io::{self, Write}; + +use crate::cli::Args; +use crate::crypto::rsa::decrypt_with_priv; + +pub fn run(args: &Args) -> Result<()> { + let private_pem = std::fs::read_to_string(&args.private_key).context("read private key failed")?; + let pass = args.passphrase.as_ref().map(|s| s.as_bytes()); + let in_path = match args.path.as_ref() { + Some(p) => p, + None => bail!("--path is required for --decrypt"), + }; + let ciphertext = std::fs::read(in_path).context("read ciphertext failed")?; + let plain = decrypt_with_priv(&ciphertext, &private_pem, pass)?; + io::stdout().write_all(&plain)?; + Ok(()) +} + diff --git a/src/commands/encrypt.rs b/src/commands/encrypt.rs new file mode 100644 index 0000000..1e98789 --- /dev/null +++ b/src/commands/encrypt.rs @@ -0,0 +1,33 @@ +use anyhow::{Context, Result}; +use chrono::Utc; +use std::io; +use std::path::Path; +use uuid::Uuid; + +use crate::cli::Args; +use crate::config::DEFAULT_OUT_MSG; +use crate::crypto::rsa::encrypt_with_pub; +use crate::storage::fsio::write_all; + +pub fn run(args: &Args) -> Result<()> { + let _t = Utc::now(); + let uuid = Uuid::new_v4(); + let out = format!("{DEFAULT_OUT_MSG}{uuid}"); + let out_path = args.path.as_deref().unwrap_or(Path::new(&out)); + + let mut author = String::new(); + println!("enter your name/pseudonyme below:"); + io::stdin().read_line(&mut author).context("stdin author")?; + + let mut content = String::new(); + println!("enter your text below:"); + io::stdin() + .read_line(&mut content) + .context("stdin content")?; + + let pk_pem = std::fs::read_to_string(&args.public_key).context("read public key failed")?; + let payload = format!("Author: {author}\n{content}"); + let cipher_text = encrypt_with_pub(payload.trim_end().as_bytes(), &pk_pem)?; + write_all(out_path, &cipher_text)?; + Ok(()) +} diff --git a/src/commands/inbox.rs b/src/commands/inbox.rs new file mode 100644 index 0000000..d201dae --- /dev/null +++ b/src/commands/inbox.rs @@ -0,0 +1,18 @@ +use anyhow::{Context, Result}; +use std::io::{self, Write}; + +use crate::cli::Args; +use crate::message::scan::get_intended_messages_with_pass; + +pub fn run(args: &Args) -> Result<()> { + let private_pem = std::fs::read_to_string(&args.private_key).context("read private key failed")?; + let pass = args.passphrase.as_deref().map(str::as_bytes); + let items = get_intended_messages_with_pass(&private_pem, pass)?; + for (path, plain) in items { + println!("{}\n---", path.display()); + io::stdout().write_all(&plain)?; + println!(); + } + Ok(()) +} + diff --git a/src/commands/mod.rs b/src/commands/mod.rs new file mode 100644 index 0000000..65f8758 --- /dev/null +++ b/src/commands/mod.rs @@ -0,0 +1,28 @@ +use anyhow::Result; + +use crate::cli::Args; + +pub mod decrypt; +pub mod encrypt; +pub mod inbox; + +pub fn dispatch(args: Args) -> Result<()> { + if args.generate_new_keys { + crate::crypto::rsa::generate_keys( + crate::config::DEFAULT_PRIVKEY, + crate::config::DEFAULT_PUBKEY, + )?; + return Ok(()); + } + if args.encrypt { + return encrypt::run(&args); + } + if args.decrypt { + return decrypt::run(&args); + } + if args.inbox { + return inbox::run(&args); + } + let _ = crate::message::scan::search_messages()?; + Ok(()) +} diff --git a/src/config.rs b/src/config.rs new file mode 100644 index 0000000..e8d1d59 --- /dev/null +++ b/src/config.rs @@ -0,0 +1,4 @@ +pub const DEFAULT_PUBKEY: &str = "storage/keys/public.pem"; +pub const DEFAULT_PRIVKEY: &str = "storage/keys/private.pem"; +pub const DEFAULT_OUT_MSG: &str = "storage/messages/"; + diff --git a/src/crypto/mod.rs b/src/crypto/mod.rs new file mode 100644 index 0000000..8184486 --- /dev/null +++ b/src/crypto/mod.rs @@ -0,0 +1,2 @@ +pub mod rsa; + diff --git a/src/crypto/rsa.rs b/src/crypto/rsa.rs new file mode 100644 index 0000000..56090ed --- /dev/null +++ b/src/crypto/rsa.rs @@ -0,0 +1,111 @@ +use openssl::encrypt::{Decrypter, Encrypter}; +use openssl::error::ErrorStack; +use openssl::hash::MessageDigest; +use openssl::pkey::{PKey, Private}; +use openssl::rsa::{Padding, Rsa}; + +use crate::errors::CryptoError; +use crate::storage::fsio::write_all; +use std::path::Path; + +fn map_err(ctx: &str, e: ErrorStack) -> CryptoError { + CryptoError::OpenSsl(format!("{ctx}: {e}")) +} + +pub fn load_public_key(pem: &str) -> Result, CryptoError> { + if pem.contains("BEGIN RSA PUBLIC KEY") { + let rsa = + Rsa::public_key_from_pem_pkcs1(pem.as_bytes()).map_err(|e| map_err("pkcs1", e))?; + PKey::from_rsa(rsa).map_err(|e| map_err("pkey from rsa", e)) + } else { + PKey::public_key_from_pem(pem.as_bytes()).map_err(|e| map_err("public_key_from_pem", e)) + } +} + +pub fn load_private_key(pem: &str, pass: Option<&[u8]>) -> Result, CryptoError> { + if let Some(p) = pass { + PKey::private_key_from_pem_passphrase(pem.as_bytes(), p) + .map_err(|e| map_err("private+pass", e)) + } else { + PKey::private_key_from_pem(pem.as_bytes()).map_err(|e| map_err("private", e)) + } +} + +pub fn encrypt_with_pub(plain: &[u8], pub_pem: &str) -> Result, CryptoError> { + let pkey = load_public_key(pub_pem)?; + let mut enc = Encrypter::new(&pkey).map_err(|e| map_err("enc new", e))?; + enc.set_rsa_padding(Padding::PKCS1_OAEP) + .map_err(|e| map_err("set padding", e))?; + enc.set_rsa_oaep_md(MessageDigest::sha256()) + .map_err(|e| map_err("oaep md", e))?; + enc.set_rsa_mgf1_md(MessageDigest::sha256()) + .map_err(|e| map_err("mgf1 md", e))?; + let mut out = vec![ + 0; + enc.encrypt_len(plain) + .map_err(|e| map_err("encrypt_len", e))? + ]; + let n = enc + .encrypt(plain, &mut out) + .map_err(|e| map_err("encrypt", e))?; + out.truncate(n); + Ok(out) +} + +pub fn decrypt_with_priv( + cipher: &[u8], + priv_pem: &str, + pass: Option<&[u8]>, +) -> Result, CryptoError> { + let pkey = load_private_key(priv_pem, pass)?; + let mut dec = Decrypter::new(&pkey).map_err(|e| map_err("dec new", e))?; + dec.set_rsa_padding(Padding::PKCS1_OAEP) + .map_err(|e| map_err("set padding", e))?; + dec.set_rsa_oaep_md(MessageDigest::sha256()) + .map_err(|e| map_err("oaep md", e))?; + dec.set_rsa_mgf1_md(MessageDigest::sha256()) + .map_err(|e| map_err("mgf1 md", e))?; + let mut out = vec![ + 0; + dec.decrypt_len(cipher) + .map_err(|e| map_err("decrypt_len", e))? + ]; + let n = dec + .decrypt(cipher, &mut out) + .map_err(|e| map_err("decrypt", e))?; + out.truncate(n); + Ok(out) +} + +pub fn generate_keys(priv_out: &str, pub_out: &str) -> Result<(), CryptoError> { + let rsa = Rsa::generate(3072).map_err(|e| map_err("rsa gen", e))?; + let pkey = PKey::from_rsa(rsa).map_err(|e| map_err("to pkey", e))?; + let sk_pem = pkey + .private_key_to_pem_pkcs8() + .map_err(|e| map_err("pem pkcs8", e))?; + let pk_pem = pkey + .public_key_to_pem() + .map_err(|e| map_err("pub pem", e))?; + write_all(Path::new(priv_out), &sk_pem) + .map_err(|e| CryptoError::OpenSsl(format!("write priv: {e}")))?; + write_all(Path::new(pub_out), &pk_pem) + .map_err(|e| CryptoError::OpenSsl(format!("write pub: {e}")))?; + Ok(()) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn roundtrip_encrypt_decrypt_pkcs8() { + let rsa = Rsa::generate(2048).unwrap(); + let pkey = PKey::from_rsa(rsa).unwrap(); + let pk_pem = String::from_utf8(pkey.public_key_to_pem().unwrap()).unwrap(); + let sk_pem = String::from_utf8(pkey.private_key_to_pem_pkcs8().unwrap()).unwrap(); + let msg = b"hello, cryptoworld"; + let cipher = encrypt_with_pub(msg, &pk_pem).unwrap(); + let plain = decrypt_with_priv(&cipher, &sk_pem, None).unwrap(); + assert_eq!(msg, &plain[..]); + } +} diff --git a/src/errors.rs b/src/errors.rs new file mode 100644 index 0000000..9f4128f --- /dev/null +++ b/src/errors.rs @@ -0,0 +1,8 @@ +use thiserror::Error; + +#[derive(Debug, Error)] +pub enum CryptoError { + #[error("{0}")] + OpenSsl(String), +} + diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..2594714 --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,8 @@ +pub mod cli; +pub mod config; +pub mod errors; +pub mod commands; +pub mod crypto; +pub mod storage; +pub mod message; + diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..a62644f --- /dev/null +++ b/src/main.rs @@ -0,0 +1,10 @@ +use anyhow::Result; +use clap::Parser; + +fn main() -> Result<()> { + let args = oxylos::cli::Args::parse(); + oxylos::storage::init::ensure_storage_or_init()?; + oxylos::storage::init::ensure_os_dropboxes()?; + let _ = oxylos::message::sync::auto_sync()?; + oxylos::commands::dispatch(args) +} diff --git a/src/message/hash.rs b/src/message/hash.rs new file mode 100644 index 0000000..f5938ff --- /dev/null +++ b/src/message/hash.rs @@ -0,0 +1,20 @@ +use openssl::sha::Sha256; +use std::fs::File; +use std::io::{self, Read}; +use std::path::Path; + +pub fn sha256_file(path: &Path) -> io::Result<[u8; 32]> { + let file = File::open(path)?; + let mut reader = std::io::BufReader::new(file); + let mut hasher = Sha256::new(); + let mut buf = [0u8; 4096]; + loop { + let n = reader.read(&mut buf)?; + if n == 0 { + break; + } + hasher.update(&buf[..n]); + } + Ok(hasher.finish()) +} + diff --git a/src/message/mod.rs b/src/message/mod.rs new file mode 100644 index 0000000..17b44fa --- /dev/null +++ b/src/message/mod.rs @@ -0,0 +1,4 @@ +pub mod scan; +pub mod sync; +pub mod hash; + diff --git a/src/message/scan.rs b/src/message/scan.rs new file mode 100644 index 0000000..2fd9b0a --- /dev/null +++ b/src/message/scan.rs @@ -0,0 +1,112 @@ +use std::fs::read_dir; +use std::fs::DirEntry; +use std::io; +use std::path::PathBuf; + +use crate::crypto::rsa::decrypt_with_priv; +use crate::storage::fsio::is_valid_dir; +use crate::storage::paths::{persistent_dir, ram_dir}; + +pub fn search_messages() -> io::Result> { + search_messages_in(persistent_dir(), ram_dir()) +} + +pub fn search_messages_in(persistent: &str, ram: &str) -> io::Result> { + if !is_valid_dir(persistent) { + eprintln!("Couldn't find persistent folder at {persistent}"); + return Ok(Vec::new()); + } + if !is_valid_dir(ram) { + eprintln!("Couldn't find RAM folder at {ram}"); + return Ok(Vec::new()); + } + let ram_paths = read_dir(ram)?; + let persistent_paths = read_dir(persistent)?; + let mut all = Vec::new(); + all.extend(ram_paths.filter_map(Result::ok)); + all.extend(persistent_paths.filter_map(Result::ok)); + Ok(all) +} + +pub fn get_intended_messages(private_pem: &str) -> io::Result)>> { + get_intended_messages_with_pass(private_pem, None) +} + +pub fn get_intended_messages_with_pass( + private_pem: &str, + pass: Option<&[u8]>, +) -> io::Result)>> { + get_intended_messages_in_with_pass(private_pem, pass, persistent_dir(), ram_dir()) +} + +pub fn get_intended_messages_in_with_pass( + private_pem: &str, + pass: Option<&[u8]>, + persistent: &str, + ram: &str, +) -> io::Result)>> { + let entries = search_messages_in(persistent, ram)?; + let mut found = Vec::new(); + for entry in entries { + let p = entry.path(); + if !p.is_file() { + continue; + } + if let Ok(cipher) = std::fs::read(&p) { + if let Ok(plain) = decrypt_with_priv(&cipher, private_pem, pass) { + found.push((p, plain)); + } + } + } + Ok(found) +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::crypto::rsa::encrypt_with_pub; + use openssl::pkey::PKey; + use openssl::rsa::Rsa; + use tempfile::tempdir; + + #[test] + fn search_messages_missing_dirs_yields_empty_ok() -> io::Result<()> { + let list = search_messages_in("/this/does/not/exist", "/neither/does/this")?; + assert!(list.is_empty()); + Ok(()) + } + + #[test] + fn get_intended_messages_returns_only_decryptable() -> io::Result<()> { + let rsa = Rsa::generate(2048).unwrap(); + let pkey = PKey::from_rsa(rsa).unwrap(); + let pk_pem = String::from_utf8(pkey.public_key_to_pem().unwrap()).unwrap(); + let sk_pem = String::from_utf8(pkey.private_key_to_pem_pkcs8().unwrap()).unwrap(); + let d_persistent = tempdir()?; + let d_ram = tempdir()?; + let msg1 = b"alpha"; + let msg2 = b"bravo"; + let c1 = encrypt_with_pub(msg1, &pk_pem).unwrap(); + let c2 = encrypt_with_pub(msg2, &pk_pem).unwrap(); + let p1 = d_persistent.path().join("m1.msg"); + let p2 = d_ram.path().join("m2.msg"); + std::fs::write(&p1, &c1)?; + std::fs::write(&p2, &c2)?; + let p_bad = d_persistent.path().join("noise.bin"); + std::fs::write(&p_bad, b"\x01\x02\x03\x04\x05")?; + let list = get_intended_messages_in_with_pass( + &sk_pem, + None, + d_persistent.path().to_str().unwrap(), + d_ram.path().to_str().unwrap(), + )?; + assert_eq!(list.len(), 2); + let plains: Vec = list + .iter() + .map(|(_, v)| String::from_utf8_lossy(v).to_string()) + .collect(); + assert!(plains.contains(&"alpha".to_string())); + assert!(plains.contains(&"bravo".to_string())); + Ok(()) + } +} diff --git a/src/message/sync.rs b/src/message/sync.rs new file mode 100644 index 0000000..f43338e --- /dev/null +++ b/src/message/sync.rs @@ -0,0 +1,72 @@ +use std::collections::HashMap; +use std::io; +use std::path::PathBuf; + +use crate::message::hash::sha256_file; +use crate::storage::fsio::{copy_msg, list_files}; + +pub struct SyncReport { + pub copied_to_remote: usize, + pub copied_to_local: usize, +} + +pub fn bidirectional_sync( + local_outbox: &[PathBuf], + remote_dirs: &[Vec], + local_dest: &str, + remote_dest: &str, +) -> io::Result { + let mut own_map = HashMap::new(); + for f in local_outbox { + let digest = sha256_file(f)?; + own_map.insert(digest, f); + } + let mut remote_map = HashMap::new(); + for group in remote_dirs { + for f in group { + let digest = sha256_file(f)?; + remote_map.insert(digest, f); + } + } + + let commons: Vec<[u8; 32]> = own_map + .keys() + .filter(|k| remote_map.contains_key(*k)) + .copied() + .collect(); + for k in commons { + own_map.remove(&k); + remote_map.remove(&k); + } + + let mut copied_to_remote = 0usize; + for msg in own_map.values() { + let name = uuid::Uuid::new_v4().to_string(); + copy_msg(msg.to_str().unwrap(), &format!("{remote_dest}{name}"))?; + copied_to_remote += 1; + } + + let mut copied_to_local = 0usize; + for msg in remote_map.values() { + let name = uuid::Uuid::new_v4().to_string(); + copy_msg(msg.to_str().unwrap(), &format!("{local_dest}{name}"))?; + copied_to_local += 1; + } + + Ok(SyncReport { + copied_to_remote, + copied_to_local, + }) +} + +pub fn auto_sync() -> io::Result { + let local = list_files(crate::config::DEFAULT_OUT_MSG)?; + let remote_p = list_files(crate::storage::paths::persistent_dir())?; + let remote_r = list_files(crate::storage::paths::ram_dir())?; + bidirectional_sync( + &local, + &[remote_p, remote_r], + crate::config::DEFAULT_OUT_MSG, + crate::storage::paths::persistent_dir(), + ) +} diff --git a/src/storage/fsio.rs b/src/storage/fsio.rs new file mode 100644 index 0000000..8a02969 --- /dev/null +++ b/src/storage/fsio.rs @@ -0,0 +1,47 @@ +use filetime::{set_file_times, FileTime}; +use std::fs::{self, File, OpenOptions}; +use std::io::{self, Read, Write}; +use std::os::unix::fs::PermissionsExt; +use std::path::{Path, PathBuf}; + +fn neutralize_metadata(path: &Path) -> io::Result<()> { + let perms = fs::Permissions::from_mode(0o600); + let _ = fs::set_permissions(path, perms); + let zero = FileTime::from_unix_time(0, 0); + let _ = set_file_times(path, zero, zero); + Ok(()) +} + +pub fn write_all(path: &Path, content: &[u8]) -> io::Result<()> { + if let Some(parent) = path.parent() { + fs::create_dir_all(parent)?; + } + let mut f = OpenOptions::new() + .write(true) + .create(true) + .truncate(true) + .open(path)?; + let _ = fs::set_permissions(path, fs::Permissions::from_mode(0o600)); + f.write_all(content)?; + f.sync_all()?; + neutralize_metadata(path) +} + +pub fn list_files(directory_path: &str) -> io::Result> { + let mut paths = Vec::new(); + for entry in fs::read_dir(directory_path)? { + let entry = entry?; + paths.push(entry.path()); + } + Ok(paths) +} + +pub fn is_valid_dir(path: &str) -> bool { + Path::new(path).is_dir() +} + +pub fn copy_msg(source: &str, destination: &str) -> io::Result<()> { + let mut buf = Vec::new(); + File::open(source)?.read_to_end(&mut buf)?; + write_all(Path::new(destination), &buf) +} diff --git a/src/storage/init.rs b/src/storage/init.rs new file mode 100644 index 0000000..8b97fac --- /dev/null +++ b/src/storage/init.rs @@ -0,0 +1,38 @@ +use colored::Colorize; +use std::io; +use std::path::Path; + +pub fn ensure_storage_or_init() -> io::Result<()> { + let path = Path::new("storage"); + if !path.exists() { + init()?; + std::process::exit(0); + } + Ok(()) +} + +fn create_persistent_storage() -> io::Result<()> { + std::fs::create_dir_all("storage")?; + std::fs::create_dir_all("storage/keys")?; + std::fs::create_dir_all("storage/index")?; + std::fs::create_dir_all("storage/messages")?; + Ok(()) +} + +pub fn init() -> io::Result<()> { + let color_text = "Olyxos -h"; + println!( + "Thank you for using Olyxos. This is the initialization of the program; it creates 4 directories. The first one is storage: this is where the program stores everything. If you already have a pair of cryptographic keys and you want to use them, please put them in storage/keys/ under the names 'private.pem' and 'public.pem'. You can see the arguments to use by running {}", + color_text.red() + ); + create_persistent_storage() +} + +pub fn ensure_os_dropboxes() -> io::Result<()> { + use std::fs::create_dir_all; + let p = crate::storage::paths::persistent_dir(); + let r = crate::storage::paths::ram_dir(); + let _ = create_dir_all(p); + let _ = create_dir_all(r); + Ok(()) +} diff --git a/src/storage/mod.rs b/src/storage/mod.rs new file mode 100644 index 0000000..1f84131 --- /dev/null +++ b/src/storage/mod.rs @@ -0,0 +1,4 @@ +pub mod init; +pub mod paths; +pub mod fsio; + diff --git a/src/storage/paths.rs b/src/storage/paths.rs new file mode 100644 index 0000000..99670b9 --- /dev/null +++ b/src/storage/paths.rs @@ -0,0 +1,29 @@ +#[cfg(target_os = "windows")] +pub fn persistent_dir() -> &'static str { + r"C:\ProgramData\Oxylos\" +} + +#[cfg(target_os = "windows")] +pub fn ram_dir() -> &'static str { + r"Global\Oxylos" +} + +#[cfg(all(unix, not(target_os = "macos")))] +pub fn persistent_dir() -> &'static str { + "/tmp/Oxylos/" +} + +#[cfg(all(unix, not(target_os = "macos")))] +pub fn ram_dir() -> &'static str { + "/dev/shm/Oxylos/" +} + +#[cfg(target_os = "macos")] +pub fn persistent_dir() -> &'static str { + "/tmp/Oxylos/" +} + +#[cfg(target_os = "macos")] +pub fn ram_dir() -> &'static str { + "/tmp/Oxylos.shm/" +}