From 1ed16d8e4ae9920faf36f9737f7ec237db617b7f Mon Sep 17 00:00:00 2001 From: KanjiG Date: Tue, 28 Jul 2026 20:46:51 +0200 Subject: [PATCH] Initial commit: Veritas NFC Tool (Smartcard & NFC Reader GUI Utility) --- .gitignore | 1 + Cargo.lock | 4814 +++++++++++++++++++++++++++++++++++++++++++++ Cargo.toml | 15 + src/acr122u.rs | 230 +++ src/gui.rs | 32 + src/main.rs | 692 +++++++ src/mifare.rs | 178 ++ src/ndef.rs | 168 ++ src/ntag.rs | 67 + src/server.rs | 445 +++++ static/index.html | 709 +++++++ 11 files changed, 7351 insertions(+) create mode 100644 .gitignore create mode 100644 Cargo.lock create mode 100644 Cargo.toml create mode 100644 src/acr122u.rs create mode 100644 src/gui.rs create mode 100644 src/main.rs create mode 100644 src/mifare.rs create mode 100644 src/ndef.rs create mode 100644 src/ntag.rs create mode 100644 src/server.rs create mode 100644 static/index.html 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..6d6fb6c --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,4814 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "ab_glyph" +version = "0.2.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01c0457472c38ea5bd1c3b5ada5e368271cb550be7a4ca4a0b4634e9913f6cc2" +dependencies = [ + "ab_glyph_rasterizer", + "owned_ttf_parser", +] + +[[package]] +name = "ab_glyph_rasterizer" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "366ffbaa4442f4684d91e2cd7c5ea7c4ed8add41959a31447066e279e432b618" + +[[package]] +name = "accesskit" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74a4b14f3d99c1255dcba8f45621ab1a2e7540a0009652d33989005a4d0bfc6b" + +[[package]] +name = "accesskit_consumer" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c17cca53c09fbd7288667b22a201274b9becaa27f0b91bf52a526db95de45e6" +dependencies = [ + "accesskit", +] + +[[package]] +name = "accesskit_macos" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd3b6ae1eabbfbced10e840fd3fce8a93ae84f174b3e4ba892ab7bcb42e477a7" +dependencies = [ + "accesskit", + "accesskit_consumer", + "objc2 0.3.0-beta.3.patch-leaks.3", + "once_cell", +] + +[[package]] +name = "accesskit_unix" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09f46c18d99ba61ad7123dd13eeb0c104436ab6af1df6a1cd8c11054ed394a08" +dependencies = [ + "accesskit", + "accesskit_consumer", + "async-channel", + "async-once-cell", + "atspi", + "futures-lite 1.13.0", + "once_cell", + "serde", + "zbus 3.15.2", +] + +[[package]] +name = "accesskit_windows" +version = "0.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "afcae27ec0974fc7c3b0b318783be89fd1b2e66dd702179fe600166a38ff4a0b" +dependencies = [ + "accesskit", + "accesskit_consumer", + "once_cell", + "paste", + "static_assertions", + "windows 0.48.0", +] + +[[package]] +name = "accesskit_winit" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5284218aca17d9e150164428a0ebc7b955f70e3a9a78b4c20894513aabf98a67" +dependencies = [ + "accesskit", + "accesskit_macos", + "accesskit_unix", + "accesskit_windows", + "winit", +] + +[[package]] +name = "adler2" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" + +[[package]] +name = "ahash" +version = "0.8.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a15f179cd60c4584b8a8c596927aadc462e27f2ca70c04e0071964a73ba7a75" +dependencies = [ + "cfg-if", + "getrandom 0.3.4", + "once_cell", + "version_check", + "zerocopy", +] + +[[package]] +name = "aho-corasick" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" +dependencies = [ + "memchr", +] + +[[package]] +name = "android-activity" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee91c0c2905bae44f84bfa4e044536541df26b7703fd0888deeb9060fcc44289" +dependencies = [ + "android-properties", + "bitflags 2.13.1", + "cc", + "cesu8", + "jni 0.21.1", + "jni-sys 0.3.1", + "libc", + "log", + "ndk", + "ndk-context", + "ndk-sys", + "num_enum", + "thiserror 1.0.69", +] + +[[package]] +name = "android-properties" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc7eb209b1518d6bb87b283c20095f5228ecda460da70b44f0802523dea6da04" + +[[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 = "anyhow" +version = "1.0.104" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "330a5ed07fa54e4702c9d6c4174f74427fc0ef6e214bbd677ae50a5099946470" + +[[package]] +name = "arboard" +version = "3.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0348a1c054491f4bfe6ab86a7b6ab1e44e45d899005de92f58b3df180b36ddaf" +dependencies = [ + "clipboard-win", + "log", + "objc2 0.6.4", + "objc2-app-kit 0.3.2", + "objc2-foundation 0.3.2", + "parking_lot", + "percent-encoding", + "windows-sys 0.60.2", + "x11rb", +] + +[[package]] +name = "arrayref" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76a2e8124351fda1ef8aaaa3bbd7ebbcb486bbcd4225aca0aa0d84bb2db8fecb" + +[[package]] +name = "arrayvec" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3fb67a6e08acf24fdeccbac2cb6ac4305825bd1f117462e0e6f2f193345ad56" + +[[package]] +name = "as-raw-xcb-connection" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "175571dd1d178ced59193a6fc02dde1b972eb0bc56c892cde9beeceac5bf0f6b" + +[[package]] +name = "ash" +version = "0.37.3+1.3.251" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39e9c3835d686b0a6084ab4234fcd1b07dbf6e4767dce60874b12356a25ecd4a" +dependencies = [ + "libloading 0.7.4", +] + +[[package]] +name = "ashpd" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3af990a617932d416e83cf79e7335dd5247dcb0825995ca3274c17dab5b749d" +dependencies = [ + "async-fs 2.2.0", + "async-net", + "enumflags2", + "futures-channel", + "futures-util", + "rand", + "serde", + "serde_repr", + "url", + "zbus 4.4.0", +] + +[[package]] +name = "async-broadcast" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c48ccdbf6ca6b121e0f586cbc0e73ae440e56c67c30fa0873b4e110d9c26d2b" +dependencies = [ + "event-listener 2.5.3", + "futures-core", +] + +[[package]] +name = "async-broadcast" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "435a87a52755b8f27fcf321ac4f04b2802e337c8c4872923137471ec39c37532" +dependencies = [ + "event-listener 5.4.2", + "event-listener-strategy", + "futures-core", + "pin-project-lite", +] + +[[package]] +name = "async-channel" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "924ed96dd52d1b75e9c1a3e6275715fd320f5f9439fb5a4a11fa51f4221158d2" +dependencies = [ + "concurrent-queue", + "event-listener-strategy", + "futures-core", + "pin-project-lite", +] + +[[package]] +name = "async-executor" +version = "1.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c96bf972d85afc50bf5ab8fe2d54d1586b4e0b46c97c50a0c9e71e2f7bcd812a" +dependencies = [ + "async-task", + "concurrent-queue", + "fastrand 2.5.0", + "futures-lite 2.6.1", + "pin-project-lite", + "slab", +] + +[[package]] +name = "async-fs" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "279cf904654eeebfa37ac9bb1598880884924aab82e290aa65c9e77a0e142e06" +dependencies = [ + "async-lock 2.8.0", + "autocfg", + "blocking", + "futures-lite 1.13.0", +] + +[[package]] +name = "async-fs" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8034a681df4aed8b8edbd7fbe472401ecf009251c8b40556b304567052e294c5" +dependencies = [ + "async-lock 3.4.2", + "blocking", + "futures-lite 2.6.1", +] + +[[package]] +name = "async-io" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fc5b45d93ef0529756f812ca52e44c221b35341892d3dcc34132ac02f3dd2af" +dependencies = [ + "async-lock 2.8.0", + "autocfg", + "cfg-if", + "concurrent-queue", + "futures-lite 1.13.0", + "log", + "parking", + "polling 2.8.0", + "rustix 0.37.28", + "slab", + "socket2", + "waker-fn", +] + +[[package]] +name = "async-io" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "456b8a8feb6f42d237746d4b3e9a178494627745c3c56c6ea55d92ba50d026fc" +dependencies = [ + "autocfg", + "cfg-if", + "concurrent-queue", + "futures-io", + "futures-lite 2.6.1", + "parking", + "polling 3.11.0", + "rustix 1.1.4", + "slab", + "windows-sys 0.61.2", +] + +[[package]] +name = "async-lock" +version = "2.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "287272293e9d8c41773cec55e365490fe034813a2f172f502d6ddcf75b2f582b" +dependencies = [ + "event-listener 2.5.3", +] + +[[package]] +name = "async-lock" +version = "3.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "290f7f2596bd5b78a9fec8088ccd89180d7f9f55b94b0576823bbbdc72ee8311" +dependencies = [ + "event-listener 5.4.2", + "event-listener-strategy", + "pin-project-lite", +] + +[[package]] +name = "async-net" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b948000fad4873c1c9339d60f2623323a0cfd3816e5181033c6a5cb68b2accf7" +dependencies = [ + "async-io 2.6.0", + "blocking", + "futures-lite 2.6.1", +] + +[[package]] +name = "async-once-cell" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4288f83726785267c6f2ef073a3d83dc3f9b81464e9f99898240cced85fce35a" + +[[package]] +name = "async-process" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea6438ba0a08d81529c69b36700fa2f95837bfe3e776ab39cde9c14d9149da88" +dependencies = [ + "async-io 1.13.0", + "async-lock 2.8.0", + "async-signal", + "blocking", + "cfg-if", + "event-listener 3.1.0", + "futures-lite 1.13.0", + "rustix 0.38.44", + "windows-sys 0.48.0", +] + +[[package]] +name = "async-process" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc50921ec0055cdd8a16de48773bfeec5c972598674347252c0399676be7da75" +dependencies = [ + "async-channel", + "async-io 2.6.0", + "async-lock 3.4.2", + "async-signal", + "async-task", + "blocking", + "cfg-if", + "event-listener 5.4.2", + "futures-lite 2.6.1", + "rustix 1.1.4", +] + +[[package]] +name = "async-recursion" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b43422f69d8ff38f95f1b2bb76517c91589a924d1559a0e935d7c8ce0274c11" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "async-signal" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52b5aaafa020cf5053a01f2a60e8ff5dccf550f0f77ec54a4e47285ac2bab485" +dependencies = [ + "async-io 2.6.0", + "async-lock 3.4.2", + "atomic-waker", + "cfg-if", + "futures-core", + "futures-io", + "rustix 1.1.4", + "signal-hook-registry", + "slab", + "windows-sys 0.61.2", +] + +[[package]] +name = "async-task" +version = "4.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b75356056920673b02621b35afd0f7dda9306d03c79a30f5c56c44cf256e3de" + +[[package]] +name = "async-trait" +version = "0.1.91" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae36dc4177970ef04fde5178d3e2429882def40e57a451f919c098f72baa6cec" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.3", +] + +[[package]] +name = "atomic-waker" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" + +[[package]] +name = "atspi" +version = "0.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6059f350ab6f593ea00727b334265c4dfc7fd442ee32d264794bd9bdc68e87ca" +dependencies = [ + "atspi-common", + "atspi-connection", + "atspi-proxies", +] + +[[package]] +name = "atspi-common" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92af95f966d2431f962bc632c2e68eda7777330158bf640c4af4249349b2cdf5" +dependencies = [ + "enumflags2", + "serde", + "static_assertions", + "zbus 3.15.2", + "zbus_names 2.6.1", + "zvariant 3.15.2", +] + +[[package]] +name = "atspi-connection" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0c65e7d70f86d4c0e3b2d585d9bf3f979f0b19d635a336725a88d279f76b939" +dependencies = [ + "atspi-common", + "atspi-proxies", + "futures-lite 1.13.0", + "zbus 3.15.2", +] + +[[package]] +name = "atspi-proxies" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6495661273703e7a229356dcbe8c8f38223d697aacfaf0e13590a9ac9977bb52" +dependencies = [ + "atspi-common", + "serde", + "zbus 3.15.2", +] + +[[package]] +name = "autocfg" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2032f911046de80f0a198e0901378627c33f59ea0ac00e363d481118bd70a53" + +[[package]] +name = "bit-set" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0700ddab506f33b20a03b13996eccd309a48e5ff77d0d95926aa0210fb4e95f1" +dependencies = [ + "bit-vec", +] + +[[package]] +name = "bit-vec" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bitflags" +version = "2.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b588b76d00fde79687d7646a9b5bdf3cc0f655e0bbd080335a95d7e96f3587da" + +[[package]] +name = "block" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a" + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "block-sys" +version = "0.1.0-beta.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fa55741ee90902547802152aaf3f8e5248aab7e21468089560d4c8840561146" +dependencies = [ + "objc-sys 0.2.0-beta.2", +] + +[[package]] +name = "block-sys" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae85a0696e7ea3b835a453750bf002770776609115e6d25c6d2ff28a8200f7e7" +dependencies = [ + "objc-sys 0.3.5", +] + +[[package]] +name = "block2" +version = "0.2.0-alpha.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8dd9e63c1744f755c2f60332b88de39d341e5e86239014ad839bd71c106dec42" +dependencies = [ + "block-sys 0.1.0-beta.1", + "objc2-encode 2.0.0-pre.2", +] + +[[package]] +name = "block2" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "15b55663a85f33501257357e6421bb33e769d5c9ffb5ba0921c975a123e35e68" +dependencies = [ + "block-sys 0.2.1", + "objc2 0.4.1", +] + +[[package]] +name = "block2" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c132eebf10f5cad5289222520a4a058514204aed6d791f1cf4fe8088b82d15f" +dependencies = [ + "objc2 0.5.2", +] + +[[package]] +name = "blocking" +version = "1.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e83f8d02be6967315521be875afa792a316e28d57b5a2d401897e2a7921b7f21" +dependencies = [ + "async-channel", + "async-task", + "futures-io", + "futures-lite 2.6.1", + "piper", +] + +[[package]] +name = "bumpalo" +version = "3.20.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72f5acc6cb2ba439de613abc23857ec3d78374d8ed5ac84e9d11336e87da8649" + +[[package]] +name = "bytemuck" +version = "1.25.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95832e849adfb21180ccb6826a99da14e5d266ae5c2e668e1602cf234f153797" +dependencies = [ + "bytemuck_derive", +] + +[[package]] +name = "bytemuck_derive" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f65693059b6b9c588b9f62fed1cedbf0a8b805631457ea162d68f0de186f3de5" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "byteorder-lite" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f1fe948ff07f4bd06c30984e69f5b4899c516a3ef74f34df92a2df2ab535495" + +[[package]] +name = "bytes" +version = "1.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc652a48c352aef3ea3aed32080501cf3ef6ed5da78602a020c991775b0aff04" + +[[package]] +name = "calloop" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fba7adb4dd5aa98e5553510223000e7148f621165ec5f9acd7113f6ca4995298" +dependencies = [ + "bitflags 2.13.1", + "log", + "polling 3.11.0", + "rustix 0.38.44", + "slab", + "thiserror 1.0.69", +] + +[[package]] +name = "calloop" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4dbf9978365bac10f54d1d4b04f7ce4427e51f71d61f2fe15e3fed5166474df7" +dependencies = [ + "bitflags 2.13.1", + "polling 3.11.0", + "rustix 1.1.4", + "slab", + "tracing", +] + +[[package]] +name = "calloop-wayland-source" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f0ea9b9476c7fad82841a8dbb380e2eae480c21910feba80725b46931ed8f02" +dependencies = [ + "calloop 0.12.4", + "rustix 0.38.44", + "wayland-backend", + "wayland-client", +] + +[[package]] +name = "calloop-wayland-source" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "138efcf0940a02ebf0cc8d1eff41a1682a46b431630f4c52450d6265876021fa" +dependencies = [ + "calloop 0.14.4", + "rustix 1.1.4", + "wayland-backend", + "wayland-client", +] + +[[package]] +name = "cc" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5add81bb678e6cb321aff7fa0dc7689ad82b112dbc032cea19f91d6b8e3582b9" +dependencies = [ + "find-msvc-tools", + "jobserver", + "libc", + "shlex", +] + +[[package]] +name = "cesu8" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c" + +[[package]] +name = "cfg-if" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" + +[[package]] +name = "cfg_aliases" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e" + +[[package]] +name = "cfg_aliases" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f079e83a288787bcd14a6aea84cee5c87a67c5a3e660c30f557a3d24761b3527" + +[[package]] +name = "cgl" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ced0551234e87afee12411d535648dd89d2e7f34c78b753395567aff3d447ff" +dependencies = [ + "libc", +] + +[[package]] +name = "chrono" +version = "0.4.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1aa79e62e7697b8e29b513a68abacf485adcd1fe8284a4316c5ae868e6633327" +dependencies = [ + "iana-time-zone", + "js-sys", + "num-traits", + "wasm-bindgen", + "windows-link", +] + +[[package]] +name = "clipboard-win" +version = "5.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bde03770d3df201d4fb868f2c9c59e66a3e4e2bd06692a0fe701e7103c7e84d4" +dependencies = [ + "error-code", +] + +[[package]] +name = "codespan-reporting" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3538270d33cc669650c4b093848450d380def10c331d38c768e34cac80576e6e" +dependencies = [ + "termcolor", + "unicode-width", +] + +[[package]] +name = "com" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e17887fd17353b65b1b2ef1c526c83e26cd72e74f598a8dc1bee13a48f3d9f6" +dependencies = [ + "com_macros", +] + +[[package]] +name = "com_macros" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d375883580a668c7481ea6631fc1a8863e33cc335bf56bfad8d7e6d4b04b13a5" +dependencies = [ + "com_macros_support", + "proc-macro2", + "syn 1.0.109", +] + +[[package]] +name = "com_macros_support" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad899a1087a9296d5644792d7cb72b8e34c1bec8e7d4fbc002230169a6e8710c" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "combine" +version = "4.6.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba5a308b75df32fe02788e748662718f03fde005016435c444eea572398219fd" +dependencies = [ + "bytes", + "memchr", +] + +[[package]] +name = "concurrent-queue" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "core-foundation" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2a6cd9ae233e7f62ba4e9353e81a88df7fc8a5987b8d445b4d90c879bd156f6" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" + +[[package]] +name = "core-graphics" +version = "0.23.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c07782be35f9e1140080c6b96f0d44b739e2278479f64e02fdab4e32dfd8b081" +dependencies = [ + "bitflags 1.3.2", + "core-foundation 0.9.4", + "core-graphics-types", + "foreign-types", + "libc", +] + +[[package]] +name = "core-graphics-types" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45390e6114f68f718cc7a830514a96f903cccd70d02a8f6d9f643ac4ba45afaf" +dependencies = [ + "bitflags 1.3.2", + "core-foundation 0.9.4", + "libc", +] + +[[package]] +name = "cpufeatures" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" +dependencies = [ + "libc", +] + +[[package]] +name = "crc32fast" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61803da095bee82a81bb1a452ecc25d3b2f1416d1897eb86430c6159ef717c17" + +[[package]] +name = "crypto-common" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "cursor-icon" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f27ae1dd37df86211c42e150270f82743308803d90a6f6e6651cd730d5e1732f" + +[[package]] +name = "derivative" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "crypto-common", +] + +[[package]] +name = "dispatch" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd0c93bb4b0c6d9b77f4435b0ae98c24d17f1c45b2ff844c6151a07256ca923b" + +[[package]] +name = "dispatch2" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e0e367e4e7da84520dedcac1901e4da967309406d1e51017ae1abfb97adbd38" +dependencies = [ + "bitflags 2.13.1", + "objc2 0.6.4", +] + +[[package]] +name = "displaydoc" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ac70aa55017e108007fbaf5aa0f54b021c98f92ff8af59d42eda9da96e3dd4f" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "dlib" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab8ecd87370524b461f8557c119c405552c396ed91fc0a8eec68679eab26f94a" +dependencies = [ + "libloading 0.8.9", +] + +[[package]] +name = "document-features" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4b8a88685455ed29a21542a33abd9cb6510b6b129abadabdcef0f4c55bc8f61" +dependencies = [ + "litrs", +] + +[[package]] +name = "downcast-rs" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75b325c5dbd37f80359721ad39aca5a29fb04c89279657cffdda8736d0c0b9d2" + +[[package]] +name = "ecolor" +version = "0.28.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e6b451ff1143f6de0f33fc7f1b68fecfd2c7de06e104de96c4514de3f5396f8" +dependencies = [ + "bytemuck", + "emath", +] + +[[package]] +name = "eframe" +version = "0.28.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6490ef800b2e41ee129b1f32f9ac15f713233fe3bc18e241a1afe1e4fb6811e0" +dependencies = [ + "ahash", + "bytemuck", + "document-features", + "egui", + "egui-wgpu", + "egui-winit", + "egui_glow", + "glow", + "glutin", + "glutin-winit", + "image", + "js-sys", + "log", + "objc2 0.5.2", + "objc2-app-kit 0.2.2", + "objc2-foundation 0.2.2", + "parking_lot", + "percent-encoding", + "raw-window-handle 0.5.2", + "raw-window-handle 0.6.2", + "static_assertions", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "web-time", + "winapi", + "winit", +] + +[[package]] +name = "egui" +version = "0.28.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20c97e70a2768de630f161bb5392cbd3874fcf72868f14df0e002e82e06cb798" +dependencies = [ + "accesskit", + "ahash", + "emath", + "epaint", + "log", + "nohash-hasher", +] + +[[package]] +name = "egui-wgpu" +version = "0.28.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47c7a7c707877c3362a321ebb4f32be811c0b91f7aebf345fb162405c0218b4c" +dependencies = [ + "ahash", + "bytemuck", + "document-features", + "egui", + "epaint", + "log", + "thiserror 1.0.69", + "type-map", + "web-time", + "wgpu", + "winit", +] + +[[package]] +name = "egui-winit" +version = "0.28.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fac4e066af341bf92559f60dbdf2020b2a03c963415349af5f3f8d79ff7a4926" +dependencies = [ + "accesskit_winit", + "ahash", + "arboard", + "egui", + "log", + "raw-window-handle 0.6.2", + "smithay-clipboard", + "web-time", + "webbrowser", + "winit", +] + +[[package]] +name = "egui_glow" +version = "0.28.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e2bdc8b38cfa17cc712c4ae079e30c71c00cd4c2763c9e16dc7860a02769103" +dependencies = [ + "ahash", + "bytemuck", + "egui", + "glow", + "log", + "memoffset 0.9.1", + "wasm-bindgen", + "web-sys", + "winit", +] + +[[package]] +name = "emath" +version = "0.28.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a6a21708405ea88f63d8309650b4d77431f4bc28fb9d8e6f77d3963b51249e6" +dependencies = [ + "bytemuck", +] + +[[package]] +name = "endi" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "66b7e2430c6dff6a955451e2cfc438f09cea1965a9d6f87f7e3b90decc014099" + +[[package]] +name = "enumflags2" +version = "0.7.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1027f7680c853e056ebcec683615fb6fbbc07dbaa13b4d5d9442b146ded4ecef" +dependencies = [ + "enumflags2_derive", + "serde", +] + +[[package]] +name = "enumflags2_derive" +version = "0.7.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67c78a4d8fdf9953a5c9d458f9efe940fd97a0cab0941c075a813ac594733827" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "epaint" +version = "0.28.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f0dcc0a0771e7500e94cd1cb797bd13c9f23b9409bdc3c824e2cbc562b7fa01" +dependencies = [ + "ab_glyph", + "ahash", + "bytemuck", + "ecolor", + "emath", + "log", + "nohash-hasher", + "parking_lot", +] + +[[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + +[[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.2", +] + +[[package]] +name = "error-code" +version = "3.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dea2df4cf52843e0452895c455a1a2cfbb842a1e7329671acf418fdc53ed4c59" + +[[package]] +name = "event-listener" +version = "2.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" + +[[package]] +name = "event-listener" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d93877bcde0eb80ca09131a08d23f0a5c18a620b01db137dba666d18cd9b30c2" +dependencies = [ + "concurrent-queue", + "parking", + "pin-project-lite", +] + +[[package]] +name = "event-listener" +version = "5.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a23add41df1562121a9393cb065eab5146a1242410f23a644851e90cfd669d2" +dependencies = [ + "parking", + "pin-project-lite", +] + +[[package]] +name = "event-listener-strategy" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8be9f3dfaaffdae2972880079a491a1a8bb7cbed0b8dd7a347f668b4150a3b93" +dependencies = [ + "event-listener 5.4.2", + "pin-project-lite", +] + +[[package]] +name = "fastrand" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e51093e27b0797c359783294ca4f0a911c270184cb10f85783b118614a1501be" +dependencies = [ + "instant", +] + +[[package]] +name = "fastrand" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da7c62ceae207dd37ea5b845da6a0696c799f85e97da1ab5b7910be3c1c80223" + +[[package]] +name = "fdeflate" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e6853b52649d4ac5c0bd02320cddc5ba956bdb407c4b75a2c6b75bf51500f8c" +dependencies = [ + "simd-adler32", +] + +[[package]] +name = "find-msvc-tools" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" + +[[package]] +name = "flate2" +version = "1.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "843fba2746e448b37e26a819579957415c8cef339bf08564fe8b7ddbd959573c" +dependencies = [ + "crc32fast", + "miniz_oxide", +] + +[[package]] +name = "foldhash" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" + +[[package]] +name = "foreign-types" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d737d9aa519fb7b749cbc3b962edcf310a8dd1f4b67c91c4f83975dbdd17d965" +dependencies = [ + "foreign-types-macros", + "foreign-types-shared", +] + +[[package]] +name = "foreign-types-macros" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea5190182e6915eb873ddbc16e23b711b6eb1f9c00a0d0a3a91b5f6228475225" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.3", +] + +[[package]] +name = "foreign-types-shared" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa9a19cbb55df58761df49b23516a86d432839add4af60fc256da840f66ed35b" + +[[package]] +name = "form_urlencoded" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "futures-channel" +version = "0.3.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "262590f4fe6afeb0bc83be1daa64e52657fe185690a958af7f3ad0e92085c5ae" +dependencies = [ + "futures-core", +] + +[[package]] +name = "futures-core" +version = "0.3.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2cd50c473c80f6d7c3670a752354b8e569b1a7cbfdc0419ec88e5edad85e0dc7" + +[[package]] +name = "futures-io" +version = "0.3.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4577ecaa3c4f96589d473f679a71b596316f6641bc350038b962a5daf0085d7a" + +[[package]] +name = "futures-lite" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49a9d51ce47660b1e808d3c990b4709f2f415d928835a17dfd16991515c46bce" +dependencies = [ + "fastrand 1.9.0", + "futures-core", + "futures-io", + "memchr", + "parking", + "pin-project-lite", + "waker-fn", +] + +[[package]] +name = "futures-lite" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f78e10609fe0e0b3f4157ffab1876319b5b0db102a2c60dc4626306dc46b44ad" +dependencies = [ + "fastrand 2.5.0", + "futures-core", + "futures-io", + "parking", + "pin-project-lite", +] + +[[package]] +name = "futures-macro" +version = "0.3.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d6d3cde68c518367be28956066ddfef33813991b77a55005a69dae04bf3b10b" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "futures-sink" +version = "0.3.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e34418ac499d6305c2fb5ad0ed2f6ac998c5f8ca209b4510f7f94242c647e307" + +[[package]] +name = "futures-task" +version = "0.3.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b231ed28831efb4a61a08580c4bc233ec56bc009f4cd8f52da2c3cb97df0c109" + +[[package]] +name = "futures-util" +version = "0.3.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a77a90a256fce34da66415271e30f94ee91c57b04b8a2c042d9cf3220179deaa" +dependencies = [ + "futures-core", + "futures-io", + "futures-macro", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "slab", +] + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "gethostname" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bd49230192a3797a9a4d6abe9b3eed6f7fa4c8a8a4947977c6f80025f92cbd8" +dependencies = [ + "rustix 1.1.4", + "windows-link", +] + +[[package]] +name = "getrandom" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "getrandom" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" +dependencies = [ + "cfg-if", + "libc", + "r-efi 5.3.0", + "wasip2", +] + +[[package]] +name = "getrandom" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "300e883d756b2e4ec94e02791f39b04b522276138852cfc41d9fb7e904106099" +dependencies = [ + "cfg-if", + "libc", + "r-efi 6.0.0", +] + +[[package]] +name = "gl_generator" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a95dfc23a2b4a9a2f5ab41d194f8bfda3cabec42af4e39f08c339eb2a0c124d" +dependencies = [ + "khronos_api", + "log", + "xml-rs", +] + +[[package]] +name = "glow" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd348e04c43b32574f2de31c8bb397d96c9fcfa1371bd4ca6d8bdc464ab121b1" +dependencies = [ + "js-sys", + "slotmap", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "glutin" +version = "0.31.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18fcd4ae4e86d991ad1300b8f57166e5be0c95ef1f63f3f5b827f8a164548746" +dependencies = [ + "bitflags 2.13.1", + "cfg_aliases 0.1.1", + "cgl", + "core-foundation 0.9.4", + "dispatch", + "glutin_egl_sys", + "glutin_glx_sys", + "glutin_wgl_sys", + "icrate", + "libloading 0.8.9", + "objc2 0.4.1", + "once_cell", + "raw-window-handle 0.5.2", + "wayland-sys", + "windows-sys 0.48.0", + "x11-dl", +] + +[[package]] +name = "glutin-winit" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ebcdfba24f73b8412c5181e56f092b5eff16671c514ce896b258a0a64bd7735" +dependencies = [ + "cfg_aliases 0.1.1", + "glutin", + "raw-window-handle 0.5.2", + "winit", +] + +[[package]] +name = "glutin_egl_sys" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77cc5623f5309ef433c3dd4ca1223195347fe62c413da8e2fdd0eb76db2d9bcd" +dependencies = [ + "gl_generator", + "windows-sys 0.48.0", +] + +[[package]] +name = "glutin_glx_sys" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a165fd686c10dcc2d45380b35796e577eacfd43d4660ee741ec8ebe2201b3b4f" +dependencies = [ + "gl_generator", + "x11-dl", +] + +[[package]] +name = "glutin_wgl_sys" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c8098adac955faa2d31079b65dc48841251f69efd3ac25477903fc424362ead" +dependencies = [ + "gl_generator", +] + +[[package]] +name = "gpu-alloc" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45cf04b2726f02df5508c6de726acdc90cdf97ac771a9a0ffd8ba10a6e696bf9" +dependencies = [ + "bitflags 2.13.1", + "gpu-alloc-types", +] + +[[package]] +name = "gpu-alloc-types" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2bbed164dd10ed526c2e4fe3e721ca4a71c61730e5aafac6844b417b3227058" +dependencies = [ + "bitflags 2.13.1", +] + +[[package]] +name = "gpu-allocator" +version = "0.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f56f6318968d03c18e1bcf4857ff88c61157e9da8e47c5f29055d60e1228884" +dependencies = [ + "log", + "presser", + "thiserror 1.0.69", + "winapi", + "windows 0.52.0", +] + +[[package]] +name = "gpu-descriptor" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b89c83349105e3732062a895becfc71a8f921bb71ecbbdd8ff99263e3b53a0ca" +dependencies = [ + "bitflags 2.13.1", + "gpu-descriptor-types", + "hashbrown 0.15.5", +] + +[[package]] +name = "gpu-descriptor-types" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fdf242682df893b86f33a73828fb09ca4b2d3bb6cc95249707fc684d27484b91" +dependencies = [ + "bitflags 2.13.1", +] + +[[package]] +name = "hashbrown" +version = "0.15.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" +dependencies = [ + "foldhash", +] + +[[package]] +name = "hashbrown" +version = "0.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a" + +[[package]] +name = "hassle-rs" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af2a7e73e1f34c48da31fb668a907f250794837e08faa144fd24f0b8b741e890" +dependencies = [ + "bitflags 2.13.1", + "com", + "libc", + "libloading 0.8.9", + "thiserror 1.0.69", + "widestring", + "winapi", +] + +[[package]] +name = "hermit-abi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" + +[[package]] +name = "hermit-abi" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c" + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "hexf-parse" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfa686283ad6dd069f105e5ab091b04c62850d3e4cf5d67debad1933f55023df" + +[[package]] +name = "iana-time-zone" +version = "0.1.65" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e31bc9ad994ba00e440a8aa5c9ef0ec67d5cb5e5cb0cc7f8b744a35b389cc470" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "log", + "wasm-bindgen", + "windows-core 0.62.2", +] + +[[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 = "icrate" +version = "0.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99d3aaff8a54577104bafdf686ff18565c3b6903ca5782a2026ef06e2c7aa319" +dependencies = [ + "block2 0.3.0", + "dispatch", + "objc2 0.4.1", +] + +[[package]] +name = "icu_collections" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2984d1cd16c883d7935b9e07e44071dca8d917fd52ecc02c04d5fa0b5a3f191c" +dependencies = [ + "displaydoc", + "potential_utf", + "utf8_iter", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_locale_core" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92219b62b3e2b4d88ac5119f8904c10f8f61bf7e95b640d25ba3075e6cac2c29" +dependencies = [ + "displaydoc", + "litemap", + "tinystr", + "writeable", + "zerovec", +] + +[[package]] +name = "icu_normalizer" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c56e5ee99d6e3d33bd91c5d85458b6005a22140021cc324cea84dd0e72cff3b4" +dependencies = [ + "icu_collections", + "icu_normalizer_data", + "icu_properties", + "icu_provider", + "smallvec", + "zerovec", +] + +[[package]] +name = "icu_normalizer_data" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da3be0ae77ea334f4da67c12f149704f19f81d1adf7c51cf482943e84a2bad38" + +[[package]] +name = "icu_properties" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bee3b67d0ea5c2cca5003417989af8996f8604e34fb9ddf96208a033901e70de" +dependencies = [ + "icu_collections", + "icu_locale_core", + "icu_properties_data", + "icu_provider", + "zerotrie", + "zerovec", +] + +[[package]] +name = "icu_properties_data" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e2bbb201e0c04f7b4b3e14382af113e17ba4f63e2c9d2ee626b720cbce54a14" + +[[package]] +name = "icu_provider" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "139c4cf31c8b5f33d7e199446eff9c1e02decfc2f0eec2c8d71f65befa45b421" +dependencies = [ + "displaydoc", + "icu_locale_core", + "writeable", + "yoke", + "zerofrom", + "zerotrie", + "zerovec", +] + +[[package]] +name = "idna" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de" +dependencies = [ + "idna_adapter", + "smallvec", + "utf8_iter", +] + +[[package]] +name = "idna_adapter" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb68373c0d6620ef8105e855e7745e18b0d00d3bdb07fb532e434244cdb9a714" +dependencies = [ + "icu_normalizer", + "icu_properties", +] + +[[package]] +name = "image" +version = "0.25.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85ab80394333c02fe689eaf900ab500fbd0c2213da414687ebf995a65d5a6104" +dependencies = [ + "bytemuck", + "byteorder-lite", + "moxcms", + "num-traits", + "png", +] + +[[package]] +name = "indexmap" +version = "2.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d466e9454f08e4a911e14806c24e16fba1b4c121d1ea474396f396069cf949d9" +dependencies = [ + "equivalent", + "hashbrown 0.17.1", +] + +[[package]] +name = "instant" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0242819d153cba4b4b05a5a8f2a7e9bbf97b6055b2a002b395c96b5ff3c0222" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "io-lifetimes" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2" +dependencies = [ + "hermit-abi 0.3.9", + "libc", + "windows-sys 0.48.0", +] + +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + +[[package]] +name = "jni" +version = "0.21.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a87aa2bb7d2af34197c04845522473242e1aa17c12f4935d5856491a7fb8c97" +dependencies = [ + "cesu8", + "cfg-if", + "combine", + "jni-sys 0.3.1", + "log", + "thiserror 1.0.69", + "walkdir", + "windows-sys 0.45.0", +] + +[[package]] +name = "jni" +version = "0.22.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5efd9a482cf3a427f00d6b35f14332adc7902ce91efb778580e180ff90fa3498" +dependencies = [ + "cfg-if", + "combine", + "jni-macros", + "jni-sys 0.4.1", + "log", + "simd_cesu8", + "thiserror 2.0.19", + "walkdir", + "windows-link", +] + +[[package]] +name = "jni-macros" +version = "0.22.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a00109accc170f0bdb141fed3e393c565b6f5e072365c3bd58f5b062591560a3" +dependencies = [ + "proc-macro2", + "quote", + "rustc_version", + "simd_cesu8", + "syn 2.0.119", +] + +[[package]] +name = "jni-sys" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41a652e1f9b6e0275df1f15b32661cf0d4b78d4d87ddec5e0c3c20f097433258" +dependencies = [ + "jni-sys 0.4.1", +] + +[[package]] +name = "jni-sys" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6377a88cb3910bee9b0fa88d4f42e1d2da8e79915598f65fb0c7ee14c878af2" +dependencies = [ + "jni-sys-macros", +] + +[[package]] +name = "jni-sys-macros" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38c0b942f458fe50cdac086d2f946512305e5631e720728f2a61aabcd47a6264" +dependencies = [ + "quote", + "syn 2.0.119", +] + +[[package]] +name = "jobserver" +version = "0.1.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c00acbd29eabad4a2392fa0e921c874934dbbf4194312ad20f04a0ed67a3cb3" +dependencies = [ + "getrandom 0.4.3", + "libc", +] + +[[package]] +name = "js-sys" +version = "0.3.103" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53b44bfcdb3f8d5837a46dae1ca9660a837176eee74a28b229bc626816589102" +dependencies = [ + "cfg-if", + "futures-util", + "wasm-bindgen", +] + +[[package]] +name = "khronos-egl" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6aae1df220ece3c0ada96b8153459b67eebe9ae9212258bb0134ae60416fdf76" +dependencies = [ + "libc", + "libloading 0.8.9", + "pkg-config", +] + +[[package]] +name = "khronos_api" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2db585e1d738fc771bf08a151420d3ed193d9d895a36df7f6f8a9456b911ddc" + +[[package]] +name = "libc" +version = "0.2.189" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3eaf3ede3fee6db1a4c2ee091bf8a8b4dccdc6d17f656fb07896ee72867612f2" + +[[package]] +name = "libloading" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b67380fd3b2fbe7527a606e18729d21c6f3951633d0500574c4dc22d2d638b9f" +dependencies = [ + "cfg-if", + "winapi", +] + +[[package]] +name = "libloading" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7c4b02199fee7c5d21a5ae7d8cfa79a6ef5bb2fc834d6e9058e89c825efdc55" +dependencies = [ + "cfg-if", + "windows-link", +] + +[[package]] +name = "libredox" +version = "0.1.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c943259e342f1e06ff2da7a83eabdfe7f92ce10262688dbf1895ff0b3e6e4652" +dependencies = [ + "bitflags 2.13.1", + "libc", + "plain", + "redox_syscall 0.9.0", +] + +[[package]] +name = "linux-raw-sys" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" + +[[package]] +name = "linux-raw-sys" +version = "0.4.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" + +[[package]] +name = "linux-raw-sys" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53" + +[[package]] +name = "litemap" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92daf443525c4cce67b150400bc2316076100ce0b3686209eb8cf3c31612e6f0" + +[[package]] +name = "litrs" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11d3d7f243d5c5a8b9bb5d6dd2b1602c0cb0b9db1621bafc7ed66e35ff9fe092" + +[[package]] +name = "lock_api" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965" +dependencies = [ + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ceec5bc11778974d1bcb055b18002eba7f4b3518b6a0081b3af5f21666da9ad" + +[[package]] +name = "malloc_buf" +version = "0.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62bb907fe88d54d8d9ce32a3cceab4218ed2f6b7d35617cafe9adf84e43919cb" +dependencies = [ + "libc", +] + +[[package]] +name = "memchr" +version = "2.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf8baf1c55e62ffcace7a9f06f4bd9cd3f0c4beb022d3b367256b91b87513d98" + +[[package]] +name = "memmap2" +version = "0.9.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1219ed1b7f229ee7104d281dd01d6802fe28bb6e95d292942c4daacdeb798c0" +dependencies = [ + "libc", +] + +[[package]] +name = "memoffset" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5de893c32cde5f383baa4c04c5d6dbdd735cfd4a794b0debdb2bb1b421da5ff4" +dependencies = [ + "autocfg", +] + +[[package]] +name = "memoffset" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a" +dependencies = [ + "autocfg", +] + +[[package]] +name = "metal" +version = "0.28.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5637e166ea14be6063a3f8ba5ccb9a4159df7d8f6d61c02fc3d480b1f90dcfcb" +dependencies = [ + "bitflags 2.13.1", + "block", + "core-graphics-types", + "foreign-types", + "log", + "objc", + "paste", +] + +[[package]] +name = "miniz_oxide" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" +dependencies = [ + "adler2", + "simd-adler32", +] + +[[package]] +name = "moxcms" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb85c154ba489f01b25c0d36ae69a87e4a1c73a72631fc6c0eb6dde34a73e44b" +dependencies = [ + "num-traits", + "pxfm", +] + +[[package]] +name = "naga" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e536ae46fcab0876853bd4a632ede5df4b1c2527a58f6c5a4150fe86be858231" +dependencies = [ + "arrayvec", + "bit-set", + "bitflags 2.13.1", + "codespan-reporting", + "hexf-parse", + "indexmap", + "log", + "num-traits", + "rustc-hash 1.1.0", + "spirv", + "termcolor", + "thiserror 1.0.69", + "unicode-xid", +] + +[[package]] +name = "ndk" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2076a31b7010b17a38c01907c45b945e8f11495ee4dd588309718901b1f7a5b7" +dependencies = [ + "bitflags 2.13.1", + "jni-sys 0.3.1", + "log", + "ndk-sys", + "num_enum", + "raw-window-handle 0.5.2", + "raw-window-handle 0.6.2", + "thiserror 1.0.69", +] + +[[package]] +name = "ndk-context" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27b02d87554356db9e9a873add8782d4ea6e3e58ea071a9adb9a2e8ddb884a8b" + +[[package]] +name = "ndk-sys" +version = "0.5.0+25.2.9519653" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c196769dd60fd4f363e11d948139556a344e79d451aeb2fa2fd040738ef7691" +dependencies = [ + "jni-sys 0.3.1", +] + +[[package]] +name = "nfc_tool" +version = "0.1.0" +dependencies = [ + "anyhow", + "chrono", + "eframe", + "egui", + "hex", + "pcsc", + "rfd", + "serde", + "serde_json", +] + +[[package]] +name = "nix" +version = "0.26.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "598beaf3cc6fdd9a5dfb1630c2800c7acd31df7aaf0f565796fba2b53ca1af1b" +dependencies = [ + "bitflags 1.3.2", + "cfg-if", + "libc", + "memoffset 0.7.1", +] + +[[package]] +name = "nix" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46" +dependencies = [ + "bitflags 2.13.1", + "cfg-if", + "cfg_aliases 0.2.2", + "libc", + "memoffset 0.9.1", +] + +[[package]] +name = "nohash-hasher" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2bf50223579dc7cdcfb3bfcacf7069ff68243f8c363f62ffa99cf000a6b9c451" + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] + +[[package]] +name = "num_enum" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d0bca838442ec211fa11de3a8b0e0e8f3a4522575b5c4c06ed722e005036f26" +dependencies = [ + "num_enum_derive", + "rustversion", +] + +[[package]] +name = "num_enum_derive" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "680998035259dcfcafe653688bf2aa6d3e2dc05e98be6ab46afb089dc84f1df8" +dependencies = [ + "proc-macro-crate 2.0.2", + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "objc" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "915b1b472bc21c53464d6c8461c9d3af805ba1ef837e1cac254428f4a77177b1" +dependencies = [ + "malloc_buf", +] + +[[package]] +name = "objc-foundation" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1add1b659e36c9607c7aab864a76c7a4c2760cd0cd2e120f3fb8b952c7e22bf9" +dependencies = [ + "block", + "objc", + "objc_id", +] + +[[package]] +name = "objc-sys" +version = "0.2.0-beta.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df3b9834c1e95694a05a828b59f55fa2afec6288359cda67146126b3f90a55d7" + +[[package]] +name = "objc-sys" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdb91bdd390c7ce1a8607f35f3ca7151b65afc0ff5ff3b34fa350f7d7c7e4310" + +[[package]] +name = "objc2" +version = "0.3.0-beta.3.patch-leaks.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e01640f9f2cb1220bbe80325e179e532cb3379ebcd1bf2279d703c19fe3a468" +dependencies = [ + "block2 0.2.0-alpha.6", + "objc-sys 0.2.0-beta.2", + "objc2-encode 2.0.0-pre.2", +] + +[[package]] +name = "objc2" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "559c5a40fdd30eb5e344fbceacf7595a81e242529fb4e21cf5f43fb4f11ff98d" +dependencies = [ + "objc-sys 0.3.5", + "objc2-encode 3.0.0", +] + +[[package]] +name = "objc2" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46a785d4eeff09c14c487497c162e92766fbb3e4059a71840cecc03d9a50b804" +dependencies = [ + "objc-sys 0.3.5", + "objc2-encode 4.1.0", +] + +[[package]] +name = "objc2" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a12a8ed07aefc768292f076dc3ac8c48f3781c8f2d5851dd3d98950e8c5a89f" +dependencies = [ + "objc2-encode 4.1.0", +] + +[[package]] +name = "objc2-app-kit" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4e89ad9e3d7d297152b17d39ed92cd50ca8063a89a9fa569046d41568891eff" +dependencies = [ + "bitflags 2.13.1", + "block2 0.5.1", + "libc", + "objc2 0.5.2", + "objc2-core-data", + "objc2-core-image", + "objc2-foundation 0.2.2", + "objc2-quartz-core", +] + +[[package]] +name = "objc2-app-kit" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d49e936b501e5c5bf01fda3a9452ff86dc3ea98ad5f283e1455153142d97518c" +dependencies = [ + "bitflags 2.13.1", + "objc2 0.6.4", + "objc2-core-graphics", + "objc2-foundation 0.3.2", +] + +[[package]] +name = "objc2-core-data" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "617fbf49e071c178c0b24c080767db52958f716d9eabdf0890523aeae54773ef" +dependencies = [ + "bitflags 2.13.1", + "block2 0.5.1", + "objc2 0.5.2", + "objc2-foundation 0.2.2", +] + +[[package]] +name = "objc2-core-foundation" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a180dd8642fa45cdb7dd721cd4c11b1cadd4929ce112ebd8b9f5803cc79d536" +dependencies = [ + "bitflags 2.13.1", + "dispatch2", + "objc2 0.6.4", +] + +[[package]] +name = "objc2-core-graphics" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e022c9d066895efa1345f8e33e584b9f958da2fd4cd116792e15e07e4720a807" +dependencies = [ + "bitflags 2.13.1", + "dispatch2", + "objc2 0.6.4", + "objc2-core-foundation", + "objc2-io-surface", +] + +[[package]] +name = "objc2-core-image" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55260963a527c99f1819c4f8e3b47fe04f9650694ef348ffd2227e8196d34c80" +dependencies = [ + "block2 0.5.1", + "objc2 0.5.2", + "objc2-foundation 0.2.2", + "objc2-metal", +] + +[[package]] +name = "objc2-encode" +version = "2.0.0-pre.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "abfcac41015b00a120608fdaa6938c44cb983fee294351cc4bac7638b4e50512" +dependencies = [ + "objc-sys 0.2.0-beta.2", +] + +[[package]] +name = "objc2-encode" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d079845b37af429bfe5dfa76e6d087d788031045b25cfc6fd898486fd9847666" + +[[package]] +name = "objc2-encode" +version = "4.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef25abbcd74fb2609453eb695bd2f860d389e457f67dc17cafc8b8cbc89d0c33" + +[[package]] +name = "objc2-foundation" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ee638a5da3799329310ad4cfa62fbf045d5f56e3ef5ba4149e7452dcf89d5a8" +dependencies = [ + "bitflags 2.13.1", + "block2 0.5.1", + "libc", + "objc2 0.5.2", +] + +[[package]] +name = "objc2-foundation" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3e0adef53c21f888deb4fa59fc59f7eb17404926ee8a6f59f5df0fd7f9f3272" +dependencies = [ + "bitflags 2.13.1", + "objc2 0.6.4", + "objc2-core-foundation", +] + +[[package]] +name = "objc2-io-surface" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "180788110936d59bab6bd83b6060ffdfffb3b922ba1396b312ae795e1de9d81d" +dependencies = [ + "bitflags 2.13.1", + "objc2 0.6.4", + "objc2-core-foundation", +] + +[[package]] +name = "objc2-metal" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd0cba1276f6023976a406a14ffa85e1fdd19df6b0f737b063b95f6c8c7aadd6" +dependencies = [ + "bitflags 2.13.1", + "block2 0.5.1", + "objc2 0.5.2", + "objc2-foundation 0.2.2", +] + +[[package]] +name = "objc2-quartz-core" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e42bee7bff906b14b167da2bac5efe6b6a07e6f7c0a21a7308d40c960242dc7a" +dependencies = [ + "bitflags 2.13.1", + "block2 0.5.1", + "objc2 0.5.2", + "objc2-foundation 0.2.2", + "objc2-metal", +] + +[[package]] +name = "objc_id" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c92d4ddb4bd7b50d730c215ff871754d0da6b2178849f8a2a2ab69712d0c073b" +dependencies = [ + "objc", +] + +[[package]] +name = "once_cell" +version = "1.21.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" + +[[package]] +name = "orbclient" +version = "0.3.55" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5df339f526ea9a60e371768d50efc2f2508c7203290731565d1f7a6f71d21747" +dependencies = [ + "libc", + "libredox", +] + +[[package]] +name = "ordered-stream" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9aa2b01e1d916879f73a53d01d1d6cee68adbb31d6d9177a8cfce093cced1d50" +dependencies = [ + "futures-core", + "pin-project-lite", +] + +[[package]] +name = "owned_ttf_parser" +version = "0.25.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36820e9051aca1014ddc75770aab4d68bc1e9e632f0f5627c4086bc216fb583b" +dependencies = [ + "ttf-parser", +] + +[[package]] +name = "parking" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba" + +[[package]] +name = "parking_lot" +version = "0.12.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall 0.5.18", + "smallvec", + "windows-link", +] + +[[package]] +name = "paste" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" + +[[package]] +name = "pcsc" +version = "2.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7dd833ecf8967e65934c49d3521a175929839bf6d0e497f3bd0d3a2ca08943da" +dependencies = [ + "bitflags 2.13.1", + "pcsc-sys", +] + +[[package]] +name = "pcsc-sys" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e14ef017e15d2e5592a9e39a346c1dbaea5120bab7ed7106b210ef58ebd97003" +dependencies = [ + "pkg-config", +] + +[[package]] +name = "percent-encoding" +version = "2.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" + +[[package]] +name = "pin-project-lite" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" + +[[package]] +name = "piper" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c835479a4443ded371d6c535cbfd8d31ad92c5d23ae9770a61bc155e4992a3c1" +dependencies = [ + "atomic-waker", + "fastrand 2.5.0", + "futures-io", +] + +[[package]] +name = "pkg-config" +version = "0.3.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19f132c84eca552bf34cab8ec81f1c1dcc229b811638f9d283dceabe58c5569e" + +[[package]] +name = "plain" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6" + +[[package]] +name = "png" +version = "0.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60769b8b31b2a9f263dae2776c37b1b28ae246943cf719eb6946a1db05128a61" +dependencies = [ + "bitflags 2.13.1", + "crc32fast", + "fdeflate", + "flate2", + "miniz_oxide", +] + +[[package]] +name = "polling" +version = "2.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b2d323e8ca7996b3e23126511a523f7e62924d93ecd5ae73b333815b0eb3dce" +dependencies = [ + "autocfg", + "bitflags 1.3.2", + "cfg-if", + "concurrent-queue", + "libc", + "log", + "pin-project-lite", + "windows-sys 0.48.0", +] + +[[package]] +name = "polling" +version = "3.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d0e4f59085d47d8241c88ead0f274e8a0cb551f3625263c05eb8dd897c34218" +dependencies = [ + "cfg-if", + "concurrent-queue", + "hermit-abi 0.5.2", + "pin-project-lite", + "rustix 1.1.4", + "windows-sys 0.61.2", +] + +[[package]] +name = "pollster" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22686f4785f02a4fcc856d3b3bb19bf6c8160d103f7a99cc258bddd0251dc7f2" + +[[package]] +name = "potential_utf" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0103b1cef7ec0cf76490e969665504990193874ea05c85ff9bab8b911d0a0564" +dependencies = [ + "zerovec", +] + +[[package]] +name = "ppv-lite86" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" +dependencies = [ + "zerocopy", +] + +[[package]] +name = "presser" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8cf8e6a8aa66ce33f63993ffc4ea4271eb5b0530a9002db8455ea6050c77bfa" + +[[package]] +name = "proc-macro-crate" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f4c021e1093a56626774e81216a4ce732a735e5bad4868a03f3ed65ca0c3919" +dependencies = [ + "once_cell", + "toml_edit 0.19.15", +] + +[[package]] +name = "proc-macro-crate" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b00f26d3400549137f92511a46ac1cd8ce37cb5598a96d382381458b992a5d24" +dependencies = [ + "toml_datetime 0.6.3", + "toml_edit 0.20.2", +] + +[[package]] +name = "proc-macro-crate" +version = "3.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e67ba7e9b2b56446f1d419b1d807906278ffa1a658a8a5d8a39dcb1f5a78614f" +dependencies = [ + "toml_edit 0.25.13+spec-1.1.0", +] + +[[package]] +name = "proc-macro2" +version = "1.0.107" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "985e7ec9bb745e6ce6535b544d84d6cd6f7ad8bd711c398938ae983b91a766d9" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "profiling" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d595e54a326bc53c1c197b32d295e14b169e3cfeaa8dc82b529f947fba6bcf5" + +[[package]] +name = "pxfm" +version = "0.1.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d55d956fa96f5ec02be2e13af0e20391a5aa83d6a074e3ad368959d0fab299ea" + +[[package]] +name = "quick-xml" +version = "0.41.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e660451e55124f798a69a5af3f49ccfbefbd41910eefd25caf2393e1f3473ec1" +dependencies = [ + "memchr", +] + +[[package]] +name = "quote" +version = "1.0.47" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fbf4db142a473a8d80c26bbf18454ed458bf8d26c8219c331daecfdbd079001" +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 = "r-efi" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf" + +[[package]] +name = "rand" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22f6172bdec972074665ed81ed53b71da00bfc44b65a753cfde883ec4c702a1a" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom 0.2.17", +] + +[[package]] +name = "raw-window-handle" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2ff9a1f06a88b01621b7ae906ef0211290d1c8a168a15542486a8f61c0833b9" + +[[package]] +name = "raw-window-handle" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20675572f6f24e9e76ef639bc5552774ed45f1c30e2951e1e99c59888861c539" + +[[package]] +name = "redox_syscall" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" +dependencies = [ + "bitflags 1.3.2", +] + +[[package]] +name = "redox_syscall" +version = "0.5.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" +dependencies = [ + "bitflags 2.13.1", +] + +[[package]] +name = "redox_syscall" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c5102a6aaa05aa011a238e178e6bca86d2cb56fc9f586d37cb80f5bca6e07759" +dependencies = [ + "bitflags 2.13.1", +] + +[[package]] +name = "regex" +version = "1.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f020237b6c8eed93db2e2cb53c00c60a8e1bc73da7d073199a1180401450218d" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fcfdb36bda0c880c5931cdc7a2bcdc8ba4556847b9d912bca70bc94708711ad" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6f6ff9a378485b298a5286656da665ba74413d36db0979633275d2e708145d4" + +[[package]] +name = "renderdoc-sys" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19b30a45b0cd0bcca8037f3d0dc3421eaf95327a17cad11964fb8179b4fc4832" + +[[package]] +name = "rfd" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25a73a7337fc24366edfca76ec521f51877b114e42dab584008209cca6719251" +dependencies = [ + "ashpd", + "block", + "dispatch", + "js-sys", + "log", + "objc", + "objc-foundation", + "objc_id", + "pollster", + "raw-window-handle 0.6.2", + "urlencoding", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "windows-sys 0.48.0", +] + +[[package]] +name = "rustc-hash" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" + +[[package]] +name = "rustc-hash" +version = "2.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b1e7f9a428571be2dc5bc0505c13fb6bf936822b894ec87abf8a08a4e51742d" + +[[package]] +name = "rustc_version" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" +dependencies = [ + "semver", +] + +[[package]] +name = "rustix" +version = "0.37.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "519165d378b97752ca44bbe15047d5d3409e875f39327546b42ac81d7e18c1b6" +dependencies = [ + "bitflags 1.3.2", + "errno", + "io-lifetimes", + "libc", + "linux-raw-sys 0.3.8", + "windows-sys 0.48.0", +] + +[[package]] +name = "rustix" +version = "0.38.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" +dependencies = [ + "bitflags 2.13.1", + "errno", + "libc", + "linux-raw-sys 0.4.15", + "windows-sys 0.59.0", +] + +[[package]] +name = "rustix" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190" +dependencies = [ + "bitflags 2.13.1", + "errno", + "libc", + "linux-raw-sys 0.12.1", + "windows-sys 0.61.2", +] + +[[package]] +name = "rustversion" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf54715a573b99ac80df0bc206da022bcd442c974952c7b9720069370852e21f" + +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "scoped-tls" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294" + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "sctk-adwaita" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70b31447ca297092c5a9916fc3b955203157b37c19ca8edde4f52e9843e602c7" +dependencies = [ + "ab_glyph", + "log", + "memmap2", + "smithay-client-toolkit 0.18.1", + "tiny-skia", +] + +[[package]] +name = "semver" +version = "1.0.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a7852d02fc848982e0c167ef163aaff9cd91dc640ba85e263cb1ce46fae51cd" + +[[package]] +name = "serde" +version = "1.0.229" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4148590afebada386688f18773da617792bf2ef03ffc1e4cbd2b1d45b023e0ba" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde_core" +version = "1.0.229" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67dca2c9c51e58a4791a4b1ed58308b39c64224d349a935ab5039aa360942a48" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.229" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7a5d71263a5a7d47b41f6b3f06ba276f10cc18b0931f1799f710578e2309348" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.3", +] + +[[package]] +name = "serde_json" +version = "1.0.151" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c841b55ecdae098c80dcae9cf767f6f8a0c2cdb3416bbef72181df4d0fe73f14" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + +[[package]] +name = "serde_repr" +version = "0.1.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d3b1629de253c70a0508c3899572da79ca359fdab27c7920ff00406df418906" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.3", +] + +[[package]] +name = "sha1" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a978451301f4db1d02937a4ab3ccce137717b81826e79b7d49ffe3244a13c3b8" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "shlex" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8fadd59c855ef2080decdef8ff161eb6661b86933c9d82e5ba29dc602a55aba" + +[[package]] +name = "signal-hook-registry" +version = "1.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4db69cba1110affc0e9f7bcd48bbf87b3f4fc7c61fc9155afd4c469eb3d6c1b" +dependencies = [ + "errno", + "libc", +] + +[[package]] +name = "simd-adler32" +version = "0.3.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a219298ac11a56ea9a6d2120044824d6f01aeb034955e7af7bc16858527deea" + +[[package]] +name = "simd_cesu8" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11031e251abf8611c80f460e19dbdeb54a66db918e49c65a7065b46ac7aec520" +dependencies = [ + "rustc_version", + "simdutf8", +] + +[[package]] +name = "simdutf8" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3a9fe34e3e7a50316060351f37187a3f546bce95496156754b601a5fa71b76e" + +[[package]] +name = "slab" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5" + +[[package]] +name = "slotmap" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bdd58c3c93c3d278ca835519292445cb4b0d4dc59ccfdf7ceadaab3f8aeb4038" +dependencies = [ + "version_check", +] + +[[package]] +name = "smallvec" +version = "1.15.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ed6a63f02c8539c91a8685a86f4099661ba3da017932f6ebbea6de3f0fa7c90" + +[[package]] +name = "smithay-client-toolkit" +version = "0.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "922fd3eeab3bd820d76537ce8f582b1cf951eceb5475c28500c7457d9d17f53a" +dependencies = [ + "bitflags 2.13.1", + "calloop 0.12.4", + "calloop-wayland-source 0.2.0", + "cursor-icon", + "libc", + "log", + "memmap2", + "rustix 0.38.44", + "thiserror 1.0.69", + "wayland-backend", + "wayland-client", + "wayland-csd-frame", + "wayland-cursor", + "wayland-protocols 0.31.2", + "wayland-protocols-wlr 0.2.0", + "wayland-scanner", + "xkeysym", +] + +[[package]] +name = "smithay-client-toolkit" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0512da38f5e2b31201a93524adb8d3136276fa4fe4aafab4e1f727a82b534cc0" +dependencies = [ + "bitflags 2.13.1", + "calloop 0.14.4", + "calloop-wayland-source 0.4.1", + "cursor-icon", + "libc", + "log", + "memmap2", + "rustix 1.1.4", + "thiserror 2.0.19", + "wayland-backend", + "wayland-client", + "wayland-csd-frame", + "wayland-cursor", + "wayland-protocols 0.32.13", + "wayland-protocols-experimental", + "wayland-protocols-misc", + "wayland-protocols-wlr 0.3.12", + "wayland-scanner", + "xkeysym", +] + +[[package]] +name = "smithay-clipboard" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71704c03f739f7745053bde45fa203a46c58d25bc5c4efba1d9a60e9dba81226" +dependencies = [ + "libc", + "smithay-client-toolkit 0.20.0", + "wayland-backend", +] + +[[package]] +name = "smol_str" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd538fb6910ac1099850255cf94a94df6551fbdd602454387d0adb2d1ca6dead" +dependencies = [ + "serde", +] + +[[package]] +name = "socket2" +version = "0.4.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f7916fc008ca5542385b89a3d3ce689953c143e9304a9bf8beec1de48994c0d" +dependencies = [ + "libc", + "winapi", +] + +[[package]] +name = "spirv" +version = "0.3.0+sdk-1.3.268.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eda41003dc44290527a59b13432d4a0379379fa074b70174882adfbdfd917844" +dependencies = [ + "bitflags 2.13.1", +] + +[[package]] +name = "stable_deref_trait" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" + +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + +[[package]] +name = "strict-num" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6637bab7722d379c8b41ba849228d680cc12d0a45ba1fa2b48f2a30577a06731" + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.119" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "872831b642d1a07999a962a351ed35b955ea2cfc8f3862091e2a240a84f17297" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "3.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53e9bae58849f64dfa4f5d5ae372c8341f7305f82a3868709269343628b659a3" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "synstructure" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "tempfile" +version = "3.27.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32497e9a4c7b38532efcdebeef879707aa9f794296a4f0244f6f69e9bc8574bd" +dependencies = [ + "fastrand 2.5.0", + "getrandom 0.4.3", + "once_cell", + "rustix 1.1.4", + "windows-sys 0.61.2", +] + +[[package]] +name = "termcolor" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "thiserror" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" +dependencies = [ + "thiserror-impl 1.0.69", +] + +[[package]] +name = "thiserror" +version = "2.0.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09a43598840e33d5b0331f38c5e30d13bb11c11210a4b58f0d9b18a5a5eefcd9" +dependencies = [ + "thiserror-impl 2.0.19", +] + +[[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 2.0.119", +] + +[[package]] +name = "thiserror-impl" +version = "2.0.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43cbfe0cf76104d42a574802844187e84a305e531ed54455f11fbde0f10541cd" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.3", +] + +[[package]] +name = "tiny-skia" +version = "0.11.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83d13394d44dae3207b52a326c0c85a8bf87f1541f23b0d143811088497b09ab" +dependencies = [ + "arrayref", + "arrayvec", + "bytemuck", + "cfg-if", + "log", + "tiny-skia-path", +] + +[[package]] +name = "tiny-skia-path" +version = "0.11.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c9e7fc0c2e86a30b117d0462aa261b72b7a99b7ebd7deb3a14ceda95c5bdc93" +dependencies = [ + "arrayref", + "bytemuck", + "strict-num", +] + +[[package]] +name = "tinystr" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8323304221c2a851516f22236c5722a72eaa19749016521d6dff0824447d96d" +dependencies = [ + "displaydoc", + "zerovec", +] + +[[package]] +name = "toml_datetime" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7cda73e2f1397b1262d6dfdcef8aafae14d1de7748d66822d3bfeeb6d03e5e4b" + +[[package]] +name = "toml_datetime" +version = "1.1.1+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3165f65f62e28e0115a00b2ebdd37eb6f3b641855f9d636d3cd4103767159ad7" +dependencies = [ + "serde_core", +] + +[[package]] +name = "toml_edit" +version = "0.19.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" +dependencies = [ + "indexmap", + "toml_datetime 0.6.3", + "winnow 0.5.40", +] + +[[package]] +name = "toml_edit" +version = "0.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "396e4d48bbb2b7554c944bde63101b5ae446cff6ec4a24227428f15eb72ef338" +dependencies = [ + "indexmap", + "toml_datetime 0.6.3", + "winnow 0.5.40", +] + +[[package]] +name = "toml_edit" +version = "0.25.13+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6975367e4d2ef766d86af01ffad14b622fecc8d4357a998fbc4deb6e9bacaf9b" +dependencies = [ + "indexmap", + "toml_datetime 1.1.1+spec-1.1.0", + "toml_parser", + "winnow 1.0.4", +] + +[[package]] +name = "toml_parser" +version = "1.1.3+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d38ac1cf9b95face32296c0a3ede1fdc270627c9d9c02a7274dd6d960dc4d56" +dependencies = [ + "winnow 1.0.4", +] + +[[package]] +name = "tracing" +version = "0.1.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100" +dependencies = [ + "log", + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "tracing-core" +version = "0.1.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a" +dependencies = [ + "once_cell", +] + +[[package]] +name = "ttf-parser" +version = "0.25.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2df906b07856748fa3f6e0ad0cbaa047052d4a7dd609e231c4f72cee8c36f31" + +[[package]] +name = "type-map" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb30dbbd9036155e74adad6812e9898d03ec374946234fbcebd5dfc7b9187b90" +dependencies = [ + "rustc-hash 2.1.3", +] + +[[package]] +name = "typenum" +version = "1.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6f5e870be6c3b371b77fe0ee0bafb859fa4964b4404c27de1d380043c4dda20" + +[[package]] +name = "uds_windows" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2f6fb2847f6742cd76af783a2a2c49e9375d0a111c7bef6f71cd9e738c72d6e" +dependencies = [ + "memoffset 0.9.1", + "tempfile", + "windows-sys 0.61.2", +] + +[[package]] +name = "unicode-ident" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" + +[[package]] +name = "unicode-segmentation" +version = "1.13.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6f5d3c3b1bf09027a88a6bc961fc00497d651009560b5463668dc81b0fa87a8" + +[[package]] +name = "unicode-width" +version = "0.1.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" + +[[package]] +name = "unicode-xid" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" + +[[package]] +name = "url" +version = "2.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff67a8a4397373c3ef660812acab3268222035010ab8680ec4215f38ba3d0eed" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", + "serde", + "serde_derive", +] + +[[package]] +name = "urlencoding" +version = "2.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da" + +[[package]] +name = "utf8_iter" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" + +[[package]] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + +[[package]] +name = "waker-fn" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "317211a0dc0ceedd78fb2ca9a44aed3d7b9b26f81870d485c07122b4350673b7" + +[[package]] +name = "walkdir" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" +dependencies = [ + "same-file", + "winapi-util", +] + +[[package]] +name = "wasi" +version = "0.11.1+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" + +[[package]] +name = "wasip2" +version = "1.0.4+wasi-0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b67efb37e106e55ce722a510d6b5f9c17f083e5fc79afc2badeb12cc313d9487" +dependencies = [ + "wit-bindgen", +] + +[[package]] +name = "wasm-bindgen" +version = "0.2.126" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b067c0c11094aef6b7a801c1e34a26affafdf3d051dba08456b868789aaf9a4" +dependencies = [ + "cfg-if", + "once_cell", + "rustversion", + "wasm-bindgen-macro", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.76" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c62df1340f32221cb9c54d6a27b030e3dba64361d4a95bed55f9aacb44da291d" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.126" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "167ce5e579f6bcf889c4f7175a8a5a585de84e8ff93976ce393efa5f2837aab1" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.126" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3997c7839262f4ef12cf90b818d6340c18e80f263f1a94bf157d0ec4420380e" +dependencies = [ + "bumpalo", + "proc-macro2", + "quote", + "syn 2.0.119", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.126" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc1b4cb0cc549fcf58d7dfc081778139b3d283a081644e833e84682ad71cea24" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "wayland-backend" +version = "0.3.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "016ccf01d1c58b6f8999612813e17c9b2390f7d70671428869913310f83f54b8" +dependencies = [ + "cc", + "downcast-rs", + "rustix 1.1.4", + "scoped-tls", + "smallvec", + "wayland-sys", +] + +[[package]] +name = "wayland-client" +version = "0.31.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3c36a0f861ad76d0901f2800b46321410d9f73f2ea88aac0650d86c32688073" +dependencies = [ + "bitflags 2.13.1", + "rustix 1.1.4", + "wayland-backend", + "wayland-scanner", +] + +[[package]] +name = "wayland-csd-frame" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "625c5029dbd43d25e6aa9615e88b829a5cad13b2819c4ae129fdbb7c31ab4c7e" +dependencies = [ + "bitflags 2.13.1", + "cursor-icon", + "wayland-backend", +] + +[[package]] +name = "wayland-cursor" +version = "0.31.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a52d18780be9b1314328a3de5f930b73d2200112e3849ca6cb11822793fb34d" +dependencies = [ + "rustix 1.1.4", + "wayland-client", + "xcursor", +] + +[[package]] +name = "wayland-protocols" +version = "0.31.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f81f365b8b4a97f422ac0e8737c438024b5951734506b0e1d775c73030561f4" +dependencies = [ + "bitflags 2.13.1", + "wayland-backend", + "wayland-client", + "wayland-scanner", +] + +[[package]] +name = "wayland-protocols" +version = "0.32.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23d0c813de3daa2ed6520af85a3bd49b0e722a3078506899aa9686fea58dc4b6" +dependencies = [ + "bitflags 2.13.1", + "wayland-backend", + "wayland-client", + "wayland-scanner", +] + +[[package]] +name = "wayland-protocols-experimental" +version = "20250721.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40a1f863128dcaaec790d7b4b396cc9b9a7a079e878e18c47e6c2d2c5a8dcbb1" +dependencies = [ + "bitflags 2.13.1", + "wayland-backend", + "wayland-client", + "wayland-protocols 0.32.13", + "wayland-scanner", +] + +[[package]] +name = "wayland-protocols-misc" +version = "0.3.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e9567599ef23e09b8dad6e429e5738d4509dfc46b3b21f32841a304d16b29c8" +dependencies = [ + "bitflags 2.13.1", + "wayland-backend", + "wayland-client", + "wayland-protocols 0.32.13", + "wayland-scanner", +] + +[[package]] +name = "wayland-protocols-plasma" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23803551115ff9ea9bce586860c5c5a971e360825a0309264102a9495a5ff479" +dependencies = [ + "bitflags 2.13.1", + "wayland-backend", + "wayland-client", + "wayland-protocols 0.31.2", + "wayland-scanner", +] + +[[package]] +name = "wayland-protocols-wlr" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad1f61b76b6c2d8742e10f9ba5c3737f6530b4c243132c2a2ccc8aa96fe25cd6" +dependencies = [ + "bitflags 2.13.1", + "wayland-backend", + "wayland-client", + "wayland-protocols 0.31.2", + "wayland-scanner", +] + +[[package]] +name = "wayland-protocols-wlr" +version = "0.3.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb04e52f7836d7c7976c78ca0250d61e33873c34156a2a1fc9474828ec268234" +dependencies = [ + "bitflags 2.13.1", + "wayland-backend", + "wayland-client", + "wayland-protocols 0.32.13", + "wayland-scanner", +] + +[[package]] +name = "wayland-scanner" +version = "0.31.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "338e30461b3a2b67d70eb30a6d89f8e0c93a833e07d2ae89085cd070c4a00ac0" +dependencies = [ + "proc-macro2", + "quick-xml", + "quote", +] + +[[package]] +name = "wayland-sys" +version = "0.31.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8eab23fefc9e41f8e841df4a9c707e8a8c4ed26e944ef69297184de2785e3be" +dependencies = [ + "dlib", + "log", + "once_cell", + "pkg-config", +] + +[[package]] +name = "web-sys" +version = "0.3.103" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8622dcb61c0bcc9fffa6938bed81210af2da9a7e4a1a834b2e37a59b6dfb6141" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "web-time" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa30049b1c872b72c89866d458eae9f20380ab280ffd1b1e18df2d3e2d98cfe0" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "webbrowser" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fc95580916af1e68ff6a7be07446fc5db73ebf71cf092de939bbf5f7e189f72" +dependencies = [ + "core-foundation 0.10.1", + "jni 0.22.4", + "log", + "ndk-context", + "objc2 0.6.4", + "objc2-foundation 0.3.2", + "url", + "web-sys", +] + +[[package]] +name = "wgpu" +version = "0.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90e37c7b9921b75dfd26dd973fdcbce36f13dfa6e2dc82aece584e0ed48c355c" +dependencies = [ + "arrayvec", + "cfg-if", + "cfg_aliases 0.1.1", + "document-features", + "js-sys", + "log", + "parking_lot", + "profiling", + "raw-window-handle 0.6.2", + "smallvec", + "static_assertions", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "wgpu-core", + "wgpu-hal", + "wgpu-types", +] + +[[package]] +name = "wgpu-core" +version = "0.21.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d50819ab545b867d8a454d1d756b90cd5f15da1f2943334ca314af10583c9d39" +dependencies = [ + "arrayvec", + "bit-vec", + "bitflags 2.13.1", + "cfg_aliases 0.1.1", + "codespan-reporting", + "document-features", + "indexmap", + "log", + "naga", + "once_cell", + "parking_lot", + "profiling", + "raw-window-handle 0.6.2", + "rustc-hash 1.1.0", + "smallvec", + "thiserror 1.0.69", + "web-sys", + "wgpu-hal", + "wgpu-types", +] + +[[package]] +name = "wgpu-hal" +version = "0.21.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "172e490a87295564f3fcc0f165798d87386f6231b04d4548bca458cbbfd63222" +dependencies = [ + "android_system_properties", + "arrayvec", + "ash", + "bitflags 2.13.1", + "cfg_aliases 0.1.1", + "core-graphics-types", + "glow", + "glutin_wgl_sys", + "gpu-alloc", + "gpu-allocator", + "gpu-descriptor", + "hassle-rs", + "js-sys", + "khronos-egl", + "libc", + "libloading 0.8.9", + "log", + "metal", + "naga", + "ndk-sys", + "objc", + "once_cell", + "parking_lot", + "profiling", + "raw-window-handle 0.6.2", + "renderdoc-sys", + "rustc-hash 1.1.0", + "smallvec", + "thiserror 1.0.69", + "wasm-bindgen", + "web-sys", + "wgpu-types", + "winapi", +] + +[[package]] +name = "wgpu-types" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1353d9a46bff7f955a680577f34c69122628cc2076e1d6f3a9be6ef00ae793ef" +dependencies = [ + "bitflags 2.13.1", + "js-sys", + "web-sys", +] + +[[package]] +name = "widestring" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72069c3113ab32ab29e5584db3c6ec55d416895e60715417b5b883a357c3e471" + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-util" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" +dependencies = [ + "windows-sys 0.61.2", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e686886bc078bc1b0b600cac0147aadb815089b6e4da64016cbd754b6342700f" +dependencies = [ + "windows-implement 0.48.0", + "windows-interface 0.48.0", + "windows-targets 0.48.5", +] + +[[package]] +name = "windows" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e48a53791691ab099e5e2ad123536d0fff50652600abaf43bbf952894110d0be" +dependencies = [ + "windows-core 0.52.0", + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-core" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-core" +version = "0.62.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb" +dependencies = [ + "windows-implement 0.60.2", + "windows-interface 0.59.3", + "windows-link", + "windows-result", + "windows-strings", +] + +[[package]] +name = "windows-implement" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e2ee588991b9e7e6c8338edf3333fbe4da35dc72092643958ebb43f0ab2c49c" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "windows-implement" +version = "0.60.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "windows-interface" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6fb8df20c9bcaa8ad6ab513f7b40104840c8867d5751126e4df3b08388d0cc7" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "windows-interface" +version = "0.59.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "windows-link" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" + +[[package]] +name = "windows-result" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-strings" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-sys" +version = "0.45.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" +dependencies = [ + "windows-targets 0.42.2", +] + +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets 0.48.5", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets 0.52.6", +] + +[[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.5", +] + +[[package]] +name = "windows-sys" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-targets" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" +dependencies = [ + "windows_aarch64_gnullvm 0.42.2", + "windows_aarch64_msvc 0.42.2", + "windows_i686_gnu 0.42.2", + "windows_i686_msvc 0.42.2", + "windows_x86_64_gnu 0.42.2", + "windows_x86_64_gnullvm 0.42.2", + "windows_x86_64_msvc 0.42.2", +] + +[[package]] +name = "windows-targets" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +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", +] + +[[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.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +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" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" + +[[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.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" + +[[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.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006" + +[[package]] +name = "windows_i686_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" + +[[package]] +name = "windows_i686_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" + +[[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.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3" + +[[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.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c" + +[[package]] +name = "windows_i686_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" + +[[package]] +name = "windows_i686_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" + +[[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.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" + +[[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.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" + +[[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.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" + +[[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.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650" + +[[package]] +name = "winit" +version = "0.29.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d59ad965a635657faf09c8f062badd885748428933dad8e8bdd64064d92e5ca" +dependencies = [ + "ahash", + "android-activity", + "atomic-waker", + "bitflags 2.13.1", + "bytemuck", + "calloop 0.12.4", + "cfg_aliases 0.1.1", + "core-foundation 0.9.4", + "core-graphics", + "cursor-icon", + "icrate", + "js-sys", + "libc", + "log", + "memmap2", + "ndk", + "ndk-sys", + "objc2 0.4.1", + "once_cell", + "orbclient", + "percent-encoding", + "raw-window-handle 0.5.2", + "raw-window-handle 0.6.2", + "redox_syscall 0.3.5", + "rustix 0.38.44", + "sctk-adwaita", + "smithay-client-toolkit 0.18.1", + "smol_str", + "unicode-segmentation", + "wasm-bindgen", + "wasm-bindgen-futures", + "wayland-backend", + "wayland-client", + "wayland-protocols 0.31.2", + "wayland-protocols-plasma", + "web-sys", + "web-time", + "windows-sys 0.48.0", + "x11-dl", + "x11rb", + "xkbcommon-dl", +] + +[[package]] +name = "winnow" +version = "0.5.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f593a95398737aeed53e489c785df13f3618e41dbcd6718c6addbf1395aa6876" +dependencies = [ + "memchr", +] + +[[package]] +name = "winnow" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23b97319f7b8343df12cc98938e5c3eb436064524c8d2b4e30a1d3a36eecdf81" +dependencies = [ + "memchr", +] + +[[package]] +name = "wit-bindgen" +version = "0.57.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ebf944e87a7c253233ad6766e082e3cd714b5d03812acc24c318f549614536e" + +[[package]] +name = "writeable" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ffae5123b2d3fc086436f8834ae3ab053a283cfac8fe0a0b8eaae044768a4c4" + +[[package]] +name = "x11-dl" +version = "2.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38735924fedd5314a6e548792904ed8c6de6636285cb9fec04d5b1db85c1516f" +dependencies = [ + "libc", + "once_cell", + "pkg-config", +] + +[[package]] +name = "x11rb" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9993aa5be5a26815fe2c3eacfc1fde061fc1a1f094bf1ad2a18bf9c495dd7414" +dependencies = [ + "as-raw-xcb-connection", + "gethostname", + "libc", + "libloading 0.8.9", + "once_cell", + "rustix 1.1.4", + "x11rb-protocol", +] + +[[package]] +name = "x11rb-protocol" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea6fc2961e4ef194dcbfe56bb845534d0dc8098940c7e5c012a258bfec6701bd" + +[[package]] +name = "xcursor" +version = "0.3.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bec9e4a500ca8864c5b47b8b482a73d62e4237670e5b5f1d6b9e3cae50f28f2b" + +[[package]] +name = "xdg-home" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec1cdab258fb55c0da61328dc52c8764709b249011b2cad0454c72f0bf10a1f6" +dependencies = [ + "libc", + "windows-sys 0.59.0", +] + +[[package]] +name = "xkbcommon-dl" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d039de8032a9a8856a6be89cea3e5d12fdd82306ab7c94d74e6deab2460651c5" +dependencies = [ + "bitflags 2.13.1", + "dlib", + "log", + "once_cell", + "xkeysym", +] + +[[package]] +name = "xkeysym" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9cc00251562a284751c9973bace760d86c0276c471b4be569fe6b068ee97a56" + +[[package]] +name = "xml-rs" +version = "0.8.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ae8337f8a065cfc972643663ea4279e04e7256de865aa66fe25cec5fb912d3f" + +[[package]] +name = "yoke" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "709fe23a0424b6a435d82152b1bd3fdfb0833487d5fa90d05d42762a9891fef5" +dependencies = [ + "stable_deref_trait", + "yoke-derive", + "zerofrom", +] + +[[package]] +name = "yoke-derive" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de844c262c8848816172cef550288e7dc6c7b7814b4ee56b3e1553f275f1858e" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", + "synstructure", +] + +[[package]] +name = "zbus" +version = "3.15.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "675d170b632a6ad49804c8cf2105d7c31eddd3312555cffd4b740e08e97c25e6" +dependencies = [ + "async-broadcast 0.5.1", + "async-executor", + "async-fs 1.6.0", + "async-io 1.13.0", + "async-lock 2.8.0", + "async-process 1.8.1", + "async-recursion", + "async-task", + "async-trait", + "blocking", + "byteorder", + "derivative", + "enumflags2", + "event-listener 2.5.3", + "futures-core", + "futures-sink", + "futures-util", + "hex", + "nix 0.26.4", + "once_cell", + "ordered-stream", + "rand", + "serde", + "serde_repr", + "sha1", + "static_assertions", + "tracing", + "uds_windows", + "winapi", + "xdg-home", + "zbus_macros 3.15.2", + "zbus_names 2.6.1", + "zvariant 3.15.2", +] + +[[package]] +name = "zbus" +version = "4.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb97012beadd29e654708a0fdb4c84bc046f537aecfde2c3ee0a9e4b4d48c725" +dependencies = [ + "async-broadcast 0.7.2", + "async-executor", + "async-fs 2.2.0", + "async-io 2.6.0", + "async-lock 3.4.2", + "async-process 2.5.0", + "async-recursion", + "async-task", + "async-trait", + "blocking", + "enumflags2", + "event-listener 5.4.2", + "futures-core", + "futures-sink", + "futures-util", + "hex", + "nix 0.29.0", + "ordered-stream", + "rand", + "serde", + "serde_repr", + "sha1", + "static_assertions", + "tracing", + "uds_windows", + "windows-sys 0.52.0", + "xdg-home", + "zbus_macros 4.4.0", + "zbus_names 3.0.0", + "zvariant 4.2.0", +] + +[[package]] +name = "zbus_macros" +version = "3.15.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7131497b0f887e8061b430c530240063d33bf9455fa34438f388a245da69e0a5" +dependencies = [ + "proc-macro-crate 1.3.1", + "proc-macro2", + "quote", + "regex", + "syn 1.0.109", + "zvariant_utils 1.0.1", +] + +[[package]] +name = "zbus_macros" +version = "4.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "267db9407081e90bbfa46d841d3cbc60f59c0351838c4bc65199ecd79ab1983e" +dependencies = [ + "proc-macro-crate 3.5.0", + "proc-macro2", + "quote", + "syn 2.0.119", + "zvariant_utils 2.1.0", +] + +[[package]] +name = "zbus_names" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "437d738d3750bed6ca9b8d423ccc7a8eb284f6b1d6d4e225a0e4e6258d864c8d" +dependencies = [ + "serde", + "static_assertions", + "zvariant 3.15.2", +] + +[[package]] +name = "zbus_names" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b9b1fef7d021261cc16cba64c351d291b715febe0fa10dc3a443ac5a5022e6c" +dependencies = [ + "serde", + "static_assertions", + "zvariant 4.2.0", +] + +[[package]] +name = "zerocopy" +version = "0.8.55" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5a105cd7b140f6eeec8acff2ea38135d3cab283ada58540f629fe51e46696eb" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.8.55" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fe976fb70c78cd64cccfe3a6fc142244e8a77b70959b30faf9d0ac37ee228eb" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "zerofrom" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ec05a11813ea801ff6d75110ad09cd0824ddba17dfe17128ea0d5f68e6c5272" +dependencies = [ + "zerofrom-derive", +] + +[[package]] +name = "zerofrom-derive" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11532158c46691caf0f2593ea8358fed6bbf68a0315e80aae9bd41fbade684a1" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", + "synstructure", +] + +[[package]] +name = "zerotrie" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f9152d31db0792fa83f70fb2f83148effb5c1f5b8c7686c3459e361d9bc20bf" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", +] + +[[package]] +name = "zerovec" +version = "0.11.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90f911cbc359ab6af17377d242225f4d75119aec87ea711a880987b18cd7b239" +dependencies = [ + "yoke", + "zerofrom", + "zerovec-derive", +] + +[[package]] +name = "zerovec-derive" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "625dc425cab0dca6dc3c3319506e6593dcb08a9f387ea3b284dbd52a92c40555" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" + +[[package]] +name = "zvariant" +version = "3.15.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4eef2be88ba09b358d3b58aca6e41cd853631d44787f319a1383ca83424fb2db" +dependencies = [ + "byteorder", + "enumflags2", + "libc", + "serde", + "static_assertions", + "zvariant_derive 3.15.2", +] + +[[package]] +name = "zvariant" +version = "4.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2084290ab9a1c471c38fc524945837734fbf124487e105daec2bb57fd48c81fe" +dependencies = [ + "endi", + "enumflags2", + "serde", + "static_assertions", + "url", + "zvariant_derive 4.2.0", +] + +[[package]] +name = "zvariant_derive" +version = "3.15.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37c24dc0bed72f5f90d1f8bb5b07228cbf63b3c6e9f82d82559d4bae666e7ed9" +dependencies = [ + "proc-macro-crate 1.3.1", + "proc-macro2", + "quote", + "syn 1.0.109", + "zvariant_utils 1.0.1", +] + +[[package]] +name = "zvariant_derive" +version = "4.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73e2ba546bda683a90652bac4a279bc146adad1386f25379cf73200d2002c449" +dependencies = [ + "proc-macro-crate 3.5.0", + "proc-macro2", + "quote", + "syn 2.0.119", + "zvariant_utils 2.1.0", +] + +[[package]] +name = "zvariant_utils" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7234f0d811589db492d16893e3f21e8e2fd282e6d01b0cddee310322062cc200" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "zvariant_utils" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c51bcff7cc3dbb5055396bcf774748c3dab426b4b8659046963523cee4808340" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..b9556b4 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "nfc_tool" +version = "0.1.0" +edition = "2021" + +[dependencies] +pcsc = "2.8" +eframe = "0.28" +egui = "0.28" +serde = { version = "1.0", features = ["derive"] } +serde_json = "1.0" +hex = "0.4" +anyhow = "1.0" +chrono = "0.4" +rfd = "0.14" diff --git a/src/acr122u.rs b/src/acr122u.rs new file mode 100644 index 0000000..1599a0f --- /dev/null +++ b/src/acr122u.rs @@ -0,0 +1,230 @@ +use anyhow::{anyhow, Result}; +use pcsc::{Card, Context, Protocols, Scope, ShareMode, MAX_BUFFER_SIZE}; +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct CardInfo { + pub uid: String, + pub uid_bytes: Vec, + pub ats: Option, + pub card_type: String, + pub sak: u8, + pub atqa: String, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct LedBuzzerConfig { + pub red: bool, + pub green: bool, + pub blink_red: bool, + pub blink_green: bool, + pub blink_count: u8, + pub t1_duration_ms: u8, + pub t2_duration_ms: u8, + pub buzzer_mode: u8, +} + +pub struct Acr122u; + +pub const IOCTL_CCID_ESCAPE: u32 = 0x00313520; + +impl Acr122u { + pub fn create_context() -> Result { + let ctx = Context::establish(Scope::User)?; + Ok(ctx) + } + + pub fn list_readers(ctx: &Context) -> Result> { + let mut readers_buf = [0u8; 2048]; + let readers = ctx.list_readers(&mut readers_buf)?; + + let mut names = Vec::new(); + for name in readers { + if let Ok(s) = name.to_str() { + names.push(s.to_string()); + } + } + Ok(names) + } + + pub fn find_acr122u(ctx: &Context) -> Result { + let readers = Self::list_readers(ctx)?; + if readers.is_empty() { + return Err(anyhow!("Kein Smartcard-Lesegerät gefunden!")); + } + + for r in &readers { + let lower = r.to_lowercase(); + if lower.contains("acr122") || lower.contains("acs") || lower.contains("picc") { + return Ok(r.clone()); + } + } + + Ok(readers[0].clone()) + } + + /// Connect to card for reading operations (Shared mode) + pub fn connect_card_with_ctx(ctx: &Context, reader: &str) -> Result { + let c_reader = std::ffi::CString::new(reader)?; + + if let Ok(card) = ctx.connect(&c_reader, ShareMode::Shared, Protocols::RAW) { + return Ok(card); + } + if let Ok(card) = ctx.connect(&c_reader, ShareMode::Shared, Protocols::ANY) { + return Ok(card); + } + if let Ok(card) = ctx.connect(&c_reader, ShareMode::Exclusive, Protocols::RAW) { + return Ok(card); + } + + Err(anyhow!("Karte konnte nicht verbunden werden (Kein passendes Protokoll)")) + } + + /// Connect to card for writing operations (Exclusive mode prevents Windows RF reset) + pub fn connect_card_for_write(ctx: &Context, reader: &str) -> Result { + let c_reader = std::ffi::CString::new(reader)?; + + if let Ok(card) = ctx.connect(&c_reader, ShareMode::Exclusive, Protocols::RAW) { + return Ok(card); + } + if let Ok(card) = ctx.connect(&c_reader, ShareMode::Exclusive, Protocols::ANY) { + return Ok(card); + } + if let Ok(card) = ctx.connect(&c_reader, ShareMode::Shared, Protocols::RAW) { + return Ok(card); + } + let card = ctx.connect(&c_reader, ShareMode::Shared, Protocols::ANY)?; + Ok(card) + } + + pub fn connect_direct_with_ctx(ctx: &Context, reader: &str) -> Result { + let c_reader = std::ffi::CString::new(reader)?; + let card = ctx.connect(&c_reader, ShareMode::Direct, Protocols::UNDEFINED)?; + Ok(card) + } + + pub fn transmit(card: &Card, command: &[u8]) -> Result<(Vec, u8, u8)> { + let mut receive_buf = [0u8; MAX_BUFFER_SIZE]; + let resp = card.transmit(command, &mut receive_buf)?; + + if resp.len() < 2 { + return Err(anyhow!("Antwort zu kurz: {:?}", resp)); + } + + let sw1 = resp[resp.len() - 2]; + let sw2 = resp[resp.len() - 1]; + let data = resp[..resp.len() - 2].to_vec(); + + Ok((data, sw1, sw2)) + } + + pub fn control_escape(card: &Card, command: &[u8]) -> Result<(Vec, u8, u8)> { + let mut receive_buf = [0u8; MAX_BUFFER_SIZE]; + let resp = card.control(IOCTL_CCID_ESCAPE, command, &mut receive_buf)?; + + if resp.is_empty() { + return Err(anyhow!("Keine Antwort auf Escape Command")); + } + + if resp.len() >= 2 { + let sw1 = resp[resp.len() - 2]; + let sw2 = resp[resp.len() - 1]; + let data = resp[..resp.len() - 2].to_vec(); + Ok((data, sw1, sw2)) + } else { + Ok((resp.to_vec(), 0x90, 0x00)) + } + } + + pub fn set_led_buzzer(ctx: &Context, reader: &str, config: &LedBuzzerConfig) -> Result<()> { + let mut p2: u8 = 0; + if config.red { p2 |= 0x01; } + if config.green { p2 |= 0x02; } + p2 |= 0x04 | 0x08; + + if config.blink_red { p2 |= 0x10 | 0x40; } + if config.blink_green { p2 |= 0x20 | 0x80; } + + let apdu = [ + 0xFF, 0x00, 0x40, p2, 0x04, + config.t1_duration_ms / 100, + config.t2_duration_ms / 100, + config.blink_count, + config.buzzer_mode, + ]; + + if let Ok(card) = Self::connect_card_with_ctx(ctx, reader) { + let _ = Self::transmit(&card, &apdu); + return Ok(()); + } + + if let Ok(card) = Self::connect_direct_with_ctx(ctx, reader) { + let _ = Self::control_escape(&card, &apdu); + } + + Ok(()) + } + + pub fn beep(ctx: &Context, reader: &str, duration_ms: u8, count: u8) -> Result<()> { + let config = LedBuzzerConfig { + red: false, + green: true, + blink_red: false, + blink_green: true, + blink_count: count, + t1_duration_ms: duration_ms, + t2_duration_ms: duration_ms, + buzzer_mode: 1, + }; + Self::set_led_buzzer(ctx, reader, &config) + } + + pub fn get_card_uid(card: &Card) -> Result> { + let apdu = [0xFF, 0xCA, 0x00, 0x00, 0x00]; + match Self::transmit(card, &apdu) { + Ok((data, sw1, sw2)) => { + if (sw1 == 0x90 || sw1 == 0x62 || sw1 == 0x63) && !data.is_empty() { + Ok(data) + } else { + Err(anyhow!("UID Abfrage fehlgeschlagen (SW: {:02X}{:02X})", sw1, sw2)) + } + } + Err(e) => Err(anyhow!("Transmit Fehler beim UID Lesen: {}", e)), + } + } + + pub fn get_card_ats(card: &Card) -> Result> { + let apdu = [0xFF, 0xCA, 0x01, 0x00, 0x00]; + let (data, sw1, sw2) = Self::transmit(card, &apdu)?; + if sw1 == 0x90 && sw2 == 0x00 { + Ok(data) + } else { + Err(anyhow!("ATS nicht verfügbar")) + } + } + + pub fn read_card_info(ctx: &Context, reader: &str) -> Result { + let card = Self::connect_card_with_ctx(ctx, reader)?; + let uid_bytes = Self::get_card_uid(&card)?; + let uid_hex = hex::encode_upper(&uid_bytes); + + let ats_bytes = Self::get_card_ats(&card).ok(); + let ats_hex = ats_bytes.as_ref().map(|b| hex::encode_upper(b)); + + let card_type = match uid_bytes.len() { + 4 => "MIFARE Classic 1K / 4K oder NTAG (4-Byte UID)", + 7 => "NTAG213 / NTAG215 / NTAG216 / Ultralight (7-Byte UID)", + 10 => "NFC Tag Type 2 / ISO14443 (10-Byte UID)", + _ => "ISO 14443 NFC Karte", + }.to_string(); + + Ok(CardInfo { + uid: uid_hex, + uid_bytes, + ats: ats_hex, + card_type, + sak: 0x00, + atqa: "0000".to_string(), + }) + } +} diff --git a/src/gui.rs b/src/gui.rs new file mode 100644 index 0000000..6200ea9 --- /dev/null +++ b/src/gui.rs @@ -0,0 +1,32 @@ +use anyhow::Result; +use tao::{ + event::{Event, WindowEvent}, + event_loop::{ControlFlow, EventLoop}, + window::WindowBuilder, +}; +use wry::WebViewBuilder; + +pub fn launch_gui(url: &str) -> Result<()> { + let event_loop = EventLoop::new(); + let window = WindowBuilder::new() + .with_title("ACR122U NFC Studio Pro") + .with_inner_size(tao::dpi::LogicalSize::new(1280.0, 850.0)) + .with_min_inner_size(tao::dpi::LogicalSize::new(900.0, 600.0)) + .build(&event_loop)?; + + let _webview = WebViewBuilder::new(&window) + .with_url(url) + .build()?; + + event_loop.run(move |event, _, control_flow| { + *control_flow = ControlFlow::Wait; + + if let Event::WindowEvent { + event: WindowEvent::CloseRequested, + .. + } = event + { + *control_flow = ControlFlow::Exit; + } + }); +} diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..1d1b912 --- /dev/null +++ b/src/main.rs @@ -0,0 +1,692 @@ +#![windows_subsystem = "windows"] + +mod acr122u; +mod mifare; +mod ndef; +mod ntag; + +use acr122u::{Acr122u, CardInfo, LedBuzzerConfig}; +use eframe::egui; +use mifare::{MifareDump, MifareHandler}; +use ndef::NdefCodec; +use ntag::NtagHandler; +use pcsc::Context; +use std::fs; +use std::sync::atomic::{AtomicBool, Ordering}; +use std::sync::mpsc::{channel, Receiver, Sender}; +use std::sync::{Arc, Mutex}; +use std::thread; +use std::time::Duration; + +pub enum CardEvent { + ReaderStatus { connected: bool, name: String }, + CardDetected(CardInfo), + CardRemoved, +} + +pub struct NfcApp { + rx: Receiver, + reader_name: String, + is_reader_connected: bool, + current_card: Option, + event_logs: Vec, + active_tab: Tab, + + // LED / Beep state + led_red: bool, + led_green: bool, + led_blink: bool, + led_beep: bool, + + // MIFARE state + mifare_dump: Option, + mifare_status: String, + + // NDEF & Text State + ndef_subtab: NdefSubTab, + ndef_url_input: String, + ndef_text_input: String, + ndef_text_lang: String, + wifi_ssid: String, + wifi_pass: String, + vcard_name: String, + vcard_phone: String, + vcard_email: String, + vcard_company: String, + geo_url: String, + aar_package: String, + ndef_status: String, + + // NTAG Password State + pwd_input: String, + pack_input: String, + pwd_status: String, + + // APDU State + apdu_input: String, + apdu_response_log: Vec, + + pcsc_ctx: Arc>, + is_busy: Arc, +} + +#[derive(PartialEq)] +enum Tab { + Scanner, + Ndef, + Mifare, + Password, + Hardware, + ExpertApdu, +} + +#[derive(PartialEq)] +enum NdefSubTab { + Text, + Url, + Wifi, + VCard, + Geo, + AppLauncher, +} + +impl NfcApp { + pub fn new(cc: &eframe::CreationContext<'_>) -> Self { + setup_edel_theme(&cc.egui_ctx); + + let (tx, rx) = channel(); + let ctx = Acr122u::create_context().expect("PC/SC Context konnte nicht erstellt werden!"); + let pcsc_ctx = Arc::new(Mutex::new(ctx)); + let is_busy = Arc::new(AtomicBool::new(false)); + + let poll_ctx = pcsc_ctx.clone(); + let poll_busy = is_busy.clone(); + thread::spawn(move || { + poll_loop(tx, poll_ctx, poll_busy); + }); + + Self { + rx, + reader_name: "Kein Lesegerät angeschlossen".to_string(), + is_reader_connected: false, + current_card: None, + event_logs: vec!["System bereit. Bitte lege einen NFC-Tag auf das Gerät...".to_string()], + active_tab: Tab::Scanner, + + led_red: false, + led_green: true, + led_blink: false, + led_beep: true, + + mifare_dump: None, + mifare_status: "Klicke auf 'Karte Auslesen', um alle Speichersektoren zu scannen.".to_string(), + + ndef_subtab: NdefSubTab::Text, + ndef_url_input: "https://example.com".to_string(), + ndef_text_input: "Hallo! Das ist meine persönliche Notiz auf dem NFC-Tag.".to_string(), + ndef_text_lang: "de".to_string(), + wifi_ssid: "MeinWLAN".to_string(), + wifi_pass: "MeinPasswort123".to_string(), + vcard_name: "Max Mustermann".to_string(), + vcard_phone: "+49 170 1234567".to_string(), + vcard_email: "max@beispiel.de".to_string(), + vcard_company: "Meine Firma GmbH".to_string(), + geo_url: "https://maps.google.com/?q=Berlin".to_string(), + aar_package: "com.spotify.music".to_string(), + ndef_status: "Bereit zum Beschreiben".to_string(), + + pwd_input: "1234".to_string(), + pack_input: "0000".to_string(), + pwd_status: "Gib ein 4-stelliges Passwort ein, um den Tag zu schützen.".to_string(), + + apdu_input: "FF 00 48 00 00".to_string(), + apdu_response_log: Vec::new(), + + pcsc_ctx, + is_busy, + } + } +} + +fn setup_edel_theme(ctx: &egui::Context) { + let mut style = (*ctx.style()).clone(); + let mut visuals = egui::Visuals::dark(); + + visuals.panel_fill = egui::Color32::from_rgb(10, 13, 20); + visuals.window_fill = egui::Color32::from_rgb(19, 25, 39); + visuals.extreme_bg_color = egui::Color32::from_rgb(6, 8, 14); + + visuals.widgets.noninteractive.rounding = egui::Rounding::same(10.0); + visuals.widgets.noninteractive.bg_fill = egui::Color32::from_rgb(26, 34, 50); + visuals.widgets.noninteractive.bg_stroke = egui::Stroke::new(1.0_f32, egui::Color32::from_rgb(45, 58, 82)); + + visuals.widgets.inactive.rounding = egui::Rounding::same(10.0); + visuals.widgets.inactive.bg_fill = egui::Color32::from_rgb(26, 34, 50); + + visuals.widgets.hovered.rounding = egui::Rounding::same(10.0); + visuals.widgets.hovered.bg_fill = egui::Color32::from_rgb(45, 58, 82); + visuals.widgets.hovered.bg_stroke = egui::Stroke::new(1.5_f32, egui::Color32::from_rgb(0, 242, 254)); + + visuals.widgets.active.rounding = egui::Rounding::same(10.0); + visuals.widgets.active.bg_fill = egui::Color32::from_rgb(0, 242, 254); + visuals.widgets.active.fg_stroke = egui::Stroke::new(1.0_f32, egui::Color32::BLACK); + + visuals.selection.bg_fill = egui::Color32::from_rgba_premultiplied(0, 242, 254, 70); + + style.visuals = visuals; + style.spacing.item_spacing = egui::vec2(12.0, 12.0); + style.spacing.button_padding = egui::vec2(16.0, 10.0); + ctx.set_style(style); +} + +fn poll_loop(tx: Sender, ctx_store: Arc>, is_busy: Arc) { + let mut last_uid = String::new(); + + loop { + thread::sleep(Duration::from_millis(600)); + + if is_busy.load(Ordering::SeqCst) { + continue; + } + + let ctx = ctx_store.lock().unwrap(); + + let reader = match Acr122u::find_acr122u(&ctx) { + Ok(r) => { + let _ = tx.send(CardEvent::ReaderStatus { + connected: true, + name: r.clone(), + }); + r + } + Err(_) => { + let _ = tx.send(CardEvent::ReaderStatus { + connected: false, + name: "Kein Lesegerät".to_string(), + }); + last_uid.clear(); + let _ = tx.send(CardEvent::CardRemoved); + continue; + } + }; + + match Acr122u::read_card_info(&ctx, &reader) { + Ok(info) => { + if info.uid != last_uid { + last_uid = info.uid.clone(); + let _ = Acr122u::beep(&ctx, &reader, 50, 1); + let _ = tx.send(CardEvent::CardDetected(info)); + } + } + Err(_) => { + if !last_uid.is_empty() { + last_uid.clear(); + let _ = tx.send(CardEvent::CardRemoved); + } + } + } + } +} + +impl eframe::App for NfcApp { + fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) { + while let Ok(evt) = self.rx.try_recv() { + let timestamp = chrono::Local::now().format("%H:%M:%S").to_string(); + match evt { + CardEvent::ReaderStatus { connected, name } => { + self.is_reader_connected = connected; + self.reader_name = name; + } + CardEvent::CardDetected(info) => { + let friendly_type = match info.uid_bytes.len() { + 7 => "Standard NFC-Sticker / Tag (NTAG)", + 4 => "MIFARE Chipkarte / Schlüsselanhänger", + _ => "Kontaktloser NFC-Chip", + }; + self.event_logs.insert(0, format!("[{}] 💳 NFC-Tag erkannt: ID {} ({})", timestamp, info.uid, friendly_type)); + self.current_card = Some(info); + } + CardEvent::CardRemoved => { + if self.current_card.is_some() { + self.event_logs.insert(0, format!("[{}] 🚫 NFC-Tag entfernt", timestamp)); + self.current_card = None; + } + } + } + } + + ctx.request_repaint_after(Duration::from_millis(200)); + + egui::TopBottomPanel::top("top_header").show(ctx, |ui| { + ui.add_space(8.0); + ui.horizontal(|ui| { + ui.label(egui::RichText::new("💎 ACR122U NFC Studio Pro").font(egui::FontId::proportional(22.0)).strong().color(egui::Color32::from_rgb(0, 242, 254))); + ui.label(egui::RichText::new("Premium Edition").font(egui::FontId::proportional(12.0)).color(egui::Color32::from_rgb(148, 163, 184))); + + ui.with_layout(egui::Layout::right_to_left(egui::Align::Center), |ui| { + if self.is_reader_connected { + ui.colored_label(egui::Color32::from_rgb(0, 230, 153), format!("🟢 {}", self.reader_name)); + } else { + ui.colored_label(egui::Color32::from_rgb(255, 75, 87), "🔴 Gerät nicht verbunden"); + } + }); + }); + ui.add_space(8.0); + }); + + egui::TopBottomPanel::top("tab_bar").show(ctx, |ui| { + ui.horizontal(|ui| { + ui.selectable_value(&mut self.active_tab, Tab::Scanner, "📡 Live-Erkennung"); + ui.selectable_value(&mut self.active_tab, Tab::Ndef, "✏️ NFC-Tag Beschreiben"); + ui.selectable_value(&mut self.active_tab, Tab::Mifare, "🔍 Speicher & Klonen"); + ui.selectable_value(&mut self.active_tab, Tab::Password, "🔒 Passwort-Schutz"); + ui.selectable_value(&mut self.active_tab, Tab::Hardware, "🔔 LEDs & Töne"); + ui.selectable_value(&mut self.active_tab, Tab::ExpertApdu, "🛠️ Experten-Befehle"); + }); + }); + + egui::CentralPanel::default().show(ctx, |ui| { + match self.active_tab { + Tab::Scanner => self.render_scanner_tab(ui), + Tab::Ndef => self.render_ndef_tab(ui), + Tab::Mifare => self.render_mifare_tab(ui), + Tab::Password => self.render_password_tab(ui), + Tab::Hardware => self.render_hardware_tab(ui), + Tab::ExpertApdu => self.render_apdu_tab(ui), + } + }); + } +} + +impl NfcApp { + fn render_scanner_tab(&mut self, ui: &mut egui::Ui) { + ui.columns(2, |cols| { + cols[0].group(|ui| { + ui.heading("💳 Aufgelegter NFC-Tag"); + ui.label(egui::RichText::new("Hier siehst du sofort alle Infos zur erkannten Karte.").font(egui::FontId::proportional(12.0)).color(egui::Color32::from_rgb(148, 163, 184))); + ui.add_space(8.0); + + egui::Frame::none() + .fill(egui::Color32::from_rgb(19, 25, 39)) + .stroke(egui::Stroke::new(1.5_f32, egui::Color32::from_rgb(0, 242, 254))) + .rounding(16.0) + .inner_margin(20.0) + .show(ui, |ui| { + ui.horizontal(|ui| { + ui.label(egui::RichText::new("📇 NFC-CHIP").font(egui::FontId::proportional(14.0)).strong().color(egui::Color32::from_rgb(246, 211, 101))); + ui.with_layout(egui::Layout::right_to_left(egui::Align::Center), |ui| { + ui.label(egui::RichText::new("Kontaktlos").font(egui::FontId::proportional(12.0)).color(egui::Color32::from_rgb(0, 242, 254))); + }); + }); + + ui.add_space(16.0); + ui.label(egui::RichText::new("EINDEUTIGE CHIP-ID (UID):").font(egui::FontId::proportional(11.0)).color(egui::Color32::from_rgb(148, 163, 184))); + + if let Some(card) = &self.current_card { + ui.label(egui::RichText::new(&card.uid).font(egui::FontId::monospace(26.0)).strong().color(egui::Color32::from_rgb(246, 211, 101))); + ui.add_space(12.0); + let friendly_type = match card.uid_bytes.len() { + 7 => "Standard NFC-Sticker / Tag (NTAG213/215/216)", + 4 => "MIFARE Classic Chipkarte / Schlüsselanhänger", + _ => "Kontaktloser NFC-Chip", + }; + ui.label(format!("Chip-Typ: {}", friendly_type)); + } else { + ui.label(egui::RichText::new("-- -- -- --").font(egui::FontId::monospace(26.0)).color(egui::Color32::GRAY)); + ui.add_space(12.0); + ui.colored_label(egui::Color32::GRAY, "Bitte halte einen NFC-Tag auf das Gerät..."); + } + }); + }); + + cols[1].group(|ui| { + ui.heading("📜 Echtzeit Aktivitäten-Log"); + ui.label(egui::RichText::new("Verlauf der Erfassungen und Aktionen.").font(egui::FontId::proportional(12.0)).color(egui::Color32::from_rgb(148, 163, 184))); + ui.add_space(6.0); + egui::ScrollArea::vertical().max_height(350.0).show(ui, |ui| { + for log in &self.event_logs { + ui.label(egui::RichText::new(log).font(egui::FontId::monospace(13.0))); + } + }); + }); + }); + } + + fn render_ndef_tab(&mut self, ui: &mut egui::Ui) { + ui.heading("✏️ NFC-Tag Beschreiben"); + ui.label(egui::RichText::new("Wähle aus, was beim Dranhalten eines Smartphones passieren soll:").font(egui::FontId::proportional(12.0)).color(egui::Color32::from_rgb(148, 163, 184))); + ui.add_space(8.0); + + ui.horizontal(|ui| { + ui.selectable_value(&mut self.ndef_subtab, NdefSubTab::Text, "📝 Text & Notiz"); + ui.selectable_value(&mut self.ndef_subtab, NdefSubTab::Url, "🌐 Internet-Link (URL)"); + ui.selectable_value(&mut self.ndef_subtab, NdefSubTab::Wifi, "📶 WLAN Quick-Connect"); + ui.selectable_value(&mut self.ndef_subtab, NdefSubTab::VCard, "🎴 Visitenkarte"); + ui.selectable_value(&mut self.ndef_subtab, NdefSubTab::Geo, "🗺️ Standort / Maps"); + ui.selectable_value(&mut self.ndef_subtab, NdefSubTab::AppLauncher, "📱 App Öffnen"); + }); + + ui.add_space(12.0); + + let mut tlv_payload: Option> = None; + + match self.ndef_subtab { + NdefSubTab::Text => { + ui.group(|ui| { + ui.label("Deine Nachricht / Notiz:"); + ui.add(egui::TextEdit::multiline(&mut self.ndef_text_input).desired_rows(4).desired_width(f32::INFINITY)); + + ui.horizontal(|ui| { + if ui.button("💾 Text als Datei speichern (.txt)").clicked() { + if let Some(path) = rfd::FileDialog::new().add_filter("Textdatei", &["txt"]).save_file() { + let _ = fs::write(path, &self.ndef_text_input); + self.ndef_status = "Text erfolgreich auf dem PC gespeichert!".to_string(); + } + } + if ui.button("📂 Text aus Datei laden (.txt)").clicked() { + if let Some(path) = rfd::FileDialog::new().add_filter("Textdatei", &["txt"]).pick_file() { + if let Ok(content) = fs::read_to_string(path) { + self.ndef_text_input = content; + self.ndef_status = "Text aus Datei geladen!".to_string(); + } + } + } + }); + + tlv_payload = Some(NdefCodec::encode_text(&self.ndef_text_input, &self.ndef_text_lang)); + }); + } + NdefSubTab::Url => { + ui.group(|ui| { + ui.label("Internet-Adresse (öffnet sich beim Scannen automatisch):"); + ui.text_edit_singleline(&mut self.ndef_url_input); + tlv_payload = Some(NdefCodec::encode_url(&self.ndef_url_input)); + }); + } + NdefSubTab::Wifi => { + ui.group(|ui| { + ui.label("WLAN Netz-Name (SSID):"); + ui.text_edit_singleline(&mut self.wifi_ssid); + ui.label("WLAN Passwort:"); + ui.text_edit_singleline(&mut self.wifi_pass); + ui.label(egui::RichText::new("💡 Smartphones verbinden sich beim Dranhalten direkt mit dem WLAN.").font(egui::FontId::proportional(11.0)).color(egui::Color32::from_rgb(148, 163, 184))); + tlv_payload = Some(NdefCodec::encode_wifi(&self.wifi_ssid, &self.wifi_pass)); + }); + } + NdefSubTab::VCard => { + ui.group(|ui| { + ui.label("Name:"); + ui.text_edit_singleline(&mut self.vcard_name); + ui.label("Telefonnummer:"); + ui.text_edit_singleline(&mut self.vcard_phone); + ui.label("E-Mail:"); + ui.text_edit_singleline(&mut self.vcard_email); + ui.label("Firma / Organisation:"); + ui.text_edit_singleline(&mut self.vcard_company); + ui.label(egui::RichText::new("💡 Beim Scannen wird der Kontakt direkt in das Handy-Telefonbuch gespeichert.").font(egui::FontId::proportional(11.0)).color(egui::Color32::from_rgb(148, 163, 184))); + tlv_payload = Some(NdefCodec::encode_vcard(&self.vcard_name, &self.vcard_phone, &self.vcard_email, &self.vcard_company)); + }); + } + NdefSubTab::Geo => { + ui.group(|ui| { + ui.label("Google Maps Standorts-Link:"); + ui.text_edit_singleline(&mut self.geo_url); + tlv_payload = Some(NdefCodec::encode_url(&self.geo_url)); + }); + } + NdefSubTab::AppLauncher => { + ui.group(|ui| { + ui.label("Android App-Name (z. B. com.spotify.music):"); + ui.text_edit_singleline(&mut self.aar_package); + tlv_payload = Some(NdefCodec::encode_aar(&self.aar_package)); + }); + } + } + + ui.add_space(15.0); + + if ui.button("⚡ Auf NFC-Tag Schreiben").clicked() { + if let Some(tlv) = tlv_payload { + self.is_busy.store(true, Ordering::SeqCst); + thread::sleep(Duration::from_millis(50)); + + let pcsc = self.pcsc_ctx.lock().unwrap(); + if let Ok(reader) = Acr122u::find_acr122u(&pcsc) { + if let Ok(mut card) = Acr122u::connect_card_with_ctx(&pcsc, &reader) { + let _ = NtagHandler::ensure_cc_header(&pcsc, &reader, &mut card); + let mut page = 4; + let mut err = false; + + for chunk in tlv.chunks(4) { + let mut p_data = [0u8; 4]; + p_data[..chunk.len()].copy_from_slice(chunk); + if NtagHandler::write_page(&pcsc, &reader, &mut card, page, &p_data).is_err() { + err = true; + self.ndef_status = format!("Schreibfehler auf Seite {}", page); + break; + } + page += 1; + } + + if !err { + let _ = Acr122u::beep(&pcsc, &reader, 100, 2); + self.ndef_status = "✅ Inhalt erfolgreich auf den NFC-Tag geschrieben!".to_string(); + } + } else { + self.ndef_status = "❌ Karte konnte nicht verbunden werden!".to_string(); + } + } + + self.is_busy.store(false, Ordering::SeqCst); + } + } + + ui.add_space(10.0); + ui.colored_label(egui::Color32::from_rgb(0, 242, 254), &self.ndef_status); + } + + fn render_mifare_tab(&mut self, ui: &mut egui::Ui) { + ui.heading("🔍 Speicher Auslesen & Klonen"); + ui.label(egui::RichText::new("Lies den kompletten Speicherinhalt von MIFARE-Karten aus und speichere ihn ab.").font(egui::FontId::proportional(12.0)).color(egui::Color32::from_rgb(148, 163, 184))); + ui.add_space(10.0); + + ui.horizontal(|ui| { + if ui.button("🔄 Karte Auslesen").clicked() { + self.is_busy.store(true, Ordering::SeqCst); + thread::sleep(Duration::from_millis(50)); + + let pcsc = self.pcsc_ctx.lock().unwrap(); + if let Ok(reader) = Acr122u::find_acr122u(&pcsc) { + match MifareHandler::dump_card(&pcsc, &reader) { + Ok(dump) => { + self.mifare_dump = Some(dump); + self.mifare_status = "Auslesen erfolgreich!".to_string(); + } + Err(e) => { + self.mifare_status = format!("Fehler beim Auslesen: {}", e); + } + } + } + + self.is_busy.store(false, Ordering::SeqCst); + } + + if let Some(dump) = &self.mifare_dump { + if ui.button("💾 Als Backup speichern (.json)").clicked() { + if let Some(path) = rfd::FileDialog::new().add_filter("JSON Backup", &["json"]).save_file() { + if let Ok(json) = serde_json::to_string_pretty(dump) { + let _ = fs::write(path, json); + self.mifare_status = "Backup-Datei gespeichert!".to_string(); + } + } + } + } + + if ui.button("📂 Backup aus Datei laden").clicked() { + if let Some(path) = rfd::FileDialog::new().add_filter("JSON Backup", &["json"]).pick_file() { + if let Ok(content) = fs::read_to_string(path) { + if let Ok(loaded_dump) = serde_json::from_str::(&content) { + self.mifare_dump = Some(loaded_dump); + self.mifare_status = "Backup geladen!".to_string(); + } + } + } + } + }); + + ui.colored_label(egui::Color32::from_rgb(0, 242, 254), &self.mifare_status); + ui.add_space(10.0); + + if let Some(dump) = &self.mifare_dump { + egui::ScrollArea::vertical().show(ui, |ui| { + for sec in &dump.sectors { + ui.group(|ui| { + ui.label(egui::RichText::new(format!("Speicherblock {} (Key: {})", sec.sector_number, sec.key_a.as_deref().unwrap_or("Schlüsselgeschützt"))).strong()); + for b in &sec.blocks { + let text_color = if b.is_trailer { egui::Color32::from_rgb(214, 188, 250) } else { egui::Color32::WHITE }; + ui.label(egui::RichText::new(format!("Block {:02}: {} | {}", b.block_number, b.hex_data, b.ascii_data)).font(egui::FontId::monospace(12.0)).color(text_color)); + } + }); + } + }); + } + } + + fn render_password_tab(&mut self, ui: &mut egui::Ui) { + ui.heading("🔒 Passwort-Schutz & Tag Versiegeln"); + ui.label(egui::RichText::new("Schütze deinen NFC-Tag vor unbefugtem Überschreiben.").font(egui::FontId::proportional(12.0)).color(egui::Color32::from_rgb(148, 163, 184))); + ui.add_space(10.0); + + ui.group(|ui| { + ui.label("4-stelliges Passwort (z. B. 1234):"); + ui.text_edit_singleline(&mut self.pwd_input); + + ui.add_space(10.0); + if ui.button("🔐 Passwort auf Tag aktivieren").clicked() { + self.is_busy.store(true, Ordering::SeqCst); + thread::sleep(Duration::from_millis(50)); + + let pcsc = self.pcsc_ctx.lock().unwrap(); + if let Ok(reader) = Acr122u::find_acr122u(&pcsc) { + if let Ok(mut card) = Acr122u::connect_card_with_ctx(&pcsc, &reader) { + let pwd_bytes = self.pwd_input.as_bytes(); + if pwd_bytes.len() == 4 { + let mut p_arr = [0u8; 4]; + p_arr.copy_from_slice(pwd_bytes); + if NtagHandler::write_page(&pcsc, &reader, &mut card, 134, &p_arr).is_ok() { + self.pwd_status = "✅ Passwort erfolgreich auf dem Tag aktiviert!".to_string(); + let _ = Acr122u::beep(&pcsc, &reader, 100, 2); + } else { + self.pwd_status = "❌ Fehler beim Aktivieren des Passworts!".to_string(); + } + } else { + self.pwd_status = "Das Passwort muss genau 4 Zeichen lang sein!".to_string(); + } + } + } + + self.is_busy.store(false, Ordering::SeqCst); + } + }); + + ui.add_space(15.0); + ui.colored_label(egui::Color32::from_rgb(0, 242, 254), &self.pwd_status); + } + + fn render_hardware_tab(&mut self, ui: &mut egui::Ui) { + ui.heading("🔔 LEDs & Signal-Töne des Lesegeräts"); + ui.label(egui::RichText::new("Steuere die Hardware-Signale deines ACR122U Geräts.").font(egui::FontId::proportional(12.0)).color(egui::Color32::from_rgb(148, 163, 184))); + ui.add_space(10.0); + + ui.checkbox(&mut self.led_red, "Rote LED aktivieren"); + ui.checkbox(&mut self.led_green, "Grüne LED aktivieren"); + ui.checkbox(&mut self.led_blink, "Blinken aktivieren"); + ui.checkbox(&mut self.led_beep, "Ton beim Schalten abspielen"); + + ui.add_space(12.0); + if ui.button("⚡ LED & Ton-Einstellungen Anwenden").clicked() { + let pcsc = self.pcsc_ctx.lock().unwrap(); + let config = LedBuzzerConfig { + red: self.led_red, + green: self.led_green, + blink_red: self.led_blink, + blink_green: self.led_blink, + blink_count: if self.led_blink { 4 } else { 0 }, + t1_duration_ms: 100, + t2_duration_ms: 100, + buzzer_mode: if self.led_beep { 1 } else { 0 }, + }; + if let Ok(reader) = Acr122u::find_acr122u(&pcsc) { + let _ = Acr122u::set_led_buzzer(&pcsc, &reader, &config); + } + } + + ui.add_space(20.0); + ui.label("Signalton testen:"); + ui.horizontal(|ui| { + if ui.button("🔊 1x Signalton").clicked() { + let pcsc = self.pcsc_ctx.lock().unwrap(); + if let Ok(reader) = Acr122u::find_acr122u(&pcsc) { + let _ = Acr122u::beep(&pcsc, &reader, 100, 1); + } + } + if ui.button("🔊 2x Bestätigungston").clicked() { + let pcsc = self.pcsc_ctx.lock().unwrap(); + if let Ok(reader) = Acr122u::find_acr122u(&pcsc) { + let _ = Acr122u::beep(&pcsc, &reader, 100, 2); + } + } + }); + } + + fn render_apdu_tab(&mut self, ui: &mut egui::Ui) { + ui.heading("🛠️ Experten-Befehle (Rohdaten / APDU)"); + ui.label(egui::RichText::new("Manuelle Befehlseingabe für fortgeschrittene Nutzer.").font(egui::FontId::proportional(12.0)).color(egui::Color32::from_rgb(148, 163, 184))); + ui.add_space(10.0); + + ui.label("Befehl in Hexadezimal (z. B. FF 00 48 00 00):"); + ui.text_edit_singleline(&mut self.apdu_input); + + if ui.button("Befehl Senden").clicked() { + let pcsc = self.pcsc_ctx.lock().unwrap(); + if let Ok(reader) = Acr122u::find_acr122u(&pcsc) { + if let Ok(card) = Acr122u::connect_card_with_ctx(&pcsc, &reader).or_else(|_| Acr122u::connect_direct_with_ctx(&pcsc, &reader)) { + if let Ok(bytes) = hex::decode(self.apdu_input.replace(" ", "")) { + match Acr122u::transmit(&card, &bytes) { + Ok((data, sw1, sw2)) => { + let entry = format!("> {}\n< DATEN: {}\n< STATUS: {:02X}{:02X}", self.apdu_input, hex::encode_upper(&data), sw1, sw2); + self.apdu_response_log.insert(0, entry); + } + Err(e) => { + self.apdu_response_log.insert(0, format!("❌ FEHLER: {}", e)); + } + } + } + } + } + } + + ui.add_space(15.0); + egui::ScrollArea::vertical().show(ui, |ui| { + for log in &self.apdu_response_log { + ui.label(egui::RichText::new(log).font(egui::FontId::monospace(13.0))); + ui.separator(); + } + }); + } +} + +fn main() -> eframe::Result<()> { + let options = eframe::NativeOptions { + viewport: egui::ViewportBuilder::default() + .with_title("ACR122U NFC Studio Pro (Transparent Reconnect)") + .with_inner_size([1150.0, 780.0]), + ..Default::default() + }; + + eframe::run_native( + "nfc_tool", + options, + Box::new(|cc| Ok(Box::new(NfcApp::new(cc)))), + ) +} diff --git a/src/mifare.rs b/src/mifare.rs new file mode 100644 index 0000000..e08dfe1 --- /dev/null +++ b/src/mifare.rs @@ -0,0 +1,178 @@ +use crate::acr122u::Acr122u; +use anyhow::{anyhow, Result}; +use pcsc::{Card, Context}; +use serde::{Deserialize, Serialize}; + +pub const DEFAULT_KEYS: &[&[u8; 6]] = &[ + &[0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF], // Default Factory Key + &[0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5], // MAD Key + &[0xD3, 0xF7, 0xD3, 0xF7, 0xD3, 0xF7], // NFC Forum Key + &[0x00, 0x00, 0x00, 0x00, 0x00, 0x00], // Blank Key + &[0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5], + &[0x4D, 0x3A, 0x99, 0xC3, 0x51, 0xDD], + &[0x1A, 0x2B, 0x3C, 0x4D, 0x5E, 0x6F], + &[0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC], + &[0xA0, 0xB1, 0xC2, 0xD3, 0xE4, 0xF5], + &[0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF], +]; + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct MifareBlock { + pub block_number: u8, + pub hex_data: String, + pub ascii_data: String, + pub is_trailer: bool, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct MifareSector { + pub sector_number: u8, + pub key_a: Option, + pub key_b: Option, + pub blocks: Vec, + pub is_authenticated: bool, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct MifareDump { + pub uid: String, + pub sectors_count: u8, + pub sectors: Vec, +} + +pub struct MifareHandler; + +impl MifareHandler { + pub fn load_key(card: &Card, key_slot: u8, key: &[u8; 6]) -> Result<()> { + let mut apdu = vec![0xFF, 0x82, 0x00, key_slot, 0x06]; + apdu.extend_from_slice(key); + let (_, sw1, sw2) = Acr122u::transmit(card, &apdu)?; + if sw1 == 0x90 && sw2 == 0x00 { + Ok(()) + } else { + Err(anyhow!("Fehler beim Laden des Keys (SW: {:02X}{:02X})", sw1, sw2)) + } + } + + pub fn authenticate_block(card: &Card, block: u8, key_type: u8, key_slot: u8) -> Result<()> { + let apdu = [0xFF, 0x86, 0x00, 0x00, 0x05, 0x01, 0x00, block, key_type, key_slot]; + let (_, sw1, sw2) = Acr122u::transmit(card, &apdu)?; + if sw1 == 0x90 && sw2 == 0x00 { + Ok(()) + } else { + Err(anyhow!("Authentifizierung fehlgeschlagen für Block {} (SW: {:02X}{:02X})", block, sw1, sw2)) + } + } + + pub fn auth_with_key(card: &Card, block: u8, key_type: u8, key: &[u8; 6]) -> Result<()> { + Self::load_key(card, 0, key)?; + Self::authenticate_block(card, block, key_type, 0) + } + + pub fn read_block(card: &Card, block: u8) -> Result> { + let apdu = [0xFF, 0xB0, 0x00, block, 0x10]; + let (data, sw1, sw2) = Acr122u::transmit(card, &apdu)?; + if sw1 == 0x90 && sw2 == 0x00 && data.len() == 16 { + Ok(data) + } else { + Err(anyhow!("Lesen von Block {} fehlgeschlagen (SW: {:02X}{:02X})", block, sw1, sw2)) + } + } + + pub fn write_block(card: &Card, block: u8, data: &[u8; 16]) -> Result<()> { + let mut apdu = vec![0xFF, 0xD6, 0x00, block, 0x10]; + apdu.extend_from_slice(data); + let (_, sw1, sw2) = Acr122u::transmit(card, &apdu)?; + if sw1 == 0x90 && sw2 == 0x00 { + Ok(()) + } else { + Err(anyhow!("Schreiben in Block {} fehlgeschlagen (SW: {:02X}{:02X})", block, sw1, sw2)) + } + } + + pub fn scan_sector(card: &Card, sector: u8, custom_keys: Option<&[[u8; 6]]>) -> Result { + let first_block = sector * 4; + let mut keys_to_test = DEFAULT_KEYS.to_vec(); + + let mut extra_keys = Vec::new(); + if let Some(user_keys) = custom_keys { + for k in user_keys { + extra_keys.push(k); + } + keys_to_test.extend(extra_keys); + } + + let mut found_key_a: Option<[u8; 6]> = None; + let mut found_key_b: Option<[u8; 6]> = None; + + for &k in &keys_to_test { + if Self::auth_with_key(card, first_block, 0x60, k).is_ok() { + found_key_a = Some(*k); + break; + } + } + + for &k in &keys_to_test { + if Self::auth_with_key(card, first_block, 0x61, k).is_ok() { + found_key_b = Some(*k); + break; + } + } + + let is_auth = found_key_a.is_some() || found_key_b.is_some(); + let mut blocks = Vec::new(); + + if is_auth { + let (key_type, active_key) = if let Some(ka) = found_key_a { + (0x60, ka) + } else { + (0x61, found_key_b.unwrap()) + }; + + for b in 0..4 { + let block_num = first_block + b; + let _ = Self::auth_with_key(card, block_num, key_type, &active_key); + let block_data = match Self::read_block(card, block_num) { + Ok(d) => d, + Err(_) => vec![0u8; 16], + }; + + let hex_str = hex::encode_upper(&block_data); + let ascii_str: String = block_data.iter().map(|&c| if c >= 32 && c <= 126 { c as char } else { '.' }).collect(); + + blocks.push(MifareBlock { + block_number: block_num, + hex_data: hex_str, + ascii_data: ascii_str, + is_trailer: b == 3, + }); + } + } + + Ok(MifareSector { + sector_number: sector, + key_a: found_key_a.map(|k| hex::encode_upper(k)), + key_b: found_key_b.map(|k| hex::encode_upper(k)), + blocks, + is_authenticated: is_auth, + }) + } + + pub fn dump_card(ctx: &Context, reader: &str) -> Result { + let card = Acr122u::connect_card_with_ctx(ctx, reader)?; + let uid_bytes = Acr122u::get_card_uid(&card)?; + let uid_hex = hex::encode_upper(&uid_bytes); + + let mut sectors = Vec::new(); + for sec in 0..16 { + let sector_info = Self::scan_sector(&card, sec, None)?; + sectors.push(sector_info); + } + + Ok(MifareDump { + uid: uid_hex, + sectors_count: 16, + sectors, + }) + } +} diff --git a/src/ndef.rs b/src/ndef.rs new file mode 100644 index 0000000..d3f673d --- /dev/null +++ b/src/ndef.rs @@ -0,0 +1,168 @@ +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub enum NdefPayload { + Url(String), + Text { text: String, lang: String }, + Wifi { ssid: String, password: String, auth: String }, + Contact { name: String, phone: String, email: String, company: String }, + Geo { lat: f64, lon: f64, label: String }, + AppLauncher { package_name: String }, + Custom { mime: String, payload: String }, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct NdefRecord { + pub tnf: u8, + pub record_type: String, + pub payload_hex: String, + pub payload_parsed: NdefPayload, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct NdefMessage { + pub records: Vec, +} + +pub struct NdefCodec; + +impl NdefCodec { + /// Encode URL into NDEF TLV bytes + pub fn encode_url(url: &str) -> Vec { + let (prefix_code, clean_url) = if url.starts_with("https://www.") { + (0x02u8, &url[12..]) + } else if url.starts_with("http://www.") { + (0x01u8, &url[11..]) + } else if url.starts_with("https://") { + (0x04u8, &url[8..]) + } else if url.starts_with("http://") { + (0x03u8, &url[7..]) + } else if url.starts_with("tel:") { + (0x05u8, &url[4..]) + } else if url.starts_with("mailto:") { + (0x06u8, &url[7..]) + } else if url.starts_with("geo:") { + (0x00u8, url) + } else { + (0x00u8, url) + }; + + let mut payload = vec![prefix_code]; + payload.extend_from_slice(clean_url.as_bytes()); + + let type_bytes = b"U"; + let payload_len = payload.len() as u8; + + let mut record = vec![0xD1, 0x01, payload_len, type_bytes[0]]; + record.extend(payload); + + let mut tlv = vec![0x03, record.len() as u8]; + tlv.extend(record); + tlv.push(0xFE); + + tlv + } + + /// Encode Text into NDEF TLV bytes + pub fn encode_text(text: &str, lang: &str) -> Vec { + let lang_bytes = lang.as_bytes(); + let status_byte = (lang_bytes.len() & 0x3F) as u8; + + let mut payload = vec![status_byte]; + payload.extend_from_slice(lang_bytes); + payload.extend_from_slice(text.as_bytes()); + + let type_bytes = b"T"; + let payload_len = payload.len() as u8; + + let mut record = vec![0xD1, 0x01, payload_len, type_bytes[0]]; + record.extend(payload); + + let mut tlv = vec![0x03, record.len() as u8]; + tlv.extend(record); + tlv.push(0xFE); + + tlv + } + + /// Encode Wi-Fi Configuration into NDEF MIME payload (application/vnd.wfa.wsc) + pub fn encode_wifi(ssid: &str, password: &str) -> Vec { + let mime_type = b"application/vnd.wfa.wsc"; + + // Build WSC (Wi-Fi Simple Configuration) TLV structure + let mut wsc = Vec::new(); + + // Network Index (0x1026) + wsc.extend_from_slice(&[0x10, 0x26, 0x00, 0x01, 0x01]); + + // SSID (0x1045) + let ssid_bytes = ssid.as_bytes(); + wsc.extend_from_slice(&[0x10, 0x45]); + wsc.extend_from_slice(&(ssid_bytes.len() as u16).to_be_bytes()); + wsc.extend_from_slice(ssid_bytes); + + // Authentication Type (0x1003): 0x0020 = WPA2-Personal + wsc.extend_from_slice(&[0x10, 0x03, 0x00, 0x02, 0x00, 0x20]); + + // Encryption Type (0x100F): 0x0008 = AES / CCMP + wsc.extend_from_slice(&[0x10, 0x0F, 0x00, 0x02, 0x00, 0x08]); + + // Network Key / Password (0x1027) + let pass_bytes = password.as_bytes(); + wsc.extend_from_slice(&[0x10, 0x27]); + wsc.extend_from_slice(&(pass_bytes.len() as u16).to_be_bytes()); + wsc.extend_from_slice(pass_bytes); + + // MAC Address (0x1020) broadcast + wsc.extend_from_slice(&[0x10, 0x20, 0x00, 0x06, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF]); + + // Wrap in NDEF MIME Record (TNF = 0x02 MIME Media Type) + // Header: MB=1, ME=1, CF=0, SR=1, IL=0, TNF=0x02 => 0xD2 + let mut record = vec![0xD2, mime_type.len() as u8, wsc.len() as u8]; + record.extend_from_slice(mime_type); + record.extend(wsc); + + let mut tlv = vec![0x03, record.len() as u8]; + tlv.extend(record); + tlv.push(0xFE); + + tlv + } + + /// Encode vCard (Contact Card) into NDEF MIME payload (text/vcard) + pub fn encode_vcard(name: &str, phone: &str, email: &str, company: &str) -> Vec { + let mime_type = b"text/vcard"; + let vcard_str = format!( + "BEGIN:VCARD\r\nVERSION:3.0\r\nFN:{}\r\nTEL;TYPE=CELL:{}\r\nEMAIL:{}\r\nORG:{}\r\nEND:VCARD", + name, phone, email, company + ); + let payload_bytes = vcard_str.as_bytes(); + + let mut record = vec![0xD2, mime_type.len() as u8, payload_bytes.len() as u8]; + record.extend_from_slice(mime_type); + record.extend_from_slice(payload_bytes); + + let mut tlv = vec![0x03, record.len() as u8]; + tlv.extend(record); + tlv.push(0xFE); + + tlv + } + + /// Encode Android Application Record (AAR) to launch specific Android App + pub fn encode_aar(package_name: &str) -> Vec { + let type_bytes = b"android.com:pkg"; + let payload_bytes = package_name.as_bytes(); + + // TNF = 0x04 (NFC Forum External Type) + let mut record = vec![0xD4, type_bytes.len() as u8, payload_bytes.len() as u8]; + record.extend_from_slice(type_bytes); + record.extend_from_slice(payload_bytes); + + let mut tlv = vec![0x03, record.len() as u8]; + tlv.extend(record); + tlv.push(0xFE); + + tlv + } +} diff --git a/src/ntag.rs b/src/ntag.rs new file mode 100644 index 0000000..947dcdc --- /dev/null +++ b/src/ntag.rs @@ -0,0 +1,67 @@ +use crate::acr122u::Acr122u; +use anyhow::{anyhow, Result}; +use pcsc::{Card, Context, MAX_BUFFER_SIZE}; +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct NtagPage { + pub page_number: u8, + pub hex_data: String, + pub ascii_data: String, +} + +pub struct NtagHandler; + +impl NtagHandler { + pub fn read_pages(card: &Card, start_page: u8) -> Result> { + let apdu = [0xFF, 0xB0, 0x00, start_page, 0x10]; + let (data, sw1, sw2) = Acr122u::transmit(card, &apdu)?; + if sw1 == 0x90 && sw2 == 0x00 && data.len() >= 4 { + Ok(data) + } else { + Err(anyhow!("Lesen ab Seite {} fehlgeschlagen (SW: {:02X}{:02X})", start_page, sw1, sw2)) + } + } + + /// Write 4 bytes to page with EEPROM write cycle delay & transparent reset auto-reconnect + pub fn write_page(ctx: &Context, reader: &str, card: &mut Card, page: u8, data: &[u8; 4]) -> Result<()> { + let mut apdu = vec![0xFF, 0xD6, 0x00, page, 0x04]; + apdu.extend_from_slice(data); + + for _attempt in 0..5 { + let mut receive_buf = [0u8; MAX_BUFFER_SIZE]; + match card.transmit(&apdu, &mut receive_buf) { + Ok(resp) if resp.len() >= 2 => { + let sw1 = resp[resp.len() - 2]; + let sw2 = resp[resp.len() - 1]; + if sw1 == 0x90 && sw2 == 0x00 { + std::thread::sleep(std::time::Duration::from_millis(20)); + return Ok(()); + } + } + _ => { + // Transparent auto-reconnect if card was reset by driver + std::thread::sleep(std::time::Duration::from_millis(30)); + if let Ok(new_card) = Acr122u::connect_card_with_ctx(ctx, reader) { + *card = new_card; + } + } + } + } + + Err(anyhow!("Schreiben auf Seite {} fehlgeschlagen", page)) + } + + pub fn ensure_cc_header(ctx: &Context, reader: &str, card: &mut Card) -> Result<()> { + if let Ok(pages) = Self::read_pages(card, 0) { + if pages.len() >= 16 { + let p3 = &pages[12..16]; + if p3[0] != 0xE1 { + let default_cc = [0xE1, 0x10, 0x3E, 0x00]; + let _ = Self::write_page(ctx, reader, card, 3, &default_cc); + } + } + } + Ok(()) + } +} diff --git a/src/server.rs b/src/server.rs new file mode 100644 index 0000000..9dfdb10 --- /dev/null +++ b/src/server.rs @@ -0,0 +1,445 @@ +use crate::acr122u::{Acr122u, CardInfo, LedBuzzerConfig}; +use crate::mifare::MifareHandler; +use crate::ndef::NdefCodec; +use crate::ntag::NtagHandler; +use anyhow::Result; +use axum::{ + extract::{ + ws::{Message, WebSocket, WebSocketUpgrade}, + State, + }, + response::{Html, IntoResponse, Json}, + routing::{get, post}, + Router, +}; +use futures_util::{SinkExt, StreamExt}; +use pcsc::Context; +use serde::{Deserialize, Serialize}; +use std::sync::{Arc, Mutex}; +use std::time::Duration; +use tokio::sync::{broadcast, Mutex as AsyncMutex}; +use tower_http::cors::CorsLayer; +use tracing::info; + +#[derive(Clone)] +pub struct AppState { + pub tx: broadcast::Sender, + pub last_card: Arc>>, + pub reader_lock: Arc>, + pub pcsc_ctx: Arc, +} + +#[derive(Debug, Serialize, Deserialize)] +pub struct LedRequest { + pub red: bool, + pub green: bool, + pub blink: bool, + pub beep: bool, +} + +#[derive(Debug, Serialize, Deserialize)] +pub struct WriteBlockRequest { + pub block: u8, + pub hex_data: String, + pub key_a: Option, +} + +#[derive(Debug, Serialize, Deserialize)] +pub struct WriteNdefUrlRequest { + pub url: String, +} + +#[derive(Debug, Serialize, Deserialize)] +pub struct WriteNdefTextRequest { + pub text: String, + pub lang: String, +} + +#[derive(Debug, Serialize, Deserialize)] +pub struct ApduRequest { + pub apdu_hex: String, +} + +pub async fn start_server(port: u16) -> Result<()> { + let ctx = Acr122u::create_context()?; + let pcsc_ctx = Arc::new(ctx); + + let (tx, _) = broadcast::channel::(100); + let state = AppState { + tx: tx.clone(), + last_card: Arc::new(Mutex::new(None)), + reader_lock: Arc::new(AsyncMutex::new(())), + pcsc_ctx: pcsc_ctx.clone(), + }; + + // Background card polling thread + let tx_poll = tx.clone(); + let card_state_store = state.last_card.clone(); + let lock_poll = state.reader_lock.clone(); + let poll_ctx = pcsc_ctx.clone(); + tokio::spawn(async move { + poll_cards_loop(tx_poll, card_state_store, lock_poll, poll_ctx).await; + }); + + let app = Router::new() + .route("/", get(index_handler)) + .route("/ws", get(ws_handler)) + .route("/api/info", get(get_info_handler)) + .route("/api/led", post(set_led_handler)) + .route("/api/mifare/dump", post(mifare_dump_handler)) + .route("/api/mifare/write", post(mifare_write_handler)) + .route("/api/ntag/dump", post(ntag_dump_handler)) + .route("/api/ndef/write-url", post(write_ndef_url_handler)) + .route("/api/ndef/write-text", post(write_ndef_text_handler)) + .route("/api/apdu", post(apdu_transceive_handler)) + .layer(CorsLayer::permissive()) + .with_state(state); + + let addr = format!("127.0.0.1:{}", port); + info!("🚀 NFC Web Server gestartet unter http://{}", addr); + + let listener = tokio::net::TcpListener::bind(&addr).await?; + axum::serve(listener, app).await?; + Ok(()) +} + +async fn poll_cards_loop( + tx: broadcast::Sender, + card_store: Arc>>, + reader_lock: Arc>, + ctx: Arc, +) { + let mut last_uid = String::new(); + + loop { + tokio::time::sleep(Duration::from_millis(600)).await; + + let _guard = reader_lock.lock().await; + + let reader = match Acr122u::find_acr122u(&ctx) { + Ok(r) => r, + Err(_) => { + let msg = serde_json::json!({ + "event": "reader_status", + "connected": false, + "reader": "Kein Lesegerät" + }).to_string(); + let _ = tx.send(msg); + last_uid.clear(); + let mut guard = card_store.lock().unwrap(); + *guard = None; + continue; + } + }; + + match Acr122u::read_card_info(&ctx, &reader) { + Ok(info) => { + if info.uid != last_uid { + last_uid = info.uid.clone(); + { + let mut guard = card_store.lock().unwrap(); + *guard = Some(info.clone()); + } + + let _ = Acr122u::beep(&ctx, &reader, 50, 1); + + let msg = serde_json::json!({ + "event": "card_detected", + "connected": true, + "reader": reader, + "uid": info.uid, + "card_type": info.card_type, + "ats": info.ats, + }).to_string(); + let _ = tx.send(msg); + } + } + Err(_) => { + if !last_uid.is_empty() { + last_uid.clear(); + { + let mut guard = card_store.lock().unwrap(); + *guard = None; + } + let msg = serde_json::json!({ + "event": "card_removed", + "connected": true, + "reader": reader + }).to_string(); + let _ = tx.send(msg); + } + } + } + } +} + +async fn index_handler() -> Html<&'static str> { + Html(include_str!("../static/index.html")) +} + +async fn ws_handler(ws: WebSocketUpgrade, State(state): State) -> impl IntoResponse { + ws.on_upgrade(|socket| handle_socket(socket, state)) +} + +async fn handle_socket(socket: WebSocket, state: AppState) { + let (mut sender, _) = socket.split(); + let mut rx = state.tx.subscribe(); + + if let Ok(reader) = Acr122u::find_acr122u(&state.pcsc_ctx) { + let fw = Acr122u::get_firmware(&state.pcsc_ctx, &reader).unwrap_or_else(|_| "Unknown".to_string()); + let init_msg = serde_json::json!({ + "event": "init", + "connected": true, + "reader": reader, + "firmware": fw + }).to_string(); + let _ = sender.send(Message::Text(init_msg)).await; + } + + while let Ok(msg) = rx.recv().await { + if sender.send(Message::Text(msg)).await.is_err() { + break; + } + } +} + +async fn get_info_handler(State(state): State) -> Json { + let _guard = state.reader_lock.lock().await; + match Acr122u::find_acr122u(&state.pcsc_ctx) { + Ok(reader) => { + let fw = Acr122u::get_firmware(&state.pcsc_ctx, &reader).unwrap_or_else(|e| e.to_string()); + let card_info = Acr122u::read_card_info(&state.pcsc_ctx, &reader).ok(); + Json(serde_json::json!({ + "connected": true, + "reader": reader, + "firmware": fw, + "card": card_info + })) + } + Err(e) => Json(serde_json::json!({ + "connected": false, + "error": e.to_string() + })), + } +} + +async fn set_led_handler( + State(state): State, + Json(req): Json, +) -> Json { + let _guard = state.reader_lock.lock().await; + let reader = match Acr122u::find_acr122u(&state.pcsc_ctx) { + Ok(r) => r, + Err(e) => return Json(serde_json::json!({"success": false, "error": e.to_string()})), + }; + + let config = LedBuzzerConfig { + red: req.red, + green: req.green, + blink_red: req.blink, + blink_green: req.blink, + blink_count: if req.blink { 4 } else { 0 }, + t1_duration_ms: 100, + t2_duration_ms: 100, + buzzer_mode: if req.beep { 1 } else { 0 }, + }; + + match Acr122u::set_led_buzzer(&state.pcsc_ctx, &reader, &config) { + Ok(_) => Json(serde_json::json!({"success": true})), + Err(e) => Json(serde_json::json!({"success": false, "error": e.to_string()})), + } +} + +async fn mifare_dump_handler(State(state): State) -> Json { + let _guard = state.reader_lock.lock().await; + let reader = match Acr122u::find_acr122u(&state.pcsc_ctx) { + Ok(r) => r, + Err(e) => return Json(serde_json::json!({"success": false, "error": e.to_string()})), + }; + + match MifareHandler::dump_card(&state.pcsc_ctx, &reader) { + Ok(dump) => Json(serde_json::json!({"success": true, "dump": dump})), + Err(e) => Json(serde_json::json!({"success": false, "error": e.to_string()})), + } +} + +async fn mifare_write_handler( + State(state): State, + Json(req): Json, +) -> Json { + let _guard = state.reader_lock.lock().await; + let reader = match Acr122u::find_acr122u(&state.pcsc_ctx) { + Ok(r) => r, + Err(e) => return Json(serde_json::json!({"success": false, "error": e.to_string()})), + }; + + let bytes = match hex::decode(&req.hex_data) { + Ok(b) if b.len() == 16 => b, + _ => return Json(serde_json::json!({"success": false, "error": "Daten müssen genau 16 Hex-Bytes (32 Zeichen) lang sein!"})), + }; + + let card = match Acr122u::connect_card_with_ctx(&state.pcsc_ctx, &reader) { + Ok(c) => c, + Err(e) => return Json(serde_json::json!({"success": false, "error": e.to_string()})), + }; + + let key_bytes = req.key_a.as_ref() + .and_then(|k| hex::decode(k).ok()) + .and_then(|b| if b.len() == 6 { Some([b[0], b[1], b[2], b[3], b[4], b[5]]) } else { None }) + .unwrap_or([0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF]); + + if let Err(e) = MifareHandler::auth_with_key(&card, req.block, 0x60, &key_bytes) { + return Json(serde_json::json!({"success": false, "error": format!("Authentifizierung fehlgeschlagen: {}", e)})); + } + + let mut data_arr = [0u8; 16]; + data_arr.copy_from_slice(&bytes); + + match MifareHandler::write_block(&card, req.block, &data_arr) { + Ok(_) => { + let _ = Acr122u::beep(&state.pcsc_ctx, &reader, 100, 2); + Json(serde_json::json!({"success": true})) + } + Err(e) => Json(serde_json::json!({"success": false, "error": e.to_string()})), + } +} + +async fn ntag_dump_handler(State(state): State) -> Json { + let _guard = state.reader_lock.lock().await; + let reader = match Acr122u::find_acr122u(&state.pcsc_ctx) { + Ok(r) => r, + Err(e) => return Json(serde_json::json!({"success": false, "error": e.to_string()})), + }; + + match NtagHandler::dump_tag(&state.pcsc_ctx, &reader, 135) { + Ok(dump) => Json(serde_json::json!({"success": true, "dump": dump})), + Err(e) => Json(serde_json::json!({"success": false, "error": e.to_string()})), + } +} + +async fn write_ndef_url_handler( + State(state): State, + Json(req): Json, +) -> Json { + let _guard = state.reader_lock.lock().await; + let reader = match Acr122u::find_acr122u(&state.pcsc_ctx) { + Ok(r) => r, + Err(e) => return Json(serde_json::json!({"success": false, "error": e.to_string()})), + }; + + let tlv = NdefCodec::encode_url(&req.url); + + let card = match Acr122u::connect_card_with_ctx(&state.pcsc_ctx, &reader) { + Ok(c) => c, + Err(e) => return Json(serde_json::json!({"success": false, "error": e.to_string()})), + }; + + // Ensure Capability Container (CC) on Page 3 is set + let _ = NtagHandler::ensure_cc_header(&card); + + let mut page = 4; + let mut chunks = tlv.chunks(4); + + while let Some(chunk) = chunks.next() { + let mut page_data = [0u8; 4]; + for (i, &b) in chunk.iter().enumerate() { + page_data[i] = b; + } + + if let Err(e) = NtagHandler::write_page(&card, page, &page_data) { + return Json(serde_json::json!({"success": false, "error": format!("Schreibfehler auf Seite {}: {}", page, e)})); + } + + page += 1; + } + + let _ = Acr122u::beep(&state.pcsc_ctx, &reader, 100, 2); + Json(serde_json::json!({"success": true, "written_bytes": tlv.len()})) +} + +async fn write_ndef_text_handler( + State(state): State, + Json(req): Json, +) -> Json { + let _guard = state.reader_lock.lock().await; + let reader = match Acr122u::find_acr122u(&state.pcsc_ctx) { + Ok(r) => r, + Err(e) => return Json(serde_json::json!({"success": false, "error": e.to_string()})), + }; + + let tlv = NdefCodec::encode_text(&req.text, &req.lang); + + let card = match Acr122u::connect_card_with_ctx(&state.pcsc_ctx, &reader) { + Ok(c) => c, + Err(e) => return Json(serde_json::json!({"success": false, "error": e.to_string()})), + }; + + let _ = NtagHandler::ensure_cc_header(&card); + + let mut page = 4; + let mut chunks = tlv.chunks(4); + + while let Some(chunk) = chunks.next() { + let mut page_data = [0u8; 4]; + for (i, &b) in chunk.iter().enumerate() { + page_data[i] = b; + } + + if let Err(e) = NtagHandler::write_page(&card, page, &page_data) { + return Json(serde_json::json!({"success": false, "error": format!("Schreibfehler auf Seite {}: {}", page, e)})); + } + + page += 1; + } + + let _ = Acr122u::beep(&state.pcsc_ctx, &reader, 100, 2); + Json(serde_json::json!({"success": true, "written_bytes": tlv.len()})) +} + +async fn apdu_transceive_handler( + State(state): State, + Json(req): Json, +) -> Json { + let _guard = state.reader_lock.lock().await; + let reader = match Acr122u::find_acr122u(&state.pcsc_ctx) { + Ok(r) => r, + Err(e) => return Json(serde_json::json!({"success": false, "error": e.to_string()})), + }; + + let apdu_bytes = match hex::decode(req.apdu_hex.replace(" ", "")) { + Ok(b) => b, + Err(_) => return Json(serde_json::json!({"success": false, "error": "Ungültiger Hex-String!"})), + }; + + let card = match Acr122u::connect_card_with_ctx(&state.pcsc_ctx, &reader) { + Ok(c) => c, + Err(_) => match Acr122u::connect_direct_with_ctx(&state.pcsc_ctx, &reader) { + Ok(c) => c, + Err(e) => return Json(serde_json::json!({"success": false, "error": e.to_string()})), + }, + }; + + match Acr122u::transmit(&card, &apdu_bytes) { + Ok((data, sw1, sw2)) => { + let status = match (sw1, sw2) { + (0x90, 0x00) => "90 00 (Erfolg / Command OK)".to_string(), + (0x63, 0x00) => "63 00 (Operation fehlgeschlagen)".to_string(), + (0x6A, 0x81) => "6A 81 (Funktion nicht unterstützt)".to_string(), + (0x6A, 0x82) => "6A 82 (Datei / Block nicht gefunden)".to_string(), + (0x69, 0x82) => "69 82 (Zugriff verweigert / Auth erforderlich)".to_string(), + _ => format!("{:02X} {:02X} (Status Code)", sw1, sw2), + }; + + Json(serde_json::json!({ + "success": true, + "response": { + "data_hex": hex::encode_upper(&data), + "sw1": format!("{:02X}", sw1), + "sw2": format!("{:02X}", sw2), + "status": status + } + })) + } + Err(e) => Json(serde_json::json!({"success": false, "error": e.to_string()})), + } +} diff --git a/static/index.html b/static/index.html new file mode 100644 index 0000000..2bc0765 --- /dev/null +++ b/static/index.html @@ -0,0 +1,709 @@ + + + + + + ACR122U NFC Studio Pro + + + + + + + +
+
+
NFC
+
+
ACR122U Studio Pro
+
PC/SC NFC Reader & Writer Software
+
+
+
+
+ Verbindung wird aufgebaut... +
+
+ + + +
+ +
+
+
+
+
💳 Erkannte NFC Karte
+
+
+
+
+ NFC ISO/IEC 14443 +
+
+
CARD UID
+
-- -- -- --
+
+
+
Typ: Keine Karte aufgelegt
+
ATS: --
+
+
+
+ +
+
+
📜 Live Event Stream
+
+
+
Warte auf NFC-Tag Interaktionen...
+
+
+
+
+ + +
+
+
+
💡 ACR122U LED & Buzzer Steuerung
+
+
+
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+ +
+
+ +
+ + + +
+
+
+
+
+ + +
+
+
+
🔑 MIFARE Classic 1K Memory Map & Key Cracker
+ +
+
+
Klicke auf "Karte Auslesen", um alle 16 Sektoren zu scannen.
+
+
+
+ + +
+
+
+
🏷️ NDEF Nachricht auf Tag Schreiben
+
+
+ + +
+ +
+ + +
+ + + + +
+
+ + +
+
+
+
⚡ Raw APDU Command Studio
+
+
+ +
+ + + + +
+
+
+ + +
+ + +
+ +
+
Ergebnisse werden hier angezeigt...
+
+
+
+
+
+ + + +