diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 31000a2..a291cd0 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -10,13 +10,16 @@ env: CARGO_TERM_COLOR: always jobs: - build: - - runs-on: ubuntu-latest + build: + strategy: + matrix: + os: [windows-latest, ubuntu-latest, macos-latest] + runs-on: ${{ matrix.os }} steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Build run: cargo build --verbose - name: Run tests run: cargo test --verbose + diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md index 6c3bcea..c707252 100644 --- a/CODE_OF_CONDUCT.md +++ b/CODE_OF_CONDUCT.md @@ -1,4 +1,3 @@ - # Contributor Covenant Code of Conduct ## Our Pledge @@ -61,7 +60,7 @@ representative at an online or offline event. Instances of abusive, harassing, or otherwise unacceptable behavior may be reported to the community leaders responsible for enforcement at -. +`@winlogon.exe:matrix.org` All complaints will be reviewed and investigated promptly and fairly. All community leaders are obligated to respect the privacy and security of the diff --git a/Cargo.lock b/Cargo.lock index 5661b2a..0f79581 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,17 +2,26 @@ # It is not intended for manual editing. version = 4 +[[package]] +name = "addr2line" +version = "0.25.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b5d307320b3181d6d7954e663bd7c774a838b8220fe0593c86d9fb09f498b4b" +dependencies = [ + "gimli", +] + [[package]] name = "adler2" -version = "2.0.0" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" +checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" [[package]] name = "anstream" -version = "0.6.18" +version = "0.6.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b" +checksum = "43d5b281e737544384e969a5ccad3f1cdd24b48086a0fc1b2a5262a26b8f4f4a" dependencies = [ "anstyle", "anstyle-parse", @@ -25,44 +34,44 @@ dependencies = [ [[package]] name = "anstyle" -version = "1.0.10" +version = "1.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9" +checksum = "5192cca8006f1fd4f7237516f40fa183bb07f8fbdfedaa0036de5ea9b0b45e78" [[package]] name = "anstyle-parse" -version = "0.2.6" +version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9" +checksum = "4e7644824f0aa2c7b9384579234ef10eb7efb6a0deb83f9630a49594dd9c15c2" dependencies = [ "utf8parse", ] [[package]] name = "anstyle-query" -version = "1.1.2" +version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c" +checksum = "9e231f6134f61b71076a3eab506c379d4f36122f2af15a9ff04415ea4c3339e2" dependencies = [ - "windows-sys 0.59.0", + "windows-sys 0.60.2", ] [[package]] name = "anstyle-wincon" -version = "3.0.7" +version = "3.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca3534e77181a9cc07539ad51f2141fe32f6c3ffd4df76db8ad92346b003ae4e" +checksum = "3e0633414522a32ffaac8ac6cc8f748e090c5717661fddeea04219e2344f5f2a" dependencies = [ "anstyle", - "once_cell", - "windows-sys 0.59.0", + "once_cell_polyfill", + "windows-sys 0.60.2", ] [[package]] name = "anyhow" -version = "1.0.97" +version = "1.0.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcfed56ad506cb2c684a14971b8861fdc3baaaae314b9e5f9bb532cbe3ba7a4f" +checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61" [[package]] name = "arrayref" @@ -78,9 +87,33 @@ checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" [[package]] name = "autocfg" -version = "1.4.0" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" + +[[package]] +name = "backtrace" +version = "0.3.76" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb531853791a215d7c62a30daf0dde835f381ab5de4589cfe7c649d2cbe92bd6" +dependencies = [ + "addr2line", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", + "windows-link", +] + +[[package]] +name = "backtrace-ext" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" +checksum = "537beee3be4a18fb023b570f80e3ae28003db9167a751266b259926e25539d50" +dependencies = [ + "backtrace", +] [[package]] name = "base64" @@ -90,9 +123,9 @@ checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" [[package]] name = "bit_field" -version = "0.10.2" +version = "0.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc827186963e592360843fb5ba4b973e145841266c1357f7180c43526f2e5b61" +checksum = "1e4b40c7323adcfc0a41c4b88143ed58346ff65a288fc144329c5c45e05d70c6" [[package]] name = "bitflags" @@ -102,15 +135,15 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.9.0" +version = "2.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd" +checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3" [[package]] name = "bytemuck" -version = "1.22.0" +version = "1.24.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6b1fc10dbac614ebc03540c9dbd60e83887fda27794998c6528f1782047d540" +checksum = "1fbdf580320f38b612e485521afda1ee26d10cc9884efaaa750d383e13e3c5f4" [[package]] name = "byteorder" @@ -120,9 +153,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "cfg-if" -version = "1.0.0" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" [[package]] name = "checked_int_cast" @@ -138,19 +171,20 @@ dependencies = [ "clap", "image 0.24.9", "log", + "miette", "qrcode", "resvg", "simple_logger", + "thiserror", "tiny-skia", - "toml", "usvg", ] [[package]] name = "clap" -version = "4.5.31" +version = "4.5.51" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "027bb0d98429ae334a8698531da7077bdf906419543a35a55c2cb1b66437d767" +checksum = "4c26d721170e0295f191a69bd9a1f93efcdb0aff38684b61ab5750468972e5f5" dependencies = [ "clap_builder", "clap_derive", @@ -158,9 +192,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.31" +version = "4.5.51" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5589e0cba072e0f3d23791efac0fd8627b49c829c196a492e88168e6a669d863" +checksum = "75835f0c7bf681bfd05abe44e965760fea999a5286c6eb2d59883634fd02011a" dependencies = [ "anstream", "anstyle", @@ -170,9 +204,9 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.5.28" +version = "4.5.49" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf4ced95c6f4a675af3da73304b9ac4ed991640c36374e4b46795c49e17cf1ed" +checksum = "2a0b5487afeab2deb2ff4e03a807ad1a03ac532ff5a2cee5d86884440c7f7671" dependencies = [ "heck", "proc-macro2", @@ -182,9 +216,9 @@ dependencies = [ [[package]] name = "clap_lex" -version = "0.7.4" +version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6" +checksum = "a1d728cc89cf3aee9ff92b05e62b19ee65a02b5702cff7d5a377e32c6ae29d8d" [[package]] name = "color_quant" @@ -194,25 +228,24 @@ checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b" [[package]] name = "colorchoice" -version = "1.0.3" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990" +checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75" [[package]] name = "colored" -version = "2.2.0" +version = "3.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "117725a109d387c937a1533ce01b450cbde6b88abceea8473c4d7a85853cda3c" +checksum = "fde0e0ec90c9dfb3b4b1a0891a7dcd0e2bffde2f7efed5fe7c9bb00e5bfb915e" dependencies = [ - "lazy_static", "windows-sys 0.59.0", ] [[package]] name = "crc32fast" -version = "1.4.2" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" +checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511" dependencies = [ "cfg-if", ] @@ -244,21 +277,21 @@ checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" [[package]] name = "crunchy" -version = "0.2.3" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43da5946c66ffcc7745f48db692ffbb10a83bfe0afd96235c5c2a4fb23994929" +checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5" [[package]] name = "data-url" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c297a1c74b71ae29df00c3e22dd9534821d60eb9af5a0192823fa2acea70c2a" +checksum = "be1e0bca6c3637f992fc1cc7cbc52a78c1ef6db076dbf1059c4323d6a2048376" [[package]] name = "deranged" -version = "0.3.11" +version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" +checksum = "ececcb659e7ba858fb4f10388c250a7252eb0a27373f1a72b8748afdd248e587" dependencies = [ "powerfmt", ] @@ -270,10 +303,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" [[package]] -name = "equivalent" -version = "1.0.2" +name = "errno" +version = "0.3.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" +checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" +dependencies = [ + "libc", + "windows-sys 0.61.2", +] [[package]] name = "exr" @@ -301,9 +338,9 @@ dependencies = [ [[package]] name = "flate2" -version = "1.1.0" +version = "1.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11faaf5a5236997af9848be0bef4db95824b1d534ebc64d0f0c6cf3e67bd38dc" +checksum = "bfe33edd8e85a12a67454e37f8c75e730830d83e313556ab9ebf9ee7fbeb3bfb" dependencies = [ "crc32fast", "miniz_oxide", @@ -317,9 +354,9 @@ checksum = "98de4bbd547a563b716d8dfa9aad1cb19bfab00f4fa09a6a4ed21dbcf44ce9c4" [[package]] name = "fontconfig-parser" -version = "0.5.7" +version = "0.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1fcfcd44ca6e90c921fee9fa665d530b21ef1327a4c1a6c5250ea44b776ada7" +checksum = "bbc773e24e02d4ddd8395fd30dc147524273a83e54e0f312d986ea30de5f5646" dependencies = [ "roxmltree 0.20.0", ] @@ -350,30 +387,31 @@ dependencies = [ [[package]] name = "gif" -version = "0.13.1" +version = "0.13.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fb2d69b19215e18bb912fa30f7ce15846e301408695e44e0ef719f1da9e19f2" +checksum = "4ae047235e33e2829703574b54fdec96bfbad892062d97fed2f76022287de61b" dependencies = [ "color_quant", "weezl", ] +[[package]] +name = "gimli" +version = "0.32.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e629b9b98ef3dd8afe6ca2bd0f89306cec16d43d907889945bc5d6687f2f13c7" + [[package]] name = "half" -version = "2.4.1" +version = "2.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6dd08c532ae367adf81c312a4580bc67f1d0fe8bc9c460520283f4c0ff277888" +checksum = "6ea2d84b969582b4b1864a92dc5d27cd2b77b622a8d79306834f1be5ba20d84b" dependencies = [ "cfg-if", "crunchy", + "zerocopy", ] -[[package]] -name = "hashbrown" -version = "0.15.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" - [[package]] name = "heck" version = "0.5.0" @@ -404,7 +442,7 @@ dependencies = [ "byteorder", "color_quant", "exr", - "gif 0.13.1", + "gif 0.13.3", "jpeg-decoder", "num-traits", "png", @@ -419,20 +457,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "029d73f573d8e8d63e6d5020011d3255b28c3ba85d6cf870a07184ed23de9284" [[package]] -name = "indexmap" -version = "2.7.1" +name = "is_ci" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c9c992b02b5b4c94ea26e32fe5bccb7aa7d9f390ab5c1221ff895bc7ea8b652" -dependencies = [ - "equivalent", - "hashbrown", -] +checksum = "7655c9839580ee829dfacba1d1278c2b7883e50a277ff7541299489d6bdfdc45" [[package]] name = "is_terminal_polyfill" -version = "1.70.1" +version = "1.70.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" +checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695" [[package]] name = "itoa" @@ -442,9 +476,9 @@ checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" [[package]] name = "jpeg-decoder" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f5d4a7da358eff58addd2877a45865158f0d78c911d43a5784ceb7bbf52833b0" +checksum = "00810f1d8b74be64b13dbf3db89ac67740615d6c891f0e7b6179326533011a07" dependencies = [ "rayon", ] @@ -469,49 +503,79 @@ dependencies = [ ] [[package]] -name = "lazy_static" -version = "1.5.0" +name = "lebe" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" +checksum = "7a79a3332a6609480d7d0c9eab957bca6b455b91bb84e66d19f5ff66294b85b8" [[package]] -name = "lebe" -version = "0.5.2" +name = "libc" +version = "0.2.177" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03087c2bad5e1034e8cace5926dec053fb3790248370865f5117a7d0213354c8" +checksum = "2874a2af47a2325c2001a6e6fad9b16a53b802102b528163885171cf92b15976" [[package]] -name = "libc" -version = "0.2.170" +name = "linux-raw-sys" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "875b3680cb2f8f71bdcf9a30f38d48282f5d3c95cbf9b3fa57269bb5d5c06828" +checksum = "df1d3c3b53da64cf5760482273a98e575c651a67eec7f77df96b5b642de8f039" [[package]] name = "log" -version = "0.4.26" +version = "0.4.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30bde2b3dc3671ae49d8e2e9f044c7c005836e7a023ee57cffa25ab82764bb9e" +checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432" [[package]] name = "memchr" -version = "2.7.4" +version = "2.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" +checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" [[package]] name = "memmap2" -version = "0.9.5" +version = "0.9.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd3f7eed9d3848f8b98834af67102b720745c4ec028fcd0aa0239277e7de374f" +checksum = "744133e4a0e0a658e1374cf3bf8e415c4052a15a111acd372764c55b4177d490" dependencies = [ "libc", ] +[[package]] +name = "miette" +version = "7.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f98efec8807c63c752b5bd61f862c165c115b0a35685bdcfd9238c7aeb592b7" +dependencies = [ + "backtrace", + "backtrace-ext", + "cfg-if", + "miette-derive", + "owo-colors", + "supports-color", + "supports-hyperlinks", + "supports-unicode", + "terminal_size", + "textwrap", + "unicode-width 0.1.14", +] + +[[package]] +name = "miette-derive" +version = "7.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db5b29714e950dbb20d5e6f74f9dcec4edbcc1067bb7f8ed198c097b8c1a818b" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "miniz_oxide" -version = "0.8.5" +version = "0.8.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e3e04debbb59698c15bacbb6d93584a8c0ca9cc3213cb423d31f760d8843ce5" +checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" dependencies = [ "adler2", "simd-adler32", @@ -573,10 +637,25 @@ dependencies = [ ] [[package]] -name = "once_cell" -version = "1.20.3" +name = "object" +version = "0.37.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff76201f031d8863c38aa7f905eca4f53abbfa15f609db4277d44cd8938f33fe" +dependencies = [ + "memchr", +] + +[[package]] +name = "once_cell_polyfill" +version = "1.70.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "945462a4b81e43c4e3ba96bd7b49d834c6f61198356aa858733bc4acf3cbe62e" +checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe" + +[[package]] +name = "owo-colors" +version = "4.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c6901729fa79e91a0913333229e9ca5dc725089d1c363b2f4b4760709dc4a52" [[package]] name = "pico-args" @@ -605,9 +684,9 @@ checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" [[package]] name = "proc-macro2" -version = "1.0.94" +version = "1.0.103" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a31971752e70b8b2686d7e46ec17fb38dad4051d94024c88df49b667caea9c84" +checksum = "5ee95bc4ef87b8d5ba32e8b7714ccc834865276eab0aed5c9958d00ec45f49e8" dependencies = [ "unicode-ident", ] @@ -633,18 +712,18 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.39" +version = "1.0.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1f1914ce909e1658d9907913b4b91947430c7d9be598b15a1912935b8c04801" +checksum = "ce25767e7b499d1b604768e7cde645d14cc8584231ea6b295e9c9eb22c02e1d1" dependencies = [ "proc-macro2", ] [[package]] name = "rayon" -version = "1.10.0" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa" +checksum = "368f01d005bf8fd9b1206fb6fa653e6c4a81ceb1466406b81792d87c5677a58f" dependencies = [ "either", "rayon-core", @@ -652,9 +731,9 @@ dependencies = [ [[package]] name = "rayon-core" -version = "1.12.1" +version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2" +checksum = "22e18b0f0062d30d4230b2e85ff77fdfe4326feb054b9783a3460d8435c8ab91" dependencies = [ "crossbeam-deque", "crossbeam-utils", @@ -679,9 +758,9 @@ dependencies = [ [[package]] name = "rgb" -version = "0.8.50" +version = "0.8.52" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57397d16646700483b67d2dd6511d79318f9d057fdbd21a4066aeac8b41d310a" +checksum = "0c6a884d2998352bb4daf0183589aec883f16a6da1f4dde84d8e2e9a5409a1ce" dependencies = [ "bytemuck", ] @@ -698,13 +777,32 @@ version = "0.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c20b6793b5c2fa6553b250154b78d6d0db37e72700ae35fad9387a46f487c97" +[[package]] +name = "rustc-demangle" +version = "0.1.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56f7d92ca342cea22a06f2121d944b4fd82af56988c270852495420f961d4ace" + +[[package]] +name = "rustix" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd15f8a2c5551a84d56efdc1cd049089e409ac19a3072d5037a17fd70719ff3e" +dependencies = [ + "bitflags 2.10.0", + "errno", + "libc", + "linux-raw-sys", + "windows-sys 0.61.2", +] + [[package]] name = "rustybuzz" version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f0ae5692c5beaad6a9e22830deeed7874eae8a4e3ba4076fb48e12c56856222c" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.10.0", "bytemuck", "smallvec", "ttf-parser", @@ -716,31 +814,31 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.218" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8dfc9d19bdbf6d17e22319da49161d5d0108e4188e8b680aef6299eed22df60" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" dependencies = [ - "serde_derive", + "serde_core", ] [[package]] -name = "serde_derive" -version = "1.0.218" +name = "serde_core" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f09503e191f4e797cb8aac08e9a4a4695c5edf6a2e70e376d961ddd5c969f82b" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" dependencies = [ - "proc-macro2", - "quote", - "syn", + "serde_derive", ] [[package]] -name = "serde_spanned" -version = "0.6.8" +name = "serde_derive" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87607cb1398ed59d48732e575a4c28a7a8ebf2454b964fe3f224f2afc07909e1" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" dependencies = [ - "serde", + "proc-macro2", + "quote", + "syn", ] [[package]] @@ -751,14 +849,14 @@ checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe" [[package]] name = "simple_logger" -version = "5.0.0" +version = "5.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8c5dfa5e08767553704aa0ffd9d9794d527103c736aba9854773851fd7497eb" +checksum = "291bee647ce7310b0ea721bfd7e0525517b4468eb7c7e15eb8bd774343179702" dependencies = [ "colored", "log", "time", - "windows-sys 0.48.0", + "windows-sys 0.61.2", ] [[package]] @@ -787,9 +885,9 @@ dependencies = [ [[package]] name = "smallvec" -version = "1.14.0" +version = "1.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fcf8323ef1faaee30a44a340193b1ac6814fd9b7b4e88e9d4519a3e4abe1cfd" +checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" [[package]] name = "strict-num" @@ -806,6 +904,27 @@ version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" +[[package]] +name = "supports-color" +version = "3.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c64fc7232dd8d2e4ac5ce4ef302b1d81e0b80d055b9d77c7c4f51f6aa4c867d6" +dependencies = [ + "is_ci", +] + +[[package]] +name = "supports-hyperlinks" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "804f44ed3c63152de6a9f90acbea1a110441de43006ea51bcce8f436196a288b" + +[[package]] +name = "supports-unicode" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7401a30af6cb5818bb64852270bb722533397edcfc7344954a38f420819ece2" + [[package]] name = "svgtypes" version = "0.14.0" @@ -818,15 +937,55 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.99" +version = "2.0.109" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e02e925281e18ffd9d640e234264753c43edc62d64b2d4cf898f1bc5e75f3fc2" +checksum = "2f17c7e013e88258aa9543dcbe81aca68a667a9ac37cd69c9fbc07858bfe0e2f" dependencies = [ "proc-macro2", "quote", "unicode-ident", ] +[[package]] +name = "terminal_size" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60b8cb979cb11c32ce1603f8137b22262a9d131aaa5c37b5678025f22b8becd0" +dependencies = [ + "rustix", + "windows-sys 0.60.2", +] + +[[package]] +name = "textwrap" +version = "0.16.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c13547615a44dc9c452a8a534638acdf07120d4b6847c8178705da06306a3057" +dependencies = [ + "unicode-linebreak", + "unicode-width 0.2.2", +] + +[[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 = "tiff" version = "0.9.1" @@ -840,9 +999,9 @@ dependencies = [ [[package]] name = "time" -version = "0.3.39" +version = "0.3.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dad298b01a40a23aac4580b67e3dbedb7cc8402f3592d7f49469de2ea4aecdd8" +checksum = "91e7d9e3bb61134e77bde20dd4825b97c010155709965fedf0f49bb138e52a9d" dependencies = [ "deranged", "itoa", @@ -857,15 +1016,15 @@ dependencies = [ [[package]] name = "time-core" -version = "0.1.3" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "765c97a5b985b7c11d7bc27fa927dc4fe6af3a6dfb021d28deb60d3bf51e76ef" +checksum = "40868e7c1d2f0b8d73e4a8c7f0ff63af4f6d19be117e90bd73eb1d62cf831c6b" [[package]] name = "time-macros" -version = "0.2.20" +version = "0.2.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8093bc3e81c3bc5f7879de09619d06c9a5a5e45ca44dfeeb7225bae38005c5c" +checksum = "30cfb0125f12d9c277f35663a0a33f8c30190f4e4574868a330595412d34ebf3" dependencies = [ "num-conv", "time-core", @@ -899,9 +1058,9 @@ dependencies = [ [[package]] name = "tinyvec" -version = "1.9.0" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09b3661f17e86524eccd4371ab0429194e0d7c008abb45f7a7495b1719463c71" +checksum = "bfa5fdc3bce6191a1dbc8c02d5c8bffcf557bafa17c124c5264a458f1b0613fa" dependencies = [ "tinyvec_macros", ] @@ -912,40 +1071,6 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" -[[package]] -name = "toml" -version = "0.8.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd87a5cdd6ffab733b2f74bc4fd7ee5fff6634124999ac278c35fc78c6120148" -dependencies = [ - "serde", - "serde_spanned", - "toml_datetime", - "toml_edit", -] - -[[package]] -name = "toml_datetime" -version = "0.6.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" -dependencies = [ - "serde", -] - -[[package]] -name = "toml_edit" -version = "0.22.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17b4795ff5edd201c7cd6dca065ae59972ce77d1b80fa0a84d94950ece7d1474" -dependencies = [ - "indexmap", - "serde", - "serde_spanned", - "toml_datetime", - "winnow", -] - [[package]] name = "ttf-parser" version = "0.20.0" @@ -972,15 +1097,21 @@ checksum = "cc2520efa644f8268dce4dcd3050eaa7fc044fca03961e9998ac7e2e92b77cf1" [[package]] name = "unicode-ident" -version = "1.0.18" +version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" +checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5" + +[[package]] +name = "unicode-linebreak" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b09c83c3c29d37506a3e260c08c03743a6bb66a9cd432c6934ab501a190571f" [[package]] name = "unicode-properties" -version = "0.1.3" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e70f2a8b45122e719eb623c01822704c4e0907e7e426a05927e1a1cfff5b75d0" +checksum = "7df058c713841ad818f1dc5d3fd88063241cc61f49f5fbea4b951e8cf5a8d71d" [[package]] name = "unicode-script" @@ -994,6 +1125,18 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b1d386ff53b415b7fe27b50bb44679e2cc4660272694b7b6f3326d8480823a94" +[[package]] +name = "unicode-width" +version = "0.1.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" + +[[package]] +name = "unicode-width" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4ac048d71ede7ee76d585517add45da530660ef4390e49b098733c6e897f254" + [[package]] name = "usvg" version = "0.40.0" @@ -1035,18 +1178,15 @@ checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" [[package]] name = "weezl" -version = "0.1.8" +version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53a85b86a771b1c87058196170769dd264f66c0782acf1ae6cc51bfd64b39082" +checksum = "a751b3277700db47d3e574514de2eced5e54dc8a5436a3bf7a0b248b2cee16f3" [[package]] -name = "windows-sys" -version = "0.48.0" +name = "windows-link" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" -dependencies = [ - "windows-targets 0.48.5", -] +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" [[package]] name = "windows-sys" @@ -1058,18 +1198,21 @@ dependencies = [ ] [[package]] -name = "windows-targets" -version = "0.48.5" +name = "windows-sys" +version = "0.60.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" +dependencies = [ + "windows-targets 0.53.5", +] + +[[package]] +name = "windows-sys" +version = "0.61.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" dependencies = [ - "windows_aarch64_gnullvm 0.48.5", - "windows_aarch64_msvc 0.48.5", - "windows_i686_gnu 0.48.5", - "windows_i686_msvc 0.48.5", - "windows_x86_64_gnu 0.48.5", - "windows_x86_64_gnullvm 0.48.5", - "windows_x86_64_msvc 0.48.5", + "windows-link", ] [[package]] @@ -1081,7 +1224,7 @@ dependencies = [ "windows_aarch64_gnullvm 0.52.6", "windows_aarch64_msvc 0.52.6", "windows_i686_gnu 0.52.6", - "windows_i686_gnullvm", + "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", @@ -1089,10 +1232,21 @@ dependencies = [ ] [[package]] -name = "windows_aarch64_gnullvm" -version = "0.48.5" +name = "windows-targets" +version = "0.53.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" +checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3" +dependencies = [ + "windows-link", + "windows_aarch64_gnullvm 0.53.1", + "windows_aarch64_msvc 0.53.1", + "windows_i686_gnu 0.53.1", + "windows_i686_gnullvm 0.53.1", + "windows_i686_msvc 0.53.1", + "windows_x86_64_gnu 0.53.1", + "windows_x86_64_gnullvm 0.53.1", + "windows_x86_64_msvc 0.53.1", +] [[package]] name = "windows_aarch64_gnullvm" @@ -1101,10 +1255,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" [[package]] -name = "windows_aarch64_msvc" -version = "0.48.5" +name = "windows_aarch64_gnullvm" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" +checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53" [[package]] name = "windows_aarch64_msvc" @@ -1113,10 +1267,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" [[package]] -name = "windows_i686_gnu" -version = "0.48.5" +name = "windows_aarch64_msvc" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" +checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006" [[package]] name = "windows_i686_gnu" @@ -1124,6 +1278,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" +[[package]] +name = "windows_i686_gnu" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3" + [[package]] name = "windows_i686_gnullvm" version = "0.52.6" @@ -1131,10 +1291,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" [[package]] -name = "windows_i686_msvc" -version = "0.48.5" +name = "windows_i686_gnullvm" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" +checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c" [[package]] name = "windows_i686_msvc" @@ -1143,10 +1303,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" [[package]] -name = "windows_x86_64_gnu" -version = "0.48.5" +name = "windows_i686_msvc" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" +checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2" [[package]] name = "windows_x86_64_gnu" @@ -1155,10 +1315,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" [[package]] -name = "windows_x86_64_gnullvm" -version = "0.48.5" +name = "windows_x86_64_gnu" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" +checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499" [[package]] name = "windows_x86_64_gnullvm" @@ -1167,10 +1327,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" [[package]] -name = "windows_x86_64_msvc" -version = "0.48.5" +name = "windows_x86_64_gnullvm" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" +checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1" [[package]] name = "windows_x86_64_msvc" @@ -1179,13 +1339,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] -name = "winnow" -version = "0.7.3" +name = "windows_x86_64_msvc" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e7f4ea97f6f78012141bcdb6a216b2609f0979ada50b20ca5b52dde2eac2bb1" -dependencies = [ - "memchr", -] +checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650" [[package]] name = "xmlwriter" @@ -1193,6 +1350,26 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec7a2a501ed189703dba8b08142f057e887dfc4b2cc4db2d343ac6376ba3e0b9" +[[package]] +name = "zerocopy" +version = "0.8.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0894878a5fa3edfd6da3f88c4805f4c8558e2b996227a3d864f47fe11e38282c" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.8.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88d2b8d9c68ad2b9e4340d7832716a4d21a22a1154777ad56ea55c51a9cf3831" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "zune-inflate" version = "0.2.54" diff --git a/Cargo.toml b/Cargo.toml index beae857..6e8d411 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,9 +22,12 @@ anyhow = "1.0" clap = { version = "4.5.1", features = ["derive"] } image = "0.24.9" log = "0.4.21" +miette = { version = "7.5.0", features = ["fancy"] } +thiserror = "1.0" + qrcode = "0.12" resvg = "0.40.0" simple_logger = "5.0.0" tiny-skia = "0.11.4" -toml = "0.8" + usvg = "0.40.0" diff --git a/README.md b/README.md index 5256c94..1437bab 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # ciphercanvas: Wi-Fi QR Code Generator -A robust and efficient program written in Rust that generates QR codes for Wi-Fi +A robust and efficient command-line tool written in Rust that generates QR codes for Wi-Fi networks. It takes inputs such as SSID, encryption type (WPA or WEP), password, and desired output format, producing a QR code that simplifies Wi-Fi access sharing. @@ -13,19 +13,23 @@ sharing. ## Usage -To generate a Wi-Fi QR code using CipherCanvas: +To generate a Wi-Fi QR code using CipherCanvas, use the `generate` subcommand with the appropriate options: -1. **Create a configuration file**: Follow the guidelines in [the - documentation](docs/configuration.md) to create a configuration file that - includes your Wi-Fi network details. +``` console +$ ciphercanvas generate --ssid MyNetwork --password MyPassword --encryption wpa --output qrcode.png --size 512 --foreground "#000000" --background "#ffffff" +``` -2. **Generate the QR code**: Run the `ccanvas` command with the - appropriate options to generate your QR code. This example command creates a - `qrcode.svg` file based on your configuration: - - ``` console - $ ccanvas -s wifi4life -e wpa -c your-config-file.toml -o qrcode.svg - ``` +Alternatively, you can use a configuration file (e.g., `config.toml`) to specify default values: + +``` console +$ ciphercanvas generate --config ./config.toml --ssid MyNetwork --output qrcode.svg +``` + +To save frequently used settings to the default configuration file: + +``` console +$ ciphercanvas save-settings --settings '[wifi]\nssid="MyNetwork"\n[qrcode]\npassword="MyPassword"' +``` ## Contributing diff --git a/src/error.rs b/src/error.rs new file mode 100644 index 0000000..ec376d7 --- /dev/null +++ b/src/error.rs @@ -0,0 +1,17 @@ +use miette::Diagnostic; +use std::io; +use thiserror::Error; + +#[derive(Error, Debug, Diagnostic)] +pub enum Error { + #[error("QR code generation error: {0}")] + QrCode(String), + #[error("Image processing error: {0}")] + Image(String), + #[error("Unsupported image format: {0}")] + UnsupportedFormat(String), + #[error("File already exists: {0}")] + FileExists(String), + #[error(transparent)] + Io(#[from] io::Error), +} diff --git a/src/get_config.rs b/src/get_config.rs deleted file mode 100644 index 7604238..0000000 --- a/src/get_config.rs +++ /dev/null @@ -1,170 +0,0 @@ -use log::error; -use toml::Value; - -/// Get a string value from the config -/// Returns the default if the value is not found -/// # Example: -/// ```rust -/// use ciphercanvas::get_config_str; -/// let config = toml::from_str(r#" -/// [server] -/// host = "127.0.0.1" -/// "#).unwrap(); -/// let host = get_config_str(&config, "server", "host", "127.0.0.1"); -/// assert_eq!(host, "127.0.0.1"); -/// ``` -pub fn get_config_str<'a>( - config: &'a Value, - key: &str, - second_key: &str, - default: &'a str, -) -> &'a str { - match config.get(key).and_then(|k| k.get(second_key)) { - Some(v) => v.as_str().unwrap_or_else(|| { - panic!( - "Configuration error: Expected a string value for '{}.{}', but found a different type.", - key, second_key - ) - }), - None => { - error!( - "Configuration error: Unable to find the string value for '{}.{}'. Using default: '{}'.", - key, second_key, default - ); - default - } - } -} - -/// Get an integer value from the config -/// Returns the default if the value is not found -/// # Example: -/// ```rust -/// use ciphercanvas::get_config_int; -/// let config = toml::from_str(r#" -/// [server] -/// port = 8080 -/// "#).unwrap(); -/// let port = get_config_int(&config, "server", "port", 8080); -/// assert_eq!(port, 8080); -/// ``` -pub fn get_config_int(config: &Value, key: &str, second_key: &str, default: i64) -> i64 { - config - .get(key) - .and_then(|k| k.get(second_key)) - .and_then(|v| v.as_integer()) - .unwrap_or_else(|| { - error!( - "Configuration error: Unable to find the integer value for '{}.{}'. Using default: '{}'.", - key, second_key, default - ); - default - }) -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn test_get_config_str_found() { - let config = toml::from_str( - r#" - [server] - host = "127.0.0.1" - "#, - ) - .unwrap(); - let host = get_config_str(&config, "server", "host", "localhost"); - assert_eq!(host, "127.0.0.1"); - } - - #[test] - fn test_get_config_str_not_found() { - let config = toml::from_str( - r#" - [server] - port = 8080 - "#, - ) - .unwrap(); - let host = get_config_str(&config, "server", "host", "localhost"); - assert_eq!(host, "localhost"); - } - - #[test] - fn test_get_config_str_default() { - let config = toml::from_str( - r#" - [server] - host = "127.0.0.1" - "#, - ) - .unwrap(); - let host = get_config_str(&config, "server", "host", "localhost"); - assert_eq!(host, "127.0.0.1"); - } - - #[test] - fn test_get_config_int_found() { - let config = toml::from_str( - r#" - [server] - port = 8080 - "#, - ) - .unwrap(); - let port = get_config_int(&config, "server", "port", 8081); - assert_eq!(port, 8080); - } - - #[test] - fn test_get_config_int_not_found() { - let config = toml::from_str( - r#" - [server] - host = "127.0.0.1" - "#, - ) - .unwrap(); - let port = get_config_int(&config, "server", "port", 8081); - assert_eq!(port, 8081); - } - - #[test] - fn test_get_config_int_default() { - let config = toml::from_str( - r#" - [server] - port = 8080 - "#, - ) - .unwrap(); - let port = get_config_int(&config, "server", "port", 8081); - assert_eq!(port, 8080); - } - - #[test] - #[should_panic] - fn test_get_config_str_invalid_type() { - let config = toml::from_str( - r#" - [server] - host = 8080 - "#, - ) - .unwrap(); - get_config_str(&config, "server", "host", "localhost"); - } - - #[test] - #[should_panic] - fn test_get_config_invalid_config() { - let _: toml::Value = toml::from_str( - r#" - i use neovim btw - "#, - ) - .unwrap(); - } -} diff --git a/src/image_ops.rs b/src/image_ops.rs index 092bb0d..2cba397 100644 --- a/src/image_ops.rs +++ b/src/image_ops.rs @@ -1,30 +1,30 @@ -use anyhow::{Context, Result, bail}; +use crate::error::Error; use log::{error, info}; use resvg::render; use std::{ fs::File, - io::{BufWriter, Write}, - path::PathBuf, + io::{BufWriter, prelude::*}, + path::Path, }; use tiny_skia::{Pixmap, Transform}; use usvg::{Options, Tree, fontdb}; -fn load_svg(contents: &[u8], size: u32) -> Result { - info!("Loading SVG content with size {}x{}", size, size); +const SUPPORTED_FORMATS: &[&str] = &["svg", "png"]; + +/// Load and render SVG content into a Pixmap of the specified size. +fn load_svg(contents: &[u8], size: u32) -> Result { + info!("Loading SVG content with size {size}x{size}"); let options = Options::default(); let fontdb = fontdb::Database::new(); - - let tree: Tree = Tree::from_data(contents, &options, &fontdb).with_context(|| { - format!( - "Failed to create SVG tree from data of size {}x{}", - size, size - ) + let tree: Tree = Tree::from_data(contents, &options, &fontdb).map_err(|e| { + Error::Image(format!( + "Failed to create SVG tree from data of size {size}x{size}: {e}" + )) })?; - info!("Successfully created SVG tree"); - let mut pixmap: Pixmap = Pixmap::new(size, size).context("Failed to create a new Pixmap")?; - info!("Created Pixmap of size {}x{}", size, size); + let mut pixmap: Pixmap = + Pixmap::new(size, size).ok_or(Error::Image("Failed to create a new Pixmap".to_string()))?; render(&tree, Transform::default(), &mut pixmap.as_mut()); info!("Rendered SVG to Pixmap"); @@ -32,10 +32,13 @@ fn load_svg(contents: &[u8], size: u32) -> Result { Ok(pixmap) } -/// Save an image to a file -/// Fails when the format is not supported, or when saving fails -/// # Examples: -/// Save an SVG image +/// Save an image to a file. Supports both SVG and PNG output formats. +/// +/// When processing a PNG image, if the requested size is small (<256px), a warning is logged. +/// +/// # Usage Examples +/// +/// Save an SVG image: /// ```rust /// use ciphercanvas::save_image; /// let image = "..."; @@ -45,7 +48,7 @@ fn load_svg(contents: &[u8], size: u32) -> Result { /// save_image(&output, &format, &image, size).unwrap(); /// ``` /// -/// Save a PNG image +/// Save a PNG image: /// ```rust /// use ciphercanvas::save_image; /// let image = "..."; @@ -54,48 +57,53 @@ fn load_svg(contents: &[u8], size: u32) -> Result { /// let output = PathBuf::from("output.png"); /// save_image(&output, &format, &image, size).unwrap(); /// ``` -pub fn save_image(output: &PathBuf, format: &str, image: &str, size: u32) -> Result<()> { - const SUPPORTED_FORMATS: &[&str] = &["svg", "png"]; +pub fn save_image( + output: &Path, + format: &str, + image: &str, + size: u32, + overwrite: bool, +) -> Result<(), Error> { info!( - "Starting to save image with format '{}' to {:?}", - format, output + "Starting to save image with format '{}' to {}", + format, + output.display() ); - let file_path = output.with_extension(if SUPPORTED_FORMATS.contains(&format) { - format - } else { - bail!("Unsupported image format: '{}'", format); - }); + if !SUPPORTED_FORMATS.contains(&format) { + return Err(Error::UnsupportedFormat(format.to_string())); + } + + let file_path = output.with_extension(format); + + if file_path.exists() && !overwrite { + return Err(Error::FileExists(format!( + "File already exists: {}. Use --overwrite to force overwrite.", + file_path.display() + ))); + } match format { "svg" => { - let mut writer = BufWriter::new( - File::create(&file_path) - .with_context(|| format!("Failed to create output file {:?}", file_path))?, - ); - writer - .write_all(image.as_bytes()) - .with_context(|| format!("Failed to write SVG image to file {:?}", file_path))?; - info!("Saved SVG image to {:?}", file_path); + let mut writer = BufWriter::new(File::create(&file_path)?); + writer.write_all(image.as_bytes())?; + info!("Saved SVG image to {}", file_path.display()); } "png" => { if size <= 256 { - error!( - "Warning: Image size is {}x{}, which may result in lower quality.", - size, size - ); + error!("Warning: Image size is {size}x{size}, which may result in lower quality.",); } let pixmap = load_svg(image.as_bytes(), size)?; pixmap .save_png(&file_path) - .with_context(|| format!("Failed to save PNG image to file {:?}", file_path))?; - info!("Saved PNG image to {:?}", file_path); + .map_err(|e| Error::Image(e.to_string()))?; + info!("Saved PNG image to {}", file_path.display()); } _ => { - bail!("Unsupported image format: '{}'", format); + return Err(Error::UnsupportedFormat(format.to_string())); } } - info!("Image saved successfully to {:?}", file_path); + info!("Image saved successfully to {}", file_path.display()); Ok(()) } diff --git a/src/main.rs b/src/main.rs index f7fd3f2..e3b16a1 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,46 +1,71 @@ -use anyhow::{Context, Result}; -use clap::{Parser, ValueEnum}; -use log::{info, warn}; -use qrcode::{EcLevel, QrCode, render::svg}; -use std::{ - fmt, - fs::File, - io::{BufReader, Read}, - path::PathBuf, -}; - -mod get_config; +use clap::{Parser, Subcommand, ValueEnum}; +use log::info; +use std::{fmt, path::PathBuf}; + +mod error; mod image_ops; +mod qr_generator; -use crate::{ - get_config::{get_config_int, get_config_str}, - image_ops::save_image, -}; +use qr_generator::QrCodeOptions; +/// Mature and modular CLI tool to generate QR codes. #[derive(Debug, Parser)] -struct Args { - #[arg(short, long, help = "The WiFi network's SSID (its name)")] - ssid: String, - - #[arg( - short, - long, - default_value = "wpa", - help = "The encryption of the WiFi network." - )] - encryption: Encryption, - - #[arg(short, long, help = "The TOML configuration file.")] - config: PathBuf, +#[command(author, version, about, long_about = None)] +struct CliArgs { + /// Activate verbose mode for detailed logs + #[arg(short, long)] + verbose: bool, - #[arg(short, help = "The output file to export the QR code to.")] - output: PathBuf, + /// Specify subcommand to execute. + #[command(subcommand)] + command: Option, +} - #[arg(short, help = "Enable verbose mode and start logging")] - verbose: bool, +/// List of available subcommands. +#[derive(Debug, Subcommand)] +enum Commands { + /// Generate a QR code image from Wi-Fi credentials. + Generate { + /// The Wi-Fi network's SSID (name) + #[arg(short, long)] + ssid: String, + + /// The encryption type used (WPA, WEP, or None). + #[arg(short, long, default_value = "wpa")] + encryption: Encryption, + + /// The output file to export the QR code image. + #[arg(short, long)] + output: Option, + + /// The Wi-Fi network's password. + #[arg(short, long)] + password: String, + + /// The size of the QR code image (e.g., 512). + #[arg(long, default_value_t = 512)] + size: u32, + + /// The output format of the image (e.g., "svg", "png"). + #[arg(long, default_value = "svg")] + format: String, + + /// The foreground color of the QR code (e.g., "#000000"). + #[arg(long, default_value = "#000000")] + foreground: String, + + /// The background color of the QR code (e.g., "#ffffff")] + #[arg(long, default_value = "#ffffff")] + background: String, + + /// Overwrite existing files without prompt. + #[arg(long, default_value_t = false)] + overwrite: bool, + }, } -#[derive(ValueEnum, Clone, Debug)] +/// Valid encryption types for Wi-Fi. +#[derive(ValueEnum, Clone, Copy, Debug, PartialEq, Eq)] enum Encryption { Wpa, Wep, @@ -54,90 +79,46 @@ impl fmt::Display for Encryption { Encryption::Wep => "WEP", Encryption::None => "nopass", }; - write!(f, "{}", encryption_str) + write!(f, "{encryption_str}") } } -struct Consts; - -impl Consts { - const FORMAT: &'static str = "svg"; - const BACKGROUND: &'static str = "#000000"; - const FOREGROUND: &'static str = "#ffffff"; - const SIZE: u32 = 512; -} - -fn main() -> Result<()> { - let args = Args::parse(); +fn main() -> Result<(), error::Error> { + let args = CliArgs::parse(); if args.verbose { simple_logger::init().unwrap(); - info!("Logger initialized"); + info!("Verbose logging enabled."); } - - info!("Parsed arguments: {:#?}", args); - - let config_str = read_config(&args.config)?; - info!("Configuration file loaded successfully"); - - let toml_config: toml::Value = - toml::from_str(&config_str).context("Failed to parse the TOML configuration file")?; - info!("TOML configuration parsed successfully"); - - let export_format = get_config_str(&toml_config, "qrcode", "export", Consts::FORMAT); - let size = get_config_int(&toml_config, "qrcode", "size", Consts::SIZE as i64) as u32; - - if size < 256 { - warn!("The image size is lower than 256. The resulting QR code may look cropped."); + info!("Parsed arguments: {args:#?}"); + + match args.command { + Some(Commands::Generate { + ssid, + encryption, + output, + password, + size, + format, + foreground, + background, + overwrite, + }) => { + let options = QrCodeOptions { + ssid, + encryption: encryption.to_string(), + password, + output_path: output, + dark_color: foreground.clone(), + light_color: background.clone(), + size, + format: format.clone(), + overwrite, + }; + qr_generator::generate_qr_code(options)?; + } + None => {} } - let foreground = get_config_str(&toml_config, "colors", "foreground", Consts::FOREGROUND); - let background = get_config_str(&toml_config, "colors", "background", Consts::BACKGROUND); - - let password = toml_config["qrcode"]["password"] - .as_str() - .context("Failed to get the password from the configuration file")?; - info!("Password retrieved from the configuration file"); - - let contents_to_encode = format!( - "WIFI:S:{};T:{};P:{};;", - args.ssid, - args.encryption.to_string().to_uppercase(), - password - ); - - let qrcode = QrCode::with_error_correction_level(contents_to_encode.as_bytes(), EcLevel::H) - .context("Failed to generate the QR code")?; - info!("QR code generated successfully"); - - let image = qrcode - .render() - .min_dimensions(size, size) - .dark_color(svg::Color(foreground)) - .light_color(svg::Color(background)) - .build(); - info!("QR code rendered to image"); - - save_image(&args.output, export_format, &image, size)?; - info!("Image saved successfully to {:?}", args.output); - Ok(()) } - -fn read_config(config_path: &PathBuf) -> Result { - info!("Reading configuration file from {:?}", config_path); - - let f = File::open(config_path) - .with_context(|| format!("Failed to open config file '{:?}'", config_path))?; - info!("Configuration file '{:?}' opened successfully", config_path); - - let mut reader = BufReader::new(f); - let mut config_str = String::new(); - - reader - .read_to_string(&mut config_str) - .context("Failed to read the config file")?; - info!("Configuration file read successfully"); - - Ok(config_str) -} diff --git a/src/qr_generator.rs b/src/qr_generator.rs new file mode 100644 index 0000000..ed35f95 --- /dev/null +++ b/src/qr_generator.rs @@ -0,0 +1,56 @@ +use crate::{error::Error, image_ops::save_image}; +use log::{info, warn}; +use miette::Result; +use qrcode::{render::svg, EcLevel, QrCode}; +use std::path::PathBuf; + +pub struct QrCodeOptions { + pub ssid: String, + pub encryption: String, + pub password: String, + pub output_path: Option, + pub dark_color: String, + pub light_color: String, + pub size: u32, + pub format: String, + pub overwrite: bool, +} + +pub fn generate_qr_code(options: QrCodeOptions) -> Result<(), Error> { + if options.size < 256 { + warn!("Image size is lower than 256. The resulting QR code may appear cropped."); + } + + let contents_to_encode = format!( + "WIFI:S:{};T:{};P:{};;", + options.ssid, + options.encryption.to_uppercase(), + options.password + ); + + let qrcode = QrCode::with_error_correction_level(contents_to_encode.as_bytes(), EcLevel::H) + .map_err(|e| Error::QrCode(format!("Failed to generate the QR code: {e}")))?; + info!("QR code generated successfully."); + + let image = qrcode + .render() + .min_dimensions(options.size, options.size) + .dark_color(svg::Color(&options.dark_color)) + .light_color(svg::Color(&options.light_color)) + .build(); + + info!("QR code rendered to image."); + + if let Some(path) = options.output_path { + save_image( + &path, + &options.format, + &image, + options.size, + options.overwrite, + )?; + } else { + println!("{image}"); + } + Ok(()) +}