diff --git a/Cargo.lock b/Cargo.lock index 7c4b07f..3af5dde 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,9 +4,9 @@ version = 3 [[package]] name = "addr2line" -version = "0.15.2" +version = "0.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7a2e47a1fbe209ee101dd6d61285226744c6c8d3c21c8dc878ba6cb9f467f3a" +checksum = "b9ecd88a8c8378ca913a680cd98f0f13ac67383d35993f86c90a70e3f137816b" dependencies = [ "gimli", ] @@ -73,9 +73,9 @@ dependencies = [ [[package]] name = "aho-corasick" -version = "0.7.15" +version = "0.7.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7404febffaa47dac81aa44dba71523c9d069b1bdc50a77db41195149e17f68e5" +checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f" dependencies = [ "memchr", ] @@ -89,12 +89,6 @@ dependencies = [ "winapi 0.3.9", ] -[[package]] -name = "arrayvec" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b" - [[package]] name = "atomicwrites" version = "0.2.5" @@ -131,9 +125,9 @@ checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" [[package]] name = "backtrace" -version = "0.3.59" +version = "0.3.63" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4717cfcbfaa661a0fd48f8453951837ae7e8f81e481fbb136e3202d72805a744" +checksum = "321629d8ba6513061f26707241fa9bc89524ff1cd7a915a97ef0c62c666ce1b6" dependencies = [ "addr2line", "cc", @@ -187,18 +181,6 @@ version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" -[[package]] -name = "bitvec" -version = "0.19.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8942c8d352ae1838c9dda0b0ca2ab657696ef2232a20147cf1b30ae1a9cb4321" -dependencies = [ - "funty", - "radium", - "tap", - "wyz", -] - [[package]] name = "block-buffer" version = "0.7.3" @@ -231,9 +213,9 @@ dependencies = [ [[package]] name = "bstr" -version = "0.2.15" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a40b47ad93e1a5404e6c18dec46b628214fee441c70f4ab5d6942142cc268a3d" +checksum = "ba3569f383e8f1598449f1a423e72e99569137b47740b1da11ef19af3d5c3223" dependencies = [ "memchr", ] @@ -284,9 +266,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.0.69" +version = "1.0.71" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e70cc2f62c6ce1868963827bd677764c62d07c3d9a3e1fb1177ee1a9ab199eb2" +checksum = "79c2681d6594606957bbb8631c4b90a7fcaaa72cdb714743a437b156d6a7eedd" [[package]] name = "cfg-if" @@ -315,12 +297,24 @@ dependencies = [ [[package]] name = "chrono-tz" -version = "0.5.3" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2554a3155fec064362507487171dcc4edc3df60cb10f3a1fb10ed8094822b120" +checksum = "64c01c1c607d25c71bbaa67c113d6c6b36c434744b4fd66691d711b5b1bc0c8b" dependencies = [ "chrono", + "chrono-tz-build", + "phf", +] + +[[package]] +name = "chrono-tz-build" +version = "0.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db058d493fb2f65f41861bfed7e3fe6335264a9f0f92710cab5bdf01fef09069" +dependencies = [ "parse-zoneinfo", + "phf", + "phf_codegen", ] [[package]] @@ -358,21 +352,21 @@ dependencies = [ [[package]] name = "const_format" -version = "0.2.17" +version = "0.2.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41f4087b5a1164f92255f8b301c88fc8627e5abf5e25b5476f84b02e4b47795d" +checksum = "22bc6cd49b0ec407b680c3e380182b6ac63b73991cb7602de350352fc309b614" dependencies = [ "const_format_proc_macros", ] [[package]] name = "const_format_proc_macros" -version = "0.2.14" +version = "0.2.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29c36c619c422113552db4eb28cddba8faa757e33f758cc3415bd2885977b591" +checksum = "ef196d5d972878a48da7decb7686eded338b4858fbabeed513d63a7c98b2b82d" dependencies = [ - "proc-macro2 1.0.28", - "quote 1.0.9", + "proc-macro2 1.0.32", + "quote 1.0.10", "unicode-xid 0.2.2", ] @@ -394,9 +388,9 @@ dependencies = [ [[package]] name = "core-foundation" -version = "0.9.1" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a89e2ae426ea83155dccf10c0fa6b1463ef6d5fcb44cee0b224a408fa640a62" +checksum = "6888e10551bb93e424d8df1d07f1a8b4fceb0001a3a4b048bfc47554946f47b3" dependencies = [ "core-foundation-sys", "libc", @@ -404,15 +398,15 @@ dependencies = [ [[package]] name = "core-foundation-sys" -version = "0.8.2" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea221b5284a47e40033bf9b66f35f984ec0ea2931eb03505246cd27a963f981b" +checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc" [[package]] name = "cpufeatures" -version = "0.1.5" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "66c99696f6c9dd7f35d486b9d04d7e6e202aa3e8c40d553f2fdf5e7e0c6a71ef" +checksum = "95059428f66df56b63431fdb4e1947ed2190586af5c5a8a8b71122bdf5a7f469" dependencies = [ "libc", ] @@ -454,7 +448,7 @@ dependencies = [ "crossbeam-utils 0.7.2", "lazy_static", "maybe-uninit", - "memoffset", + "memoffset 0.5.6", "scopeguard 1.1.0", ] @@ -521,11 +515,11 @@ dependencies = [ [[package]] name = "ctrlc" -version = "3.1.9" +version = "3.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "232295399409a8b7ae41276757b5a1cc21032848d42bff2352261f958b3ca29a" +checksum = "a19c6cedffdc8c03a3346d723eb20bd85a13362bb96dc2ac000842c6381ec7bf" dependencies = [ - "nix 0.20.0", + "nix 0.23.0", "winapi 0.3.9", ] @@ -585,6 +579,26 @@ dependencies = [ "generic-array 0.14.4", ] +[[package]] +name = "dirs" +version = "3.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30baa043103c9d0c2a57cf537cc2f35623889dc0d405e6c3cccfadbc81c71309" +dependencies = [ + "dirs-sys", +] + +[[package]] +name = "dirs-sys" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03d86534ed367a67548dc68113a0f5db55432fdfbb6e6f9d77704397d95d5780" +dependencies = [ + "libc", + "redox_users", + "winapi 0.3.9", +] + [[package]] name = "doc-comment" version = "0.3.3" @@ -675,9 +689,9 @@ version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "aa4da3c766cd7a0db8242e326e9e4e081edd567072893ed320008189715366a4" dependencies = [ - "proc-macro2 1.0.28", - "quote 1.0.9", - "syn 1.0.74", + "proc-macro2 1.0.32", + "quote 1.0.10", + "syn 1.0.81", "synstructure", ] @@ -689,9 +703,9 @@ checksum = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed" [[package]] name = "filetime" -version = "0.2.14" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d34cfa13a63ae058bfa601fe9e313bbdb3746427c1459185464ce0fcf62e1e8" +checksum = "975ccf83d8d9d0d84682850a38c8169027be83368805971cc4f238c2b245bc98" dependencies = [ "cfg-if 1.0.0", "libc", @@ -741,9 +755,9 @@ dependencies = [ [[package]] name = "fslock" -version = "0.1.6" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b14c83e47c73f7d62d907ae24a1a98e9132df3c33eb6c54fcf4bce0dbc41d5af" +checksum = "57eafdd0c16f57161105ae1b98a1238f97645f2f588438b2949c99a2af9616bf" dependencies = [ "libc", "winapi 0.3.9", @@ -771,12 +785,6 @@ version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" -[[package]] -name = "funty" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fed34cd105917e91daa4da6b3728c47b068749d6a62c59811f06ed2ac71d9da7" - [[package]] name = "futures" version = "0.1.31" @@ -874,9 +882,9 @@ dependencies = [ [[package]] name = "gimli" -version = "0.24.0" +version = "0.26.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e4075386626662786ddb0ec9081e7c7eeb1ba31951f447ca780ef9f5d568189" +checksum = "78cc372d058dcf6d5ecd98510e7fbc9e5aec4d21de70f65fea8fecebcd881bd4" [[package]] name = "glob" @@ -939,7 +947,7 @@ dependencies = [ "http", "indexmap", "log 0.4.14", - "slab 0.4.4", + "slab 0.4.5", "string", "tokio-io", ] @@ -1013,9 +1021,9 @@ dependencies = [ [[package]] name = "httparse" -version = "1.4.1" +version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3a87b616e37e93c22fb19bcd386f02f3af5ea98a25670ad0fce773de23c5e68" +checksum = "acd94fdbe1d4ff688b67b04eee2e17bd50995534a61539e45adfefb45e5e5503" [[package]] name = "humansize" @@ -1196,9 +1204,9 @@ dependencies = [ [[package]] name = "itoa" -version = "0.4.7" +version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd25036021b0de88a0aff6b850051563c6516d0bf53f8638938edbb9de732736" +checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4" [[package]] name = "jsonrpc-client-core" @@ -1210,7 +1218,7 @@ dependencies = [ "futures", "jsonrpc-core 8.0.1", "log 0.4.14", - "serde 1.0.127", + "serde 1.0.130", "serde_json", ] @@ -1239,7 +1247,7 @@ dependencies = [ "jsonrpc-core 14.2.0", "jsonrpc-pubsub 14.2.0", "log 0.4.14", - "serde 1.0.127", + "serde 1.0.130", "serde_json", "url", ] @@ -1252,7 +1260,7 @@ checksum = "ddf83704f4e79979a424d1082dd2c1e52683058056c9280efa19ac5f6bc9033c" dependencies = [ "futures", "log 0.3.9", - "serde 1.0.127", + "serde 1.0.130", "serde_derive", "serde_json", ] @@ -1265,7 +1273,7 @@ checksum = "97b83fdc5e0218128d0d270f2f2e7a5ea716f3240c8518a58bc89e6716ba8581" dependencies = [ "futures", "log 0.4.14", - "serde 1.0.127", + "serde 1.0.130", "serde_derive", "serde_json", ] @@ -1278,7 +1286,7 @@ checksum = "a0747307121ffb9703afd93afbd0fb4f854c38fb873f2c8b90e0e902f27c7b62" dependencies = [ "futures", "log 0.4.14", - "serde 1.0.127", + "serde 1.0.130", "serde_derive", "serde_json", ] @@ -1293,7 +1301,7 @@ dependencies = [ "futures", "jsonrpc-core 11.0.0", "log 0.4.14", - "serde 1.0.127", + "serde 1.0.130", "serde_json", ] @@ -1329,7 +1337,7 @@ dependencies = [ "jsonrpc-core 11.0.0", "log 0.4.14", "parking_lot 0.7.1", - "serde 1.0.127", + "serde 1.0.130", ] [[package]] @@ -1342,7 +1350,7 @@ dependencies = [ "log 0.4.14", "parking_lot 0.10.2", "rand 0.7.3", - "serde 1.0.127", + "serde 1.0.130", ] [[package]] @@ -1372,7 +1380,7 @@ dependencies = [ "jsonrpc-core-client 11.0.0", "jsonrpc-pubsub 11.0.0", "log 0.4.14", - "serde 1.0.127", + "serde 1.0.130", "serde_json", ] @@ -1386,7 +1394,7 @@ dependencies = [ "jsonrpc-core-client 14.2.0", "jsonrpc-pubsub 14.2.0", "log 0.4.14", - "serde 1.0.127", + "serde 1.0.130", "serde_json", ] @@ -1400,7 +1408,7 @@ dependencies = [ "jsonrpc-server-utils", "log 0.4.14", "parking_lot 0.7.1", - "slab 0.4.4", + "slab 0.4.5", "ws", ] @@ -1432,24 +1440,11 @@ version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" -[[package]] -name = "lexical-core" -version = "0.7.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6607c62aa161d23d17a9072cc5da0be67cdfc89d3afb1e8d9c842bebc2525ffe" -dependencies = [ - "arrayvec", - "bitflags 1.3.2", - "cfg-if 1.0.0", - "ryu", - "static_assertions", -] - [[package]] name = "libc" -version = "0.2.105" +version = "0.2.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "869d572136620d55835903746bcb5cdc54cb2851fd0aeec53220b4bb65ef3013" +checksum = "a60553f9a9e039a333b4e9b20573b9e9b9c0bb3a11e201ccc48ef4283456d673" [[package]] name = "linked-hash-map" @@ -1525,9 +1520,9 @@ checksum = "3e2e65a1a2e43cfcb47a895c4c8b10d1f4a61097f9f254f183aee60cad9c651d" [[package]] name = "matches" -version = "0.1.8" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08" +checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f" [[package]] name = "maybe-uninit" @@ -1537,9 +1532,9 @@ checksum = "60302e4db3a61da70c0cb7991976248362f30319e88850c487b9b95bbf059e00" [[package]] name = "memchr" -version = "2.3.4" +version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ee1c47aaa256ecabcaea351eae4a9b01ef39ed810004e298d2511ed284b1525" +checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a" [[package]] name = "memoffset" @@ -1550,6 +1545,15 @@ dependencies = [ "autocfg 1.0.1", ] +[[package]] +name = "memoffset" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59accc507f1338036a0477ef61afdae33cde60840f4dfe481319ce3ad116ddf9" +dependencies = [ + "autocfg 1.0.1", +] + [[package]] name = "mime" version = "0.2.6" @@ -1565,6 +1569,12 @@ version = "0.3.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2a60c7ce501c71e03a9c9c0d35b861413ae925bd979cc7a4e30d060069aaac8d" +[[package]] +name = "minimal-lexical" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c64630dcdd71f1a64c435f54885086a0de5d6a12d104d69b165fb7d5286d677" + [[package]] name = "miniz_oxide" version = "0.4.4" @@ -1590,7 +1600,7 @@ dependencies = [ "log 0.4.14", "miow", "net2", - "slab 0.4.4", + "slab 0.4.5", "winapi 0.2.8", ] @@ -1603,7 +1613,7 @@ dependencies = [ "lazycell", "log 0.4.14", "mio", - "slab 0.4.4", + "slab 0.4.5", ] [[package]] @@ -1637,9 +1647,9 @@ checksum = "9796ba90f2e7187d7837ea05033ed6dff5320cbf2944fe2dc1da53569396ca07" [[package]] name = "native-tls" -version = "0.2.7" +version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8d96b2e1c8da3957d58100b09f102c6d9cfdfced01b7ec5a8974044bb09dbd4" +checksum = "48ba9f7719b5a0f42f338907614285fb5fd70e53858141f69898a1fb7203b24d" dependencies = [ "lazy_static", "libc", @@ -1754,14 +1764,15 @@ dependencies = [ [[package]] name = "nix" -version = "0.20.0" +version = "0.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa9b4819da1bc61c0ea48b63b7bc8604064dd43013e7cc325df098d49cd7c18a" +checksum = "f305c2c2e4c39a82f7bf0bf65fb557f9070ce06781d4f2454295cc34b1c43188" dependencies = [ "bitflags 1.3.2", "cc", "cfg-if 1.0.0", "libc", + "memoffset 0.6.4", ] [[package]] @@ -1786,14 +1797,12 @@ dependencies = [ [[package]] name = "nom" -version = "6.2.1" +version = "7.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c5c51b9083a3c620fa67a2a635d1ce7d95b897e957d6b28ff9a5da960a103a6" +checksum = "7ffd9d26838a953b4af82cbeb9f1592c6798916983959be223a7124e992742c1" dependencies = [ - "bitvec", - "funty", - "lexical-core", "memchr", + "minimal-lexical", "version_check 0.9.3", ] @@ -1855,9 +1864,12 @@ dependencies = [ [[package]] name = "object" -version = "0.24.0" +version = "0.27.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a5b3dd1c072ee7963717671d1ca129f1048fda25edea6b752bfc71ac8854170" +checksum = "67ac1d3f9a1d3616fd9a60c8d74296f22406a238b6a72f5cc1e6f314df4ffbf9" +dependencies = [ + "memchr", +] [[package]] name = "objekt" @@ -1885,9 +1897,9 @@ checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" [[package]] name = "openssl" -version = "0.10.35" +version = "0.10.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "549430950c79ae24e6d02e0b7404534ecf311d94cc9f861e9e4020187d13d885" +checksum = "0c7ae222234c30df141154f159066c5093ff73b63204dcda7121eb082fc56a95" dependencies = [ "bitflags 1.3.2", "cfg-if 1.0.0", @@ -1905,18 +1917,18 @@ checksum = "28988d872ab76095a6e6ac88d99b54fd267702734fd7ffe610ca27f533ddb95a" [[package]] name = "openssl-src" -version = "111.15.0+1.1.1k" +version = "300.0.2+3.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1a5f6ae2ac04393b217ea9f700cd04fa9bf3d93fae2872069f3d15d908af70a" +checksum = "14a760a11390b1a5daf72074d4f6ff1a6e772534ae191f999f57e9ee8146d1fb" dependencies = [ "cc", ] [[package]] name = "openssl-sys" -version = "0.9.65" +version = "0.9.70" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a7907e3bfa08bb85105209cdfcb6c63d109f8f6c1ed6ca318fff5c1853fbc1d" +checksum = "c6517987b3f8226b5da3661dad65ff7f300cc59fb5ea8333ca191fc65fde3edf" dependencies = [ "autocfg 1.0.1", "cc", @@ -2004,7 +2016,7 @@ dependencies = [ "cloudabi", "libc", "redox_syscall 0.1.57", - "smallvec 1.6.1", + "smallvec 1.7.0", "winapi 0.3.9", ] @@ -2041,7 +2053,7 @@ dependencies = [ "lazy_static", "log 0.4.14", "regex", - "serde 1.0.127", + "serde 1.0.130", "serde_json", "snafu 0.6.10", "structopt", @@ -2069,7 +2081,7 @@ dependencies = [ "log 0.4.14", "rand 0.8.4", "regex", - "serde 1.0.127", + "serde 1.0.130", "serde_derive", "serde_json", "serde_yaml", @@ -2089,7 +2101,7 @@ dependencies = [ "jsonrpc-test 11.0.0", "log 0.4.14", "peach-lib", - "serde 1.0.127", + "serde 1.0.130", "serde_json", "ws", ] @@ -2119,7 +2131,7 @@ dependencies = [ "log 0.4.14", "probes 0.4.1", "regex", - "serde 1.0.127", + "serde 1.0.130", "serde_json", "snafu 0.6.10", "wpactrl", @@ -2137,7 +2149,7 @@ dependencies = [ "linux-embedded-hal", "log 0.4.14", "nix 0.11.1", - "serde 1.0.127", + "serde 1.0.130", "serde_json", "snafu 0.4.4", "ssd1306", @@ -2158,7 +2170,7 @@ dependencies = [ "log 0.4.14", "peach-lib", "regex", - "serde 1.0.127", + "serde 1.0.130", "serde_derive", "serde_json", "snafu 0.4.4", @@ -2175,7 +2187,7 @@ dependencies = [ "jsonrpc-test 11.0.0", "log 0.4.14", "probes 0.3.0", - "serde 1.0.127", + "serde 1.0.130", "serde_json", "snafu 0.4.4", "systemstat", @@ -2194,10 +2206,10 @@ dependencies = [ "regex", "rocket", "rocket_contrib", - "serde 1.0.127", + "serde 1.0.130", "serde_json", "snafu 0.6.10", - "tera 1.12.1", + "tera 1.14.0", "websocket", "xdg", ] @@ -2263,9 +2275,9 @@ checksum = "99b8db626e31e5b81787b9783425769681b347011cc59471e33ea46d2ea0cf55" dependencies = [ "pest", "pest_meta", - "proc-macro2 1.0.28", - "quote 1.0.9", - "syn 1.0.74", + "proc-macro2 1.0.32", + "quote 1.0.10", + "syn 1.0.81", ] [[package]] @@ -2280,10 +2292,49 @@ dependencies = [ ] [[package]] -name = "pkg-config" -version = "0.3.19" +name = "phf" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3831453b3449ceb48b6d9c7ad7c96d5ea673e9b470a1dc578c2ce6521230884c" +checksum = "b9fc3db1018c4b59d7d582a739436478b6035138b6aecbce989fc91c3e98409f" +dependencies = [ + "phf_shared", +] + +[[package]] +name = "phf_codegen" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fb1c3a8bc4dd4e5cfce29b44ffc14bedd2ee294559a294e2a4d4c9e9a6a13cd" +dependencies = [ + "phf_generator", + "phf_shared", +] + +[[package]] +name = "phf_generator" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d5285893bb5eb82e6aaf5d59ee909a06a16737a8970984dd7746ba9283498d6" +dependencies = [ + "phf_shared", + "rand 0.8.4", +] + +[[package]] +name = "phf_shared" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6796ad771acdc0123d2a88dc428b5e38ef24456743ddb1744ed628f9815c096" +dependencies = [ + "siphasher", + "uncased", +] + +[[package]] +name = "pkg-config" +version = "0.3.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12295df4f294471248581bc09bef3c38a5e46f1e36d6a37353621a0c6c357e1f" [[package]] name = "polyval" @@ -2298,9 +2349,9 @@ dependencies = [ [[package]] name = "ppv-lite86" -version = "0.2.10" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857" +checksum = "ed0cfbc8191465bed66e1718596ee0b0b35d5ee1f41c5df2189d0fe8bde535ba" [[package]] name = "probes" @@ -2329,9 +2380,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" dependencies = [ "proc-macro-error-attr", - "proc-macro2 1.0.28", - "quote 1.0.9", - "syn 1.0.74", + "proc-macro2 1.0.32", + "quote 1.0.10", + "syn 1.0.81", "version_check 0.9.3", ] @@ -2341,8 +2392,8 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" dependencies = [ - "proc-macro2 1.0.28", - "quote 1.0.9", + "proc-macro2 1.0.32", + "quote 1.0.10", "version_check 0.9.3", ] @@ -2357,9 +2408,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.28" +version = "1.0.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c7ed8b8c7b886ea3ed7dde405212185f423ab44682667c8c6dd14aa1d9f6612" +checksum = "ba508cc11742c0dc5c1659771673afbab7a0efab23aa17e854cbab0837ed0b43" dependencies = [ "unicode-xid 0.2.2", ] @@ -2381,19 +2432,13 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.9" +version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7" +checksum = "38bc8cc6a5f2e3655e0899c1b848643b2562f853f114bfec7be120678e3ace05" dependencies = [ - "proc-macro2 1.0.28", + "proc-macro2 1.0.32", ] -[[package]] -name = "radium" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "941ba9d78d8e2f7ce474c015eea4d9c6d25b6a3327f9832ee29a4de27f91bbb8" - [[package]] name = "rand" version = "0.3.23" @@ -2629,10 +2674,20 @@ dependencies = [ ] [[package]] -name = "regex" -version = "1.4.6" +name = "redox_users" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a26af418b574bd56588335b3a3659a65725d4e636eb1016c2f9e3b38c7cc759" +checksum = "528532f3d801c87aec9def2add9ca802fe569e44a544afe633765267840abe64" +dependencies = [ + "getrandom 0.2.3", + "redox_syscall 0.2.10", +] + +[[package]] +name = "regex" +version = "1.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d07a8629359eb56f1e2fb1652bb04212c072a87ba68546a04065d525673ac461" dependencies = [ "aho-corasick", "memchr", @@ -2709,7 +2764,7 @@ dependencies = [ "log 0.4.14", "notify", "rocket", - "serde 1.0.127", + "serde 1.0.130", "serde_json", "tera 0.11.20", ] @@ -2725,7 +2780,7 @@ dependencies = [ "indexmap", "pear", "percent-encoding 1.0.1", - "smallvec 1.6.1", + "smallvec 1.7.0", "state", "time", "unicode-xid 0.1.0", @@ -2733,9 +2788,9 @@ dependencies = [ [[package]] name = "rustc-demangle" -version = "0.1.20" +version = "0.1.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dead70b0b5e03e9c814bcb6b01e03e68f7c57a80aa48c72ec92152ab3e818d49" +checksum = "7ef03e0a2b150c7a90d01faf6254c9c48a41e95fb2a8c2ac1c6f0d2b9aefc342" [[package]] name = "rustc_version" @@ -2815,9 +2870,9 @@ checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" [[package]] name = "security-framework" -version = "2.3.1" +version = "2.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23a2ac85147a3a11d77ecf1bc7166ec0b92febfa4461c37944e180f319ece467" +checksum = "525bc1abfda2e1998d152c45cf13e696f76d0a4972310b22fac1658b05df7c87" dependencies = [ "bitflags 1.3.2", "core-foundation", @@ -2828,9 +2883,9 @@ dependencies = [ [[package]] name = "security-framework-sys" -version = "2.3.0" +version = "2.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e4effb91b4b8b6fb7732e670b6cee160278ff8e6bf485c7805d9e319d76e284" +checksum = "a9dd14d83160b528b7bfd66439110573efcfbe281b17fc2ca9f39f550d619c7e" dependencies = [ "core-foundation-sys", "libc", @@ -2871,9 +2926,9 @@ checksum = "9dad3f759919b92c3068c696c15c3d17238234498bbdcc80f2c469606f948ac8" [[package]] name = "serde" -version = "1.0.127" +version = "1.0.130" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f03b9878abf6d14e6779d3f24f07b2cfa90352cfec4acc5aab8f1ac7f146fae8" +checksum = "f12d06de37cf59146fbdecab66aa99f9fe4f78722e3607577a5375d66bd0c913" dependencies = [ "serde_derive", ] @@ -2893,25 +2948,25 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.127" +version = "1.0.130" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a024926d3432516606328597e0f224a51355a493b49fdd67e9209187cbe55ecc" +checksum = "d7bc1a1ab1961464eae040d96713baa5a724a8152c1222492465b54322ec508b" dependencies = [ - "proc-macro2 1.0.28", - "quote 1.0.9", - "syn 1.0.74", + "proc-macro2 1.0.32", + "quote 1.0.10", + "syn 1.0.81", ] [[package]] name = "serde_json" -version = "1.0.66" +version = "1.0.68" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "336b10da19a12ad094b59d870ebde26a45402e5b470add4b5fd03c5048a32127" +checksum = "0f690853975602e1bfe1ccbf50504d67174e3bcf340f23b5ea9992e0587a52d8" dependencies = [ "indexmap", "itoa", "ryu", - "serde 1.0.127", + "serde 1.0.130", ] [[package]] @@ -2925,13 +2980,13 @@ dependencies = [ [[package]] name = "serde_yaml" -version = "0.8.17" +version = "0.8.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15654ed4ab61726bf918a39cb8d98a2e2995b002387807fa6ba58fdf7f59bb23" +checksum = "d8c608a35705a5d3cdc9fbe403147647ff34b921f8e833e49306df898f9b20af" dependencies = [ "dtoa", - "linked-hash-map 0.5.4", - "serde 1.0.127", + "indexmap", + "serde 1.0.130", "yaml-rust", ] @@ -2949,9 +3004,9 @@ dependencies = [ [[package]] name = "sha2" -version = "0.9.5" +version = "0.9.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b362ae5752fd2137731f9fa25fd4d9058af34666ca1966fb969119cc35719f12" +checksum = "b69f9a4c9740d74c5baa3fd2e547f9525fa8088a8a958e0ca2409a514e33f5fa" dependencies = [ "block-buffer 0.9.0", "cfg-if 1.0.0", @@ -2960,6 +3015,12 @@ dependencies = [ "opaque-debug 0.3.0", ] +[[package]] +name = "siphasher" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "533494a8f9b724d33625ab53c6c4800f7cc445895924a8ef649222dcb76e938b" + [[package]] name = "slab" version = "0.3.0" @@ -2968,9 +3029,9 @@ checksum = "17b4fcaed89ab08ef143da37bc52adbcc04d4a69014f4c1208d6b51f0c47bc23" [[package]] name = "slab" -version = "0.4.4" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c307a32c1c5c437f38c7fd45d753050587732ba8628319fbdf12a7e289ccc590" +checksum = "9def91fd1e018fe007022791f865d0ccc9b3a0d5001e01aabb8b40e46000afb5" [[package]] name = "slug" @@ -2998,9 +3059,9 @@ dependencies = [ [[package]] name = "smallvec" -version = "1.6.1" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe0f37c9e8f3c5a4a66ad655a93c74daac4ad00c441533bf5c6e7990bb42604e" +checksum = "1ecab6c735a6bb4139c0caafd0cc3635748bbb3acf4550e8138122099251f309" [[package]] name = "snafu" @@ -3061,9 +3122,9 @@ version = "0.6.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1508efa03c362e23817f96cde18abed596a25219a8b2c66e8db33c03543d315b" dependencies = [ - "proc-macro2 1.0.28", - "quote 1.0.9", - "syn 1.0.74", + "proc-macro2 1.0.32", + "quote 1.0.10", + "syn 1.0.81", ] [[package]] @@ -3099,12 +3160,6 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3015a7d0a5fd5105c91c3710d42f9ccf0abfb287d62206484dcc67f9569a6483" -[[package]] -name = "static_assertions" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" - [[package]] name = "string" version = "0.2.1" @@ -3122,9 +3177,9 @@ checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" [[package]] name = "structopt" -version = "0.3.22" +version = "0.3.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69b041cdcb67226aca307e6e7be44c8806423d83e018bd662360a93dabce4d71" +checksum = "40b9788f4202aa75c240ecc9c15c65185e6a39ccdeb0fd5d008b98825464c87c" dependencies = [ "clap", "lazy_static", @@ -3133,15 +3188,15 @@ dependencies = [ [[package]] name = "structopt-derive" -version = "0.4.15" +version = "0.4.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7813934aecf5f51a54775e00068c237de98489463968231a51746bbbc03f9c10" +checksum = "dcb5ae327f9cc13b68763b5749770cb9e048a99bd9dfdfa58d0cf05d5f64afe0" dependencies = [ "heck", "proc-macro-error", - "proc-macro2 1.0.28", - "quote 1.0.9", - "syn 1.0.74", + "proc-macro2 1.0.32", + "quote 1.0.10", + "syn 1.0.81", ] [[package]] @@ -3163,24 +3218,24 @@ dependencies = [ [[package]] name = "syn" -version = "1.0.74" +version = "1.0.81" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1873d832550d4588c3dbc20f01361ab00bfe741048f71e3fecf145a7cc18b29c" +checksum = "f2afee18b8beb5a596ecb4a2dce128c719b4ba399d34126b9e4396e3f9860966" dependencies = [ - "proc-macro2 1.0.28", - "quote 1.0.9", + "proc-macro2 1.0.32", + "quote 1.0.10", "unicode-xid 0.2.2", ] [[package]] name = "synstructure" -version = "0.12.5" +version = "0.12.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "474aaa926faa1603c40b7885a9eaea29b444d1cb2850cb7c0e37bb1a4182f4fa" +checksum = "f36bdaa60a83aca3921b5259d5400cbf5e90fc51931376a9bd4a0eb79aa7210f" dependencies = [ - "proc-macro2 1.0.28", - "quote 1.0.9", - "syn 1.0.74", + "proc-macro2 1.0.32", + "quote 1.0.10", + "syn 1.0.81", "unicode-xid 0.2.2", ] @@ -3195,16 +3250,15 @@ dependencies = [ [[package]] name = "systemstat" -version = "0.1.8" +version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a934f8fe2f893260080fdde71e840b35308f48bf3bd3b261cb24e668c4b48db3" +checksum = "8862adb0fd5f4c5707b0eeb6c2ec7610bd7a8bf5e069150bd6dde04a7f40ebf7" dependencies = [ "bytesize", "chrono", "lazy_static", "libc", - "nom 6.2.1", - "time", + "nom 7.0.0", "winapi 0.3.9", ] @@ -3214,12 +3268,6 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b157868d8ac1f56b64604539990685fa7611d8fa9e5476cf0c02cf34d32917c5" -[[package]] -name = "tap" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" - [[package]] name = "tempdir" version = "0.3.7" @@ -3258,7 +3306,7 @@ dependencies = [ "pest", "pest_derive", "regex", - "serde 1.0.127", + "serde 1.0.130", "serde_json", "slug", "unic-segment 0.7.0", @@ -3267,9 +3315,9 @@ dependencies = [ [[package]] name = "tera" -version = "1.12.1" +version = "1.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf95b0d8a46da5fe3ea119394a6c7f1e745f9de359081641c99946e2bf55d4f2" +checksum = "3e7f3fd1bd7e48ef73d9e9124caedee3e1c645657ec876a50a278c8d0555d9da" dependencies = [ "chrono", "chrono-tz", @@ -3281,7 +3329,7 @@ dependencies = [ "pest_derive", "rand 0.8.4", "regex", - "serde 1.0.127", + "serde 1.0.130", "serde_json", "slug", "unic-segment 0.9.0", @@ -3345,9 +3393,9 @@ dependencies = [ [[package]] name = "tinyvec" -version = "1.3.1" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "848a1e1181b9f6753b5e96a092749e29b11d19ede67dfbbd6c7dc7e0f49b5338" +checksum = "f83b2a3d4d9091d0abd7eba4dc2710b1718583bd4d8992e2190720ea38f391f7" dependencies = [ "tinyvec_macros", ] @@ -3496,7 +3544,7 @@ dependencies = [ "mio", "num_cpus", "parking_lot 0.9.0", - "slab 0.4.4", + "slab 0.4.5", "tokio-executor", "tokio-io", "tokio-sync", @@ -3548,7 +3596,7 @@ dependencies = [ "lazy_static", "log 0.4.14", "num_cpus", - "slab 0.4.4", + "slab 0.4.5", "tokio-executor", ] @@ -3560,7 +3608,7 @@ checksum = "93044f2d313c95ff1cb7809ce9a7a05735b012288a888b62d4434fd58c94f296" dependencies = [ "crossbeam-utils 0.7.2", "futures", - "slab 0.4.4", + "slab 0.4.5", "tokio-executor", ] @@ -3614,7 +3662,7 @@ version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "758664fc71a3a69038656bee8b6be6477d2a6c315a6b81f7081f591bffa4111f" dependencies = [ - "serde 1.0.127", + "serde 1.0.130", ] [[package]] @@ -3624,7 +3672,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a31142970826733df8241ef35dc040ef98c679ab14d7c3e54d827099b3acecaa" dependencies = [ "indexmap", - "serde 1.0.127", + "serde 1.0.130", ] [[package]] @@ -3653,9 +3701,9 @@ checksum = "1410f6f91f21d1612654e7cc69193b0334f909dcf2c790c4826254fbb86f8887" [[package]] name = "typenum" -version = "1.13.0" +version = "1.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "879f6906492a7cd215bfa4cf595b600146ccfac0c79bcbd1f3000162af5e8b06" +checksum = "b63708a265f51345575b27fe43f9500ad611579e764c79edbc2037b1121959ec" [[package]] name = "ucd-trie" @@ -3663,6 +3711,15 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "56dee185309b50d1f11bfedef0fe6d036842e3fb77413abef29f8f8d1c5d4c1c" +[[package]] +name = "uncased" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5baeed7327e25054889b9bd4f975f32e5f4c5d434042d59ab6cd4142c0a76ed0" +dependencies = [ + "version_check 0.9.3", +] + [[package]] name = "unic-char-property" version = "0.7.0" @@ -3783,12 +3840,9 @@ dependencies = [ [[package]] name = "unicode-bidi" -version = "0.3.5" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eeb8be209bb1c96b7c177c7420d26e04eccacb0eeae6b980e35fcb74678107e0" -dependencies = [ - "matches", -] +checksum = "1a01404663e3db436ed2746d9fefef640d868edae3cceb81c3b8d5732fda678f" [[package]] name = "unicode-normalization" @@ -3807,9 +3861,9 @@ checksum = "8895849a949e7845e06bd6dc1aa51731a103c42707010a5b591c0038fb73385b" [[package]] name = "unicode-width" -version = "0.1.8" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3" +checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973" [[package]] name = "unicode-xid" @@ -4028,7 +4082,7 @@ dependencies = [ "mio-extras", "rand 0.6.5", "sha-1", - "slab 0.4.4", + "slab 0.4.5", "url", ] @@ -4042,17 +4096,14 @@ dependencies = [ "winapi-build", ] -[[package]] -name = "wyz" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85e60b0d1b5f99db2556934e21937020776a5d31520bf169e851ac44e6420214" - [[package]] name = "xdg" -version = "2.2.0" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d089681aa106a86fade1b0128fb5daf07d5867a509ab036d99988dec80429a57" +checksum = "3a23fe958c70412687039c86f578938b4a0bb50ec788e96bce4d6ab00ddd5803" +dependencies = [ + "dirs", +] [[package]] name = "yaml-rust" diff --git a/peach-buttons/Cargo.lock b/peach-buttons/Cargo.lock deleted file mode 100644 index 4983353..0000000 --- a/peach-buttons/Cargo.lock +++ /dev/null @@ -1,1460 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -[[package]] -name = "addr2line" -version = "0.14.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a55f82cfe485775d02112886f4169bde0c5894d75e79ead7eafe7e40a25e45f7" -dependencies = [ - "gimli", -] - -[[package]] -name = "adler" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee2a4ec343196209d6594e19543ae87a39f96d5534d7174822a3ad825dd6ed7e" - -[[package]] -name = "aho-corasick" -version = "0.7.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7404febffaa47dac81aa44dba71523c9d069b1bdc50a77db41195149e17f68e5" -dependencies = [ - "memchr", -] - -[[package]] -name = "atty" -version = "0.2.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" -dependencies = [ - "hermit-abi", - "libc", - "winapi 0.3.9", -] - -[[package]] -name = "autocfg" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d49d90015b3c36167a20fe2810c5cd875ad504b39cff3d4eae7977e6b7c1cb2" - -[[package]] -name = "autocfg" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" - -[[package]] -name = "backtrace" -version = "0.3.55" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef5140344c85b01f9bbb4d4b7288a8aa4b3287ccef913a14bcc78a1063623598" -dependencies = [ - "addr2line", - "cfg-if 1.0.0", - "libc", - "miniz_oxide", - "object", - "rustc-demangle", -] - -[[package]] -name = "bitflags" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" - -[[package]] -name = "block-buffer" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0940dc441f31689269e10ac70eb1002a3a1d3ad1390e030043662eb7fe4688b" -dependencies = [ - "block-padding", - "byte-tools", - "byteorder", - "generic-array", -] - -[[package]] -name = "block-padding" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa79dedbb091f449f1f39e53edf88d5dbe95f895dae6135a8d7b881fb5af73f5" -dependencies = [ - "byte-tools", -] - -[[package]] -name = "bstr" -version = "0.2.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "473fc6b38233f9af7baa94fb5852dca389e3d95b8e21c8e3719301462c5d9faf" -dependencies = [ - "memchr", -] - -[[package]] -name = "byte-tools" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7" - -[[package]] -name = "byteorder" -version = "1.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de" - -[[package]] -name = "bytes" -version = "0.4.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "206fdffcfa2df7cbe15601ef46c813fce0965eb3286db6b56c583b814b51c81c" -dependencies = [ - "byteorder", - "iovec", -] - -[[package]] -name = "cc" -version = "1.0.66" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c0496836a84f8d0495758516b8621a622beb77c0fed418570e50764093ced48" - -[[package]] -name = "cfg-if" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" - -[[package]] -name = "cfg-if" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" - -[[package]] -name = "cloudabi" -version = "0.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" -dependencies = [ - "bitflags", -] - -[[package]] -name = "crossbeam-channel" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8ec7fcd21571dc78f96cc96243cab8d8f035247c3efd16c687be154c3fa9efa" -dependencies = [ - "crossbeam-utils 0.6.6", -] - -[[package]] -name = "crossbeam-deque" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f02af974daeee82218205558e51ec8768b48cf524bd01d550abe5573a608285" -dependencies = [ - "crossbeam-epoch", - "crossbeam-utils 0.7.2", - "maybe-uninit", -] - -[[package]] -name = "crossbeam-epoch" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "058ed274caafc1f60c4997b5fc07bf7dc7cca454af7c6e81edffe5f33f70dace" -dependencies = [ - "autocfg 1.0.1", - "cfg-if 0.1.10", - "crossbeam-utils 0.7.2", - "lazy_static", - "maybe-uninit", - "memoffset", - "scopeguard 1.1.0", -] - -[[package]] -name = "crossbeam-queue" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "774ba60a54c213d409d5353bda12d49cd68d14e45036a285234c8d6f91f92570" -dependencies = [ - "cfg-if 0.1.10", - "crossbeam-utils 0.7.2", - "maybe-uninit", -] - -[[package]] -name = "crossbeam-utils" -version = "0.6.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04973fa96e96579258a5091af6003abde64af786b860f18622b82e026cca60e6" -dependencies = [ - "cfg-if 0.1.10", - "lazy_static", -] - -[[package]] -name = "crossbeam-utils" -version = "0.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3c7c73a2d1e9fc0886a08b93e98eb643461230d5f1925e4036204d5f2e261a8" -dependencies = [ - "autocfg 1.0.1", - "cfg-if 0.1.10", - "lazy_static", -] - -[[package]] -name = "digest" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3d0c8c8752312f9713efd397ff63acb9f85585afbf179282e720e7704954dd5" -dependencies = [ - "generic-array", -] - -[[package]] -name = "doc-comment" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10" - -[[package]] -name = "env_logger" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aafcde04e90a5226a6443b7aabdb016ba2f8307c847d524724bd9b346dd1a2d3" -dependencies = [ - "atty", - "humantime", - "log", - "regex", - "termcolor", -] - -[[package]] -name = "error-chain" -version = "0.12.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d2f06b9cac1506ece98fe3231e3cc9c4410ec3d5b1f24ae1c8946f0742cdefc" -dependencies = [ - "backtrace", - "version_check", -] - -[[package]] -name = "failure" -version = "0.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d32e9bd16cc02eae7db7ef620b392808b89f6a5e16bb3497d159c6b92a0f4f86" -dependencies = [ - "backtrace", - "failure_derive", -] - -[[package]] -name = "failure_derive" -version = "0.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa4da3c766cd7a0db8242e326e9e4e081edd567072893ed320008189715366a4" -dependencies = [ - "proc-macro2 1.0.24", - "quote 1.0.8", - "syn 1.0.56", - "synstructure", -] - -[[package]] -name = "fake-simd" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed" - -[[package]] -name = "fnv" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" - -[[package]] -name = "fuchsia-cprng" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" - -[[package]] -name = "fuchsia-zircon" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82" -dependencies = [ - "bitflags", - "fuchsia-zircon-sys", -] - -[[package]] -name = "fuchsia-zircon-sys" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" - -[[package]] -name = "futures" -version = "0.1.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c7e4c2612746b0df8fed4ce0c69156021b704c9aefa360311c04e6e9e002eed" - -[[package]] -name = "generic-array" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c68f0274ae0e023facc3c97b2e00f076be70e254bc851d972503b328db79b2ec" -dependencies = [ - "typenum", -] - -[[package]] -name = "gimli" -version = "0.23.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6503fe142514ca4799d4c26297c4248239fe8838d827db6bd6065c6ed29a6ce" - -[[package]] -name = "globset" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c152169ef1e421390738366d2f796655fec62621dabbd0fd476f905934061e4a" -dependencies = [ - "aho-corasick", - "bstr", - "fnv", - "log", - "regex", -] - -[[package]] -name = "gpio-cdev" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04d50743080fbae298c55f0b28dd5ea4b513c53cddeddace6cbdd31db7dda981" -dependencies = [ - "bitflags", - "error-chain", - "libc", - "nix", -] - -[[package]] -name = "hermit-abi" -version = "0.1.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5aca5565f760fb5b220e499d72710ed156fdb74e631659e99377d9ebfbd13ae8" -dependencies = [ - "libc", -] - -[[package]] -name = "httparse" -version = "1.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd179ae861f0c2e53da70d892f5f3029f9594be0c41dc5269cd371691b1dc2f9" - -[[package]] -name = "humantime" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df004cfca50ef23c36850aaaa59ad52cc70d0e90243c3c7737a4dd32dc7a3c4f" -dependencies = [ - "quick-error", -] - -[[package]] -name = "idna" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38f09e0f0b1fb55fdee1f17470ad800da77af5186a1a76c026b679358b7e844e" -dependencies = [ - "matches", - "unicode-bidi", - "unicode-normalization", -] - -[[package]] -name = "iovec" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2b3ea6ff95e175473f8ffe6a7eb7c00d054240321b84c57051175fe3c1e075e" -dependencies = [ - "libc", -] - -[[package]] -name = "itoa" -version = "0.4.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd25036021b0de88a0aff6b850051563c6516d0bf53f8638938edbb9de732736" - -[[package]] -name = "jsonrpc-core" -version = "11.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97b83fdc5e0218128d0d270f2f2e7a5ea716f3240c8518a58bc89e6716ba8581" -dependencies = [ - "futures", - "log", - "serde", - "serde_derive", - "serde_json", -] - -[[package]] -name = "jsonrpc-core-client" -version = "11.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c889ca27072f038496a62f38356e8f827acf194d7276030120265362b2974eab" -dependencies = [ - "failure", - "futures", - "jsonrpc-core", - "log", - "serde", - "serde_json", -] - -[[package]] -name = "jsonrpc-pubsub" -version = "11.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c233c4570183a45f7bde14cd7d23446d6c236de6df9442e53a60951adae9fd34" -dependencies = [ - "jsonrpc-core", - "log", - "parking_lot 0.7.1", - "serde", -] - -[[package]] -name = "jsonrpc-server-utils" -version = "11.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3372b3248a53abcca8f61924f188052bb0c4cd80b482b2b4eaf9f8667efb9f4" -dependencies = [ - "bytes", - "globset", - "jsonrpc-core", - "lazy_static", - "log", - "num_cpus", - "tokio", - "tokio-codec", - "unicase", -] - -[[package]] -name = "jsonrpc-test" -version = "11.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0aedad254cd8faba2bf8d1fe00c52fe9d9944f1a8c3f789916b68a61a3414c87" -dependencies = [ - "jsonrpc-core", - "jsonrpc-core-client", - "jsonrpc-pubsub", - "log", - "serde", - "serde_json", -] - -[[package]] -name = "jsonrpc-ws-server" -version = "11.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e72d8f524c7afd11d9c71614d1f814ee1c46377869933ce42d559d6973922f79" -dependencies = [ - "jsonrpc-core", - "jsonrpc-server-utils", - "log", - "parking_lot 0.7.1", - "slab", - "ws", -] - -[[package]] -name = "kernel32-sys" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" -dependencies = [ - "winapi 0.2.8", - "winapi-build", -] - -[[package]] -name = "lazy_static" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" - -[[package]] -name = "lazycell" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" - -[[package]] -name = "libc" -version = "0.2.81" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1482821306169ec4d07f6aca392a4681f66c75c9918aa49641a2595db64053cb" - -[[package]] -name = "lock_api" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62ebf1391f6acad60e5c8b43706dde4582df75c06698ab44511d15016bc2442c" -dependencies = [ - "owning_ref", - "scopeguard 0.3.3", -] - -[[package]] -name = "lock_api" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4da24a77a3d8a6d4862d95f72e6fdb9c09a643ecdb402d754004a557f2bec75" -dependencies = [ - "scopeguard 1.1.0", -] - -[[package]] -name = "log" -version = "0.4.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fabed175da42fed1fa0746b0ea71f412aa9d35e76e95e59b192c64b9dc2bf8b" -dependencies = [ - "cfg-if 0.1.10", -] - -[[package]] -name = "matches" -version = "0.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08" - -[[package]] -name = "maybe-uninit" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60302e4db3a61da70c0cb7991976248362f30319e88850c487b9b95bbf059e00" - -[[package]] -name = "memchr" -version = "2.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ee1c47aaa256ecabcaea351eae4a9b01ef39ed810004e298d2511ed284b1525" - -[[package]] -name = "memoffset" -version = "0.5.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "043175f069eda7b85febe4a74abbaeff828d9f8b448515d3151a14a3542811aa" -dependencies = [ - "autocfg 1.0.1", -] - -[[package]] -name = "miniz_oxide" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f2d26ec3309788e423cfbf68ad1800f061638098d76a83681af979dc4eda19d" -dependencies = [ - "adler", - "autocfg 1.0.1", -] - -[[package]] -name = "mio" -version = "0.6.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4afd66f5b91bf2a3bc13fad0e21caedac168ca4c707504e75585648ae80e4cc4" -dependencies = [ - "cfg-if 0.1.10", - "fuchsia-zircon", - "fuchsia-zircon-sys", - "iovec", - "kernel32-sys", - "libc", - "log", - "miow", - "net2", - "slab", - "winapi 0.2.8", -] - -[[package]] -name = "mio-extras" -version = "2.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52403fe290012ce777c4626790c8951324a2b9e3316b3143779c72b029742f19" -dependencies = [ - "lazycell", - "log", - "mio", - "slab", -] - -[[package]] -name = "mio-uds" -version = "0.6.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "afcb699eb26d4332647cc848492bbc15eafb26f08d0304550d5aa1f612e066f0" -dependencies = [ - "iovec", - "libc", - "mio", -] - -[[package]] -name = "miow" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebd808424166322d4a38da87083bfddd3ac4c131334ed55856112eb06d46944d" -dependencies = [ - "kernel32-sys", - "net2", - "winapi 0.2.8", - "ws2_32-sys", -] - -[[package]] -name = "net2" -version = "0.2.37" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "391630d12b68002ae1e25e8f974306474966550ad82dac6886fb8910c19568ae" -dependencies = [ - "cfg-if 0.1.10", - "libc", - "winapi 0.3.9", -] - -[[package]] -name = "nix" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "becb657d662f1cd2ef38c7ad480ec6b8cf9e96b27adb543e594f9cf0f2e6065c" -dependencies = [ - "bitflags", - "cc", - "cfg-if 0.1.10", - "libc", - "void", -] - -[[package]] -name = "num_cpus" -version = "1.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05499f3756671c15885fee9034446956fff3f243d6077b91e5767df161f766b3" -dependencies = [ - "hermit-abi", - "libc", -] - -[[package]] -name = "object" -version = "0.22.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d3b63360ec3cb337817c2dbd47ab4a0f170d285d8e5a2064600f3def1402397" - -[[package]] -name = "opaque-debug" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c" - -[[package]] -name = "owning_ref" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ff55baddef9e4ad00f88b6c743a2a8062d4c6ade126c2a528644b8e444d52ce" -dependencies = [ - "stable_deref_trait", -] - -[[package]] -name = "parking_lot" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab41b4aed082705d1056416ae4468b6ea99d52599ecf3169b00088d43113e337" -dependencies = [ - "lock_api 0.1.5", - "parking_lot_core 0.4.0", -] - -[[package]] -name = "parking_lot" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f842b1982eb6c2fe34036a4fbfb06dd185a3f5c8edfaacdf7d1ea10b07de6252" -dependencies = [ - "lock_api 0.3.4", - "parking_lot_core 0.6.2", - "rustc_version", -] - -[[package]] -name = "parking_lot_core" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94c8c7923936b28d546dfd14d4472eaf34c99b14e1c973a32b3e6d4eb04298c9" -dependencies = [ - "libc", - "rand", - "rustc_version", - "smallvec", - "winapi 0.3.9", -] - -[[package]] -name = "parking_lot_core" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b876b1b9e7ac6e1a74a6da34d25c42e17e8862aa409cbbbdcfc8d86c6f3bc62b" -dependencies = [ - "cfg-if 0.1.10", - "cloudabi", - "libc", - "redox_syscall", - "rustc_version", - "smallvec", - "winapi 0.3.9", -] - -[[package]] -name = "peach-buttons" -version = "0.1.3" -dependencies = [ - "crossbeam-channel", - "env_logger", - "gpio-cdev", - "jsonrpc-core", - "jsonrpc-pubsub", - "jsonrpc-test", - "jsonrpc-ws-server", - "log", - "snafu", -] - -[[package]] -name = "percent-encoding" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31010dd2e1ac33d5b46a5b413495239882813e0369f8ed8a5e266f173602f831" - -[[package]] -name = "proc-macro2" -version = "0.4.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759" -dependencies = [ - "unicode-xid 0.1.0", -] - -[[package]] -name = "proc-macro2" -version = "1.0.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e0704ee1a7e00d7bb417d0770ea303c1bccbabf0ef1667dae92b5967f5f8a71" -dependencies = [ - "unicode-xid 0.2.1", -] - -[[package]] -name = "quick-error" -version = "1.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" - -[[package]] -name = "quote" -version = "0.6.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ce23b6b870e8f94f81fb0a363d65d86675884b34a09043c81e5562f11c1f8e1" -dependencies = [ - "proc-macro2 0.4.30", -] - -[[package]] -name = "quote" -version = "1.0.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "991431c3519a3f36861882da93630ce66b52918dcf1b8e2fd66b397fc96f28df" -dependencies = [ - "proc-macro2 1.0.24", -] - -[[package]] -name = "rand" -version = "0.6.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d71dacdc3c88c1fde3885a3be3fbab9f35724e6ce99467f7d9c5026132184ca" -dependencies = [ - "autocfg 0.1.7", - "libc", - "rand_chacha", - "rand_core 0.4.2", - "rand_hc", - "rand_isaac", - "rand_jitter", - "rand_os", - "rand_pcg", - "rand_xorshift", - "winapi 0.3.9", -] - -[[package]] -name = "rand_chacha" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "556d3a1ca6600bfcbab7c7c91ccb085ac7fbbcd70e008a98742e7847f4f7bcef" -dependencies = [ - "autocfg 0.1.7", - "rand_core 0.3.1", -] - -[[package]] -name = "rand_core" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" -dependencies = [ - "rand_core 0.4.2", -] - -[[package]] -name = "rand_core" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc" - -[[package]] -name = "rand_hc" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b40677c7be09ae76218dc623efbf7b18e34bced3f38883af07bb75630a21bc4" -dependencies = [ - "rand_core 0.3.1", -] - -[[package]] -name = "rand_isaac" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ded997c9d5f13925be2a6fd7e66bf1872597f759fd9dd93513dd7e92e5a5ee08" -dependencies = [ - "rand_core 0.3.1", -] - -[[package]] -name = "rand_jitter" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1166d5c91dc97b88d1decc3285bb0a99ed84b05cfd0bc2341bdf2d43fc41e39b" -dependencies = [ - "libc", - "rand_core 0.4.2", - "winapi 0.3.9", -] - -[[package]] -name = "rand_os" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b75f676a1e053fc562eafbb47838d67c84801e38fc1ba459e8f180deabd5071" -dependencies = [ - "cloudabi", - "fuchsia-cprng", - "libc", - "rand_core 0.4.2", - "rdrand", - "winapi 0.3.9", -] - -[[package]] -name = "rand_pcg" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abf9b09b01790cfe0364f52bf32995ea3c39f4d2dd011eac241d2914146d0b44" -dependencies = [ - "autocfg 0.1.7", - "rand_core 0.4.2", -] - -[[package]] -name = "rand_xorshift" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cbf7e9e623549b0e21f6e97cf8ecf247c1a8fd2e8a992ae265314300b2455d5c" -dependencies = [ - "rand_core 0.3.1", -] - -[[package]] -name = "rdrand" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" -dependencies = [ - "rand_core 0.3.1", -] - -[[package]] -name = "redox_syscall" -version = "0.1.57" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce" - -[[package]] -name = "regex" -version = "1.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38cf2c13ed4745de91a5eb834e11c00bcc3709e773173b2ce4c56c9fbde04b9c" -dependencies = [ - "aho-corasick", - "memchr", - "regex-syntax", - "thread_local", -] - -[[package]] -name = "regex-syntax" -version = "0.6.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b181ba2dcf07aaccad5448e8ead58db5b742cf85dfe035e2227f137a539a189" - -[[package]] -name = "rustc-demangle" -version = "0.1.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e3bad0ee36814ca07d7968269dd4b7ec89ec2da10c4bb613928d3077083c232" - -[[package]] -name = "rustc_version" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" -dependencies = [ - "semver", -] - -[[package]] -name = "ryu" -version = "1.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e" - -[[package]] -name = "scopeguard" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94258f53601af11e6a49f722422f6e3425c52b06245a5cf9bc09908b174f5e27" - -[[package]] -name = "scopeguard" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" - -[[package]] -name = "semver" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" -dependencies = [ - "semver-parser", -] - -[[package]] -name = "semver-parser" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" - -[[package]] -name = "serde" -version = "1.0.118" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06c64263859d87aa2eb554587e2d23183398d617427327cf2b3d0ed8c69e4800" - -[[package]] -name = "serde_derive" -version = "1.0.118" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c84d3526699cd55261af4b941e4e725444df67aa4f9e6a3564f18030d12672df" -dependencies = [ - "proc-macro2 1.0.24", - "quote 1.0.8", - "syn 1.0.56", -] - -[[package]] -name = "serde_json" -version = "1.0.61" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fceb2595057b6891a4ee808f70054bd2d12f0e97f1cbb78689b59f676df325a" -dependencies = [ - "itoa", - "ryu", - "serde", -] - -[[package]] -name = "sha-1" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7d94d0bede923b3cea61f3f1ff57ff8cdfd77b400fb8f9998949e0cf04163df" -dependencies = [ - "block-buffer", - "digest", - "fake-simd", - "opaque-debug", -] - -[[package]] -name = "slab" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8" - -[[package]] -name = "smallvec" -version = "0.6.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7b0758c52e15a8b5e3691eae6cc559f08eee9406e548a4477ba4e67770a82b6" -dependencies = [ - "maybe-uninit", -] - -[[package]] -name = "snafu" -version = "0.4.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b028158eb06caa8345bee10cccfb25fa632beccf0ef5308832b4fd4b78a7db48" -dependencies = [ - "backtrace", - "doc-comment", - "snafu-derive", -] - -[[package]] -name = "snafu-derive" -version = "0.4.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf50aaef500c248a590e2696e8bf8c7620ca2235b9bb90a70363d82dd1abec6a" -dependencies = [ - "proc-macro2 0.4.30", - "quote 0.6.13", - "syn 0.15.44", -] - -[[package]] -name = "stable_deref_trait" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" - -[[package]] -name = "syn" -version = "0.15.44" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ca4b3b69a77cbe1ffc9e198781b7acb0c7365a883670e8f1c1bc66fba79a5c5" -dependencies = [ - "proc-macro2 0.4.30", - "quote 0.6.13", - "unicode-xid 0.1.0", -] - -[[package]] -name = "syn" -version = "1.0.56" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9802ddde94170d186eeee5005b798d9c159fa970403f1be19976d0cfb939b72" -dependencies = [ - "proc-macro2 1.0.24", - "quote 1.0.8", - "unicode-xid 0.2.1", -] - -[[package]] -name = "synstructure" -version = "0.12.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b834f2d66f734cb897113e34aaff2f1ab4719ca946f9a7358dba8f8064148701" -dependencies = [ - "proc-macro2 1.0.24", - "quote 1.0.8", - "syn 1.0.56", - "unicode-xid 0.2.1", -] - -[[package]] -name = "termcolor" -version = "1.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dfed899f0eb03f32ee8c6a0aabdb8a7949659e3466561fc0adf54e26d88c5f4" -dependencies = [ - "winapi-util", -] - -[[package]] -name = "thread_local" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d40c6d1b69745a6ec6fb1ca717914848da4b44ae29d9b3080cbee91d72a69b14" -dependencies = [ - "lazy_static", -] - -[[package]] -name = "tinyvec" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ccf8dbc19eb42fba10e8feaaec282fb50e2c14b2726d6301dbfeed0f73306a6f" -dependencies = [ - "tinyvec_macros", -] - -[[package]] -name = "tinyvec_macros" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" - -[[package]] -name = "tokio" -version = "0.1.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a09c0b5bb588872ab2f09afa13ee6e9dac11e10a0ec9e8e3ba39a5a5d530af6" -dependencies = [ - "bytes", - "futures", - "mio", - "num_cpus", - "tokio-codec", - "tokio-current-thread", - "tokio-executor", - "tokio-fs", - "tokio-io", - "tokio-reactor", - "tokio-sync", - "tokio-tcp", - "tokio-threadpool", - "tokio-timer", - "tokio-udp", - "tokio-uds", -] - -[[package]] -name = "tokio-codec" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25b2998660ba0e70d18684de5d06b70b70a3a747469af9dea7618cc59e75976b" -dependencies = [ - "bytes", - "futures", - "tokio-io", -] - -[[package]] -name = "tokio-current-thread" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1de0e32a83f131e002238d7ccde18211c0a5397f60cbfffcb112868c2e0e20e" -dependencies = [ - "futures", - "tokio-executor", -] - -[[package]] -name = "tokio-executor" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb2d1b8f4548dbf5e1f7818512e9c406860678f29c300cdf0ebac72d1a3a1671" -dependencies = [ - "crossbeam-utils 0.7.2", - "futures", -] - -[[package]] -name = "tokio-fs" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "297a1206e0ca6302a0eed35b700d292b275256f596e2f3fea7729d5e629b6ff4" -dependencies = [ - "futures", - "tokio-io", - "tokio-threadpool", -] - -[[package]] -name = "tokio-io" -version = "0.1.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57fc868aae093479e3131e3d165c93b1c7474109d13c90ec0dda2a1bbfff0674" -dependencies = [ - "bytes", - "futures", - "log", -] - -[[package]] -name = "tokio-reactor" -version = "0.1.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09bc590ec4ba8ba87652da2068d150dcada2cfa2e07faae270a5e0409aa51351" -dependencies = [ - "crossbeam-utils 0.7.2", - "futures", - "lazy_static", - "log", - "mio", - "num_cpus", - "parking_lot 0.9.0", - "slab", - "tokio-executor", - "tokio-io", - "tokio-sync", -] - -[[package]] -name = "tokio-sync" -version = "0.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edfe50152bc8164fcc456dab7891fa9bf8beaf01c5ee7e1dd43a397c3cf87dee" -dependencies = [ - "fnv", - "futures", -] - -[[package]] -name = "tokio-tcp" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "98df18ed66e3b72e742f185882a9e201892407957e45fbff8da17ae7a7c51f72" -dependencies = [ - "bytes", - "futures", - "iovec", - "mio", - "tokio-io", - "tokio-reactor", -] - -[[package]] -name = "tokio-threadpool" -version = "0.1.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df720b6581784c118f0eb4310796b12b1d242a7eb95f716a8367855325c25f89" -dependencies = [ - "crossbeam-deque", - "crossbeam-queue", - "crossbeam-utils 0.7.2", - "futures", - "lazy_static", - "log", - "num_cpus", - "slab", - "tokio-executor", -] - -[[package]] -name = "tokio-timer" -version = "0.2.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93044f2d313c95ff1cb7809ce9a7a05735b012288a888b62d4434fd58c94f296" -dependencies = [ - "crossbeam-utils 0.7.2", - "futures", - "slab", - "tokio-executor", -] - -[[package]] -name = "tokio-udp" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2a0b10e610b39c38b031a2fcab08e4b82f16ece36504988dcbd81dbba650d82" -dependencies = [ - "bytes", - "futures", - "log", - "mio", - "tokio-codec", - "tokio-io", - "tokio-reactor", -] - -[[package]] -name = "tokio-uds" -version = "0.2.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab57a4ac4111c8c9dbcf70779f6fc8bc35ae4b2454809febac840ad19bd7e4e0" -dependencies = [ - "bytes", - "futures", - "iovec", - "libc", - "log", - "mio", - "mio-uds", - "tokio-codec", - "tokio-io", - "tokio-reactor", -] - -[[package]] -name = "typenum" -version = "1.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "373c8a200f9e67a0c95e62a4f52fbf80c23b4381c05a17845531982fa99e6b33" - -[[package]] -name = "unicase" -version = "2.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50f37be617794602aabbeee0be4f259dc1778fabe05e2d67ee8f79326d5cb4f6" -dependencies = [ - "version_check", -] - -[[package]] -name = "unicode-bidi" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5" -dependencies = [ - "matches", -] - -[[package]] -name = "unicode-normalization" -version = "0.1.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a13e63ab62dbe32aeee58d1c5408d35c36c392bba5d9d3142287219721afe606" -dependencies = [ - "tinyvec", -] - -[[package]] -name = "unicode-xid" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" - -[[package]] -name = "unicode-xid" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564" - -[[package]] -name = "url" -version = "1.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd4e7c0d531266369519a4aa4f399d748bd37043b00bde1e4ff1f60a120b355a" -dependencies = [ - "idna", - "matches", - "percent-encoding", -] - -[[package]] -name = "version_check" -version = "0.9.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5a972e5669d67ba988ce3dc826706fb0a8b01471c088cb0b6110b805cc36aed" - -[[package]] -name = "void" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" - -[[package]] -name = "winapi" -version = "0.2.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" - -[[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-build" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" - -[[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.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" -dependencies = [ - "winapi 0.3.9", -] - -[[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 = "ws" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec91ea61b83ce033c43c06c52ddc7532f465c0153281610d44c58b74083aee1a" -dependencies = [ - "byteorder", - "bytes", - "httparse", - "log", - "mio", - "mio-extras", - "rand", - "sha-1", - "slab", - "url", -] - -[[package]] -name = "ws2_32-sys" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d59cefebd0c892fa2dd6de581e937301d8552cb44489cdff035c6187cb63fa5e" -dependencies = [ - "winapi 0.2.8", - "winapi-build", -] diff --git a/peach-oled/Cargo.lock b/peach-oled/Cargo.lock deleted file mode 100644 index 99b28bd..0000000 --- a/peach-oled/Cargo.lock +++ /dev/null @@ -1,1603 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -[[package]] -name = "addr2line" -version = "0.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c0929d69e78dd9bf5408269919fcbcaeb2e35e5d43e5815517cdc6a8e11a423" -dependencies = [ - "gimli", -] - -[[package]] -name = "adler" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee2a4ec343196209d6594e19543ae87a39f96d5534d7174822a3ad825dd6ed7e" - -[[package]] -name = "aho-corasick" -version = "0.7.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7404febffaa47dac81aa44dba71523c9d069b1bdc50a77db41195149e17f68e5" -dependencies = [ - "memchr", -] - -[[package]] -name = "atty" -version = "0.2.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" -dependencies = [ - "hermit-abi", - "libc", - "winapi 0.3.9", -] - -[[package]] -name = "autocfg" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d49d90015b3c36167a20fe2810c5cd875ad504b39cff3d4eae7977e6b7c1cb2" - -[[package]] -name = "autocfg" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" - -[[package]] -name = "backtrace" -version = "0.3.55" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef5140344c85b01f9bbb4d4b7288a8aa4b3287ccef913a14bcc78a1063623598" -dependencies = [ - "addr2line", - "cfg-if 1.0.0", - "libc", - "miniz_oxide", - "object", - "rustc-demangle", -] - -[[package]] -name = "bitflags" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32866f4d103c4e438b1db1158aa1b1a80ee078e5d77a59a2f906fd62a577389c" - -[[package]] -name = "bitflags" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8dead7461c1127cf637931a1e50934eb6eee8bff2f74433ac7909e9afcee04a3" - -[[package]] -name = "bitflags" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" - -[[package]] -name = "bstr" -version = "0.2.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "473fc6b38233f9af7baa94fb5852dca389e3d95b8e21c8e3719301462c5d9faf" -dependencies = [ - "memchr", -] - -[[package]] -name = "byteorder" -version = "1.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de" - -[[package]] -name = "bytes" -version = "0.4.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "206fdffcfa2df7cbe15601ef46c813fce0965eb3286db6b56c583b814b51c81c" -dependencies = [ - "byteorder", - "either", - "iovec", -] - -[[package]] -name = "cast" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b9434b9a5aa1450faa3f9cb14ea0e8c53bb5d2b3c1bfd1ab4fc03e9f33fbfb0" -dependencies = [ - "rustc_version 0.2.3", -] - -[[package]] -name = "cc" -version = "1.0.66" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c0496836a84f8d0495758516b8621a622beb77c0fed418570e50764093ced48" - -[[package]] -name = "cfg-if" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" - -[[package]] -name = "cfg-if" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" - -[[package]] -name = "cloudabi" -version = "0.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" -dependencies = [ - "bitflags 1.2.1", -] - -[[package]] -name = "crossbeam-deque" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f02af974daeee82218205558e51ec8768b48cf524bd01d550abe5573a608285" -dependencies = [ - "crossbeam-epoch", - "crossbeam-utils", - "maybe-uninit", -] - -[[package]] -name = "crossbeam-epoch" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "058ed274caafc1f60c4997b5fc07bf7dc7cca454af7c6e81edffe5f33f70dace" -dependencies = [ - "autocfg 1.0.1", - "cfg-if 0.1.10", - "crossbeam-utils", - "lazy_static", - "maybe-uninit", - "memoffset", - "scopeguard 1.1.0", -] - -[[package]] -name = "crossbeam-queue" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "774ba60a54c213d409d5353bda12d49cd68d14e45036a285234c8d6f91f92570" -dependencies = [ - "cfg-if 0.1.10", - "crossbeam-utils", - "maybe-uninit", -] - -[[package]] -name = "crossbeam-utils" -version = "0.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3c7c73a2d1e9fc0886a08b93e98eb643461230d5f1925e4036204d5f2e261a8" -dependencies = [ - "autocfg 1.0.1", - "cfg-if 0.1.10", - "lazy_static", -] - -[[package]] -name = "doc-comment" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10" - -[[package]] -name = "either" -version = "1.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" - -[[package]] -name = "embedded-graphics" -version = "0.4.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2e7ee289ac88cbeea6f749cd72c6eb4cdeb801f4ea26795aace97b9776a2db2" -dependencies = [ - "tinybmp", - "tinytga", -] - -[[package]] -name = "embedded-hal" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa998ce59ec9765d15216393af37a58961ddcefb14c753b4816ba2191d865fcb" -dependencies = [ - "nb 0.1.3", - "void", -] - -[[package]] -name = "env_logger" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aafcde04e90a5226a6443b7aabdb016ba2f8307c847d524724bd9b346dd1a2d3" -dependencies = [ - "atty", - "humantime", - "log", - "regex", - "termcolor", -] - -[[package]] -name = "failure" -version = "0.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d32e9bd16cc02eae7db7ef620b392808b89f6a5e16bb3497d159c6b92a0f4f86" -dependencies = [ - "backtrace", - "failure_derive", -] - -[[package]] -name = "failure_derive" -version = "0.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa4da3c766cd7a0db8242e326e9e4e081edd567072893ed320008189715366a4" -dependencies = [ - "proc-macro2 1.0.24", - "quote 1.0.8", - "syn 1.0.56", - "synstructure", -] - -[[package]] -name = "fnv" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" - -[[package]] -name = "fuchsia-cprng" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" - -[[package]] -name = "fuchsia-zircon" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82" -dependencies = [ - "bitflags 1.2.1", - "fuchsia-zircon-sys", -] - -[[package]] -name = "fuchsia-zircon-sys" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" - -[[package]] -name = "futures" -version = "0.1.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c7e4c2612746b0df8fed4ce0c69156021b704c9aefa360311c04e6e9e002eed" - -[[package]] -name = "futures-cpupool" -version = "0.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab90cde24b3319636588d0c35fe03b1333857621051837ed769faefb4c2162e4" -dependencies = [ - "futures", - "num_cpus", -] - -[[package]] -name = "gimli" -version = "0.23.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6503fe142514ca4799d4c26297c4248239fe8838d827db6bd6065c6ed29a6ce" - -[[package]] -name = "globset" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c152169ef1e421390738366d2f796655fec62621dabbd0fd476f905934061e4a" -dependencies = [ - "aho-corasick", - "bstr", - "fnv", - "log", - "regex", -] - -[[package]] -name = "h2" -version = "0.1.26" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5b34c246847f938a410a03c5458c7fee2274436675e76d8b903c08efc29c462" -dependencies = [ - "byteorder", - "bytes", - "fnv", - "futures", - "http", - "indexmap", - "log", - "slab", - "string", - "tokio-io", -] - -[[package]] -name = "hashbrown" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7afe4a420e3fe79967a00898cc1f4db7c8a49a9333a29f8a4bd76a253d5cd04" - -[[package]] -name = "hermit-abi" -version = "0.1.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5aca5565f760fb5b220e499d72710ed156fdb74e631659e99377d9ebfbd13ae8" -dependencies = [ - "libc", -] - -[[package]] -name = "http" -version = "0.1.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6ccf5ede3a895d8856620237b2f02972c1bbc78d2965ad7fe8838d4a0ed41f0" -dependencies = [ - "bytes", - "fnv", - "itoa", -] - -[[package]] -name = "http-body" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6741c859c1b2463a423a1dbce98d418e6c3c3fc720fb0d45528657320920292d" -dependencies = [ - "bytes", - "futures", - "http", - "tokio-buf", -] - -[[package]] -name = "httparse" -version = "1.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd179ae861f0c2e53da70d892f5f3029f9594be0c41dc5269cd371691b1dc2f9" - -[[package]] -name = "humantime" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df004cfca50ef23c36850aaaa59ad52cc70d0e90243c3c7737a4dd32dc7a3c4f" -dependencies = [ - "quick-error", -] - -[[package]] -name = "hyper" -version = "0.12.35" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9dbe6ed1438e1f8ad955a4701e9a944938e9519f6888d12d8558b645e247d5f6" -dependencies = [ - "bytes", - "futures", - "futures-cpupool", - "h2", - "http", - "http-body", - "httparse", - "iovec", - "itoa", - "log", - "net2", - "rustc_version 0.2.3", - "time", - "tokio", - "tokio-buf", - "tokio-executor", - "tokio-io", - "tokio-reactor", - "tokio-tcp", - "tokio-threadpool", - "tokio-timer", - "want", -] - -[[package]] -name = "i2cdev" -version = "0.4.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c0eb3d9b6b02dc2508ee23439170004e44344bab9d53a490eb1f64c885b5003" -dependencies = [ - "bitflags 1.2.1", - "byteorder", - "libc", - "nix 0.14.1", -] - -[[package]] -name = "indexmap" -version = "1.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fb1fa934250de4de8aef298d81c729a7d33d8c239daa3a7575e6b92bfc7313b" -dependencies = [ - "autocfg 1.0.1", - "hashbrown", -] - -[[package]] -name = "iovec" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2b3ea6ff95e175473f8ffe6a7eb7c00d054240321b84c57051175fe3c1e075e" -dependencies = [ - "libc", -] - -[[package]] -name = "itoa" -version = "0.4.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd25036021b0de88a0aff6b850051563c6516d0bf53f8638938edbb9de732736" - -[[package]] -name = "jsonrpc-core" -version = "11.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97b83fdc5e0218128d0d270f2f2e7a5ea716f3240c8518a58bc89e6716ba8581" -dependencies = [ - "futures", - "log", - "serde", - "serde_derive", - "serde_json", -] - -[[package]] -name = "jsonrpc-core-client" -version = "11.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c889ca27072f038496a62f38356e8f827acf194d7276030120265362b2974eab" -dependencies = [ - "failure", - "futures", - "jsonrpc-core", - "log", - "serde", - "serde_json", -] - -[[package]] -name = "jsonrpc-http-server" -version = "11.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "541257be6c8f75a41812575150dfa1120d3ee3a852601f2ca8ac9bcb73575c4e" -dependencies = [ - "hyper", - "jsonrpc-core", - "jsonrpc-server-utils", - "log", - "net2", - "unicase", -] - -[[package]] -name = "jsonrpc-pubsub" -version = "11.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c233c4570183a45f7bde14cd7d23446d6c236de6df9442e53a60951adae9fd34" -dependencies = [ - "jsonrpc-core", - "log", - "parking_lot 0.7.1", - "serde", -] - -[[package]] -name = "jsonrpc-server-utils" -version = "11.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3372b3248a53abcca8f61924f188052bb0c4cd80b482b2b4eaf9f8667efb9f4" -dependencies = [ - "bytes", - "globset", - "jsonrpc-core", - "lazy_static", - "log", - "num_cpus", - "tokio", - "tokio-codec", - "unicase", -] - -[[package]] -name = "jsonrpc-test" -version = "11.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0aedad254cd8faba2bf8d1fe00c52fe9d9944f1a8c3f789916b68a61a3414c87" -dependencies = [ - "jsonrpc-core", - "jsonrpc-core-client", - "jsonrpc-pubsub", - "log", - "serde", - "serde_json", -] - -[[package]] -name = "kernel32-sys" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" -dependencies = [ - "winapi 0.2.8", - "winapi-build", -] - -[[package]] -name = "lazy_static" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" - -[[package]] -name = "libc" -version = "0.2.81" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1482821306169ec4d07f6aca392a4681f66c75c9918aa49641a2595db64053cb" - -[[package]] -name = "linux-embedded-hal" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "795096c0eecb0622afb591c3e1a97b1ba046688a7689957b70b8eee9cac8fb84" -dependencies = [ - "cast", - "embedded-hal", - "i2cdev", - "spidev", - "sysfs_gpio", -] - -[[package]] -name = "lock_api" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62ebf1391f6acad60e5c8b43706dde4582df75c06698ab44511d15016bc2442c" -dependencies = [ - "owning_ref", - "scopeguard 0.3.3", -] - -[[package]] -name = "lock_api" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4da24a77a3d8a6d4862d95f72e6fdb9c09a643ecdb402d754004a557f2bec75" -dependencies = [ - "scopeguard 1.1.0", -] - -[[package]] -name = "log" -version = "0.4.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fabed175da42fed1fa0746b0ea71f412aa9d35e76e95e59b192c64b9dc2bf8b" -dependencies = [ - "cfg-if 0.1.10", -] - -[[package]] -name = "maybe-uninit" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60302e4db3a61da70c0cb7991976248362f30319e88850c487b9b95bbf059e00" - -[[package]] -name = "memchr" -version = "2.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ee1c47aaa256ecabcaea351eae4a9b01ef39ed810004e298d2511ed284b1525" - -[[package]] -name = "memoffset" -version = "0.5.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "043175f069eda7b85febe4a74abbaeff828d9f8b448515d3151a14a3542811aa" -dependencies = [ - "autocfg 1.0.1", -] - -[[package]] -name = "miniz_oxide" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f2d26ec3309788e423cfbf68ad1800f061638098d76a83681af979dc4eda19d" -dependencies = [ - "adler", - "autocfg 1.0.1", -] - -[[package]] -name = "mio" -version = "0.6.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4afd66f5b91bf2a3bc13fad0e21caedac168ca4c707504e75585648ae80e4cc4" -dependencies = [ - "cfg-if 0.1.10", - "fuchsia-zircon", - "fuchsia-zircon-sys", - "iovec", - "kernel32-sys", - "libc", - "log", - "miow", - "net2", - "slab", - "winapi 0.2.8", -] - -[[package]] -name = "mio-uds" -version = "0.6.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "afcb699eb26d4332647cc848492bbc15eafb26f08d0304550d5aa1f612e066f0" -dependencies = [ - "iovec", - "libc", - "mio", -] - -[[package]] -name = "miow" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebd808424166322d4a38da87083bfddd3ac4c131334ed55856112eb06d46944d" -dependencies = [ - "kernel32-sys", - "net2", - "winapi 0.2.8", - "ws2_32-sys", -] - -[[package]] -name = "nb" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "801d31da0513b6ec5214e9bf433a77966320625a37860f910be265be6e18d06f" -dependencies = [ - "nb 1.0.0", -] - -[[package]] -name = "nb" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "546c37ac5d9e56f55e73b677106873d9d9f5190605e41a856503623648488cae" - -[[package]] -name = "net2" -version = "0.2.37" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "391630d12b68002ae1e25e8f974306474966550ad82dac6886fb8910c19568ae" -dependencies = [ - "cfg-if 0.1.10", - "libc", - "winapi 0.3.9", -] - -[[package]] -name = "nix" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a7bb1da2be7da3cbffda73fc681d509ffd9e665af478d2bee1907cee0bc64b2" -dependencies = [ - "bitflags 0.4.0", - "cfg-if 0.1.10", - "libc", - "rustc_version 0.1.7", - "semver 0.1.20", - "void", -] - -[[package]] -name = "nix" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "becb657d662f1cd2ef38c7ad480ec6b8cf9e96b27adb543e594f9cf0f2e6065c" -dependencies = [ - "bitflags 1.2.1", - "cc", - "cfg-if 0.1.10", - "libc", - "void", -] - -[[package]] -name = "nix" -version = "0.14.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c722bee1037d430d0f8e687bbdbf222f27cc6e4e68d5caf630857bb2b6dbdce" -dependencies = [ - "bitflags 1.2.1", - "cc", - "cfg-if 0.1.10", - "libc", - "void", -] - -[[package]] -name = "nom" -version = "4.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ad2a91a8e869eeb30b9cb3119ae87773a8f4ae617f41b1eb9c154b2905f7bd6" -dependencies = [ - "memchr", - "version_check 0.1.5", -] - -[[package]] -name = "nom" -version = "5.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffb4262d26ed83a1c0a33a38fe2bb15797329c85770da05e6b828ddb782627af" -dependencies = [ - "memchr", - "version_check 0.9.2", -] - -[[package]] -name = "num_cpus" -version = "1.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05499f3756671c15885fee9034446956fff3f243d6077b91e5767df161f766b3" -dependencies = [ - "hermit-abi", - "libc", -] - -[[package]] -name = "object" -version = "0.22.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d3b63360ec3cb337817c2dbd47ab4a0f170d285d8e5a2064600f3def1402397" - -[[package]] -name = "owning_ref" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ff55baddef9e4ad00f88b6c743a2a8062d4c6ade126c2a528644b8e444d52ce" -dependencies = [ - "stable_deref_trait", -] - -[[package]] -name = "parking_lot" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab41b4aed082705d1056416ae4468b6ea99d52599ecf3169b00088d43113e337" -dependencies = [ - "lock_api 0.1.5", - "parking_lot_core 0.4.0", -] - -[[package]] -name = "parking_lot" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f842b1982eb6c2fe34036a4fbfb06dd185a3f5c8edfaacdf7d1ea10b07de6252" -dependencies = [ - "lock_api 0.3.4", - "parking_lot_core 0.6.2", - "rustc_version 0.2.3", -] - -[[package]] -name = "parking_lot_core" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94c8c7923936b28d546dfd14d4472eaf34c99b14e1c973a32b3e6d4eb04298c9" -dependencies = [ - "libc", - "rand", - "rustc_version 0.2.3", - "smallvec", - "winapi 0.3.9", -] - -[[package]] -name = "parking_lot_core" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b876b1b9e7ac6e1a74a6da34d25c42e17e8862aa409cbbbdcfc8d86c6f3bc62b" -dependencies = [ - "cfg-if 0.1.10", - "cloudabi", - "libc", - "redox_syscall", - "rustc_version 0.2.3", - "smallvec", - "winapi 0.3.9", -] - -[[package]] -name = "peach-oled" -version = "0.1.3" -dependencies = [ - "embedded-graphics", - "env_logger", - "jsonrpc-core", - "jsonrpc-http-server", - "jsonrpc-test", - "linux-embedded-hal", - "log", - "nix 0.11.1", - "serde", - "serde_json", - "snafu", - "ssd1306", - "tinybmp", -] - -[[package]] -name = "proc-macro2" -version = "0.4.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759" -dependencies = [ - "unicode-xid 0.1.0", -] - -[[package]] -name = "proc-macro2" -version = "1.0.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e0704ee1a7e00d7bb417d0770ea303c1bccbabf0ef1667dae92b5967f5f8a71" -dependencies = [ - "unicode-xid 0.2.1", -] - -[[package]] -name = "quick-error" -version = "1.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" - -[[package]] -name = "quote" -version = "0.6.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ce23b6b870e8f94f81fb0a363d65d86675884b34a09043c81e5562f11c1f8e1" -dependencies = [ - "proc-macro2 0.4.30", -] - -[[package]] -name = "quote" -version = "1.0.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "991431c3519a3f36861882da93630ce66b52918dcf1b8e2fd66b397fc96f28df" -dependencies = [ - "proc-macro2 1.0.24", -] - -[[package]] -name = "rand" -version = "0.6.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d71dacdc3c88c1fde3885a3be3fbab9f35724e6ce99467f7d9c5026132184ca" -dependencies = [ - "autocfg 0.1.7", - "libc", - "rand_chacha", - "rand_core 0.4.2", - "rand_hc", - "rand_isaac", - "rand_jitter", - "rand_os", - "rand_pcg", - "rand_xorshift", - "winapi 0.3.9", -] - -[[package]] -name = "rand_chacha" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "556d3a1ca6600bfcbab7c7c91ccb085ac7fbbcd70e008a98742e7847f4f7bcef" -dependencies = [ - "autocfg 0.1.7", - "rand_core 0.3.1", -] - -[[package]] -name = "rand_core" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" -dependencies = [ - "rand_core 0.4.2", -] - -[[package]] -name = "rand_core" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc" - -[[package]] -name = "rand_hc" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b40677c7be09ae76218dc623efbf7b18e34bced3f38883af07bb75630a21bc4" -dependencies = [ - "rand_core 0.3.1", -] - -[[package]] -name = "rand_isaac" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ded997c9d5f13925be2a6fd7e66bf1872597f759fd9dd93513dd7e92e5a5ee08" -dependencies = [ - "rand_core 0.3.1", -] - -[[package]] -name = "rand_jitter" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1166d5c91dc97b88d1decc3285bb0a99ed84b05cfd0bc2341bdf2d43fc41e39b" -dependencies = [ - "libc", - "rand_core 0.4.2", - "winapi 0.3.9", -] - -[[package]] -name = "rand_os" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b75f676a1e053fc562eafbb47838d67c84801e38fc1ba459e8f180deabd5071" -dependencies = [ - "cloudabi", - "fuchsia-cprng", - "libc", - "rand_core 0.4.2", - "rdrand", - "winapi 0.3.9", -] - -[[package]] -name = "rand_pcg" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abf9b09b01790cfe0364f52bf32995ea3c39f4d2dd011eac241d2914146d0b44" -dependencies = [ - "autocfg 0.1.7", - "rand_core 0.4.2", -] - -[[package]] -name = "rand_xorshift" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cbf7e9e623549b0e21f6e97cf8ecf247c1a8fd2e8a992ae265314300b2455d5c" -dependencies = [ - "rand_core 0.3.1", -] - -[[package]] -name = "rdrand" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" -dependencies = [ - "rand_core 0.3.1", -] - -[[package]] -name = "redox_syscall" -version = "0.1.57" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce" - -[[package]] -name = "regex" -version = "1.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38cf2c13ed4745de91a5eb834e11c00bcc3709e773173b2ce4c56c9fbde04b9c" -dependencies = [ - "aho-corasick", - "memchr", - "regex-syntax", - "thread_local", -] - -[[package]] -name = "regex-syntax" -version = "0.6.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b181ba2dcf07aaccad5448e8ead58db5b742cf85dfe035e2227f137a539a189" - -[[package]] -name = "rustc-demangle" -version = "0.1.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e3bad0ee36814ca07d7968269dd4b7ec89ec2da10c4bb613928d3077083c232" - -[[package]] -name = "rustc_version" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5f5376ea5e30ce23c03eb77cbe4962b988deead10910c372b226388b594c084" -dependencies = [ - "semver 0.1.20", -] - -[[package]] -name = "rustc_version" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" -dependencies = [ - "semver 0.9.0", -] - -[[package]] -name = "ryu" -version = "1.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e" - -[[package]] -name = "scopeguard" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94258f53601af11e6a49f722422f6e3425c52b06245a5cf9bc09908b174f5e27" - -[[package]] -name = "scopeguard" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" - -[[package]] -name = "semver" -version = "0.1.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4f410fedcf71af0345d7607d246e7ad15faaadd49d240ee3b24e5dc21a820ac" - -[[package]] -name = "semver" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" -dependencies = [ - "semver-parser", -] - -[[package]] -name = "semver-parser" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" - -[[package]] -name = "serde" -version = "1.0.118" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06c64263859d87aa2eb554587e2d23183398d617427327cf2b3d0ed8c69e4800" -dependencies = [ - "serde_derive", -] - -[[package]] -name = "serde_derive" -version = "1.0.118" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c84d3526699cd55261af4b941e4e725444df67aa4f9e6a3564f18030d12672df" -dependencies = [ - "proc-macro2 1.0.24", - "quote 1.0.8", - "syn 1.0.56", -] - -[[package]] -name = "serde_json" -version = "1.0.61" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fceb2595057b6891a4ee808f70054bd2d12f0e97f1cbb78689b59f676df325a" -dependencies = [ - "itoa", - "ryu", - "serde", -] - -[[package]] -name = "slab" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8" - -[[package]] -name = "smallvec" -version = "0.6.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7b0758c52e15a8b5e3691eae6cc559f08eee9406e548a4477ba4e67770a82b6" -dependencies = [ - "maybe-uninit", -] - -[[package]] -name = "snafu" -version = "0.4.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b028158eb06caa8345bee10cccfb25fa632beccf0ef5308832b4fd4b78a7db48" -dependencies = [ - "backtrace", - "doc-comment", - "snafu-derive", -] - -[[package]] -name = "snafu-derive" -version = "0.4.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf50aaef500c248a590e2696e8bf8c7620ca2235b9bb90a70363d82dd1abec6a" -dependencies = [ - "proc-macro2 0.4.30", - "quote 0.6.13", - "syn 0.15.44", -] - -[[package]] -name = "spidev" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ba01d3ef92a37e898fecac76cd3e1b33c999395e2d70787608d9678c4293e04" -dependencies = [ - "bitflags 0.3.3", - "libc", - "nix 0.6.0", -] - -[[package]] -name = "ssd1306" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57d818022001ebca8cec28b230700660a3f6a027123c8193c5e76e9764d087f3" -dependencies = [ - "embedded-graphics", - "embedded-hal", -] - -[[package]] -name = "stable_deref_trait" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" - -[[package]] -name = "string" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d24114bfcceb867ca7f71a0d3fe45d45619ec47a6fbfa98cb14e14250bfa5d6d" -dependencies = [ - "bytes", -] - -[[package]] -name = "syn" -version = "0.15.44" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ca4b3b69a77cbe1ffc9e198781b7acb0c7365a883670e8f1c1bc66fba79a5c5" -dependencies = [ - "proc-macro2 0.4.30", - "quote 0.6.13", - "unicode-xid 0.1.0", -] - -[[package]] -name = "syn" -version = "1.0.56" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9802ddde94170d186eeee5005b798d9c159fa970403f1be19976d0cfb939b72" -dependencies = [ - "proc-macro2 1.0.24", - "quote 1.0.8", - "unicode-xid 0.2.1", -] - -[[package]] -name = "synstructure" -version = "0.12.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b834f2d66f734cb897113e34aaff2f1ab4719ca946f9a7358dba8f8064148701" -dependencies = [ - "proc-macro2 1.0.24", - "quote 1.0.8", - "syn 1.0.56", - "unicode-xid 0.2.1", -] - -[[package]] -name = "sysfs_gpio" -version = "0.5.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24961a55846623d8e4f6cec38718945116fed8d6970336a7110710a07aa9b5d1" -dependencies = [ - "nix 0.14.1", -] - -[[package]] -name = "termcolor" -version = "1.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dfed899f0eb03f32ee8c6a0aabdb8a7949659e3466561fc0adf54e26d88c5f4" -dependencies = [ - "winapi-util", -] - -[[package]] -name = "thread_local" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d40c6d1b69745a6ec6fb1ca717914848da4b44ae29d9b3080cbee91d72a69b14" -dependencies = [ - "lazy_static", -] - -[[package]] -name = "time" -version = "0.1.44" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6db9e6914ab8b1ae1c260a4ae7a49b6c5611b40328a735b21862567685e73255" -dependencies = [ - "libc", - "wasi", - "winapi 0.3.9", -] - -[[package]] -name = "tinybmp" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30d12b7f8b271567d6d072c49dee16b22271aabfc473e2066e3353e5af0f5230" -dependencies = [ - "nom 5.1.2", -] - -[[package]] -name = "tinytga" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc9485052c1f4b541d888f1d564dd9957671e0c21da9bca0c9824c1123e03f07" -dependencies = [ - "nom 4.2.3", -] - -[[package]] -name = "tokio" -version = "0.1.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a09c0b5bb588872ab2f09afa13ee6e9dac11e10a0ec9e8e3ba39a5a5d530af6" -dependencies = [ - "bytes", - "futures", - "mio", - "num_cpus", - "tokio-codec", - "tokio-current-thread", - "tokio-executor", - "tokio-fs", - "tokio-io", - "tokio-reactor", - "tokio-sync", - "tokio-tcp", - "tokio-threadpool", - "tokio-timer", - "tokio-udp", - "tokio-uds", -] - -[[package]] -name = "tokio-buf" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fb220f46c53859a4b7ec083e41dec9778ff0b1851c0942b211edb89e0ccdc46" -dependencies = [ - "bytes", - "either", - "futures", -] - -[[package]] -name = "tokio-codec" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25b2998660ba0e70d18684de5d06b70b70a3a747469af9dea7618cc59e75976b" -dependencies = [ - "bytes", - "futures", - "tokio-io", -] - -[[package]] -name = "tokio-current-thread" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1de0e32a83f131e002238d7ccde18211c0a5397f60cbfffcb112868c2e0e20e" -dependencies = [ - "futures", - "tokio-executor", -] - -[[package]] -name = "tokio-executor" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb2d1b8f4548dbf5e1f7818512e9c406860678f29c300cdf0ebac72d1a3a1671" -dependencies = [ - "crossbeam-utils", - "futures", -] - -[[package]] -name = "tokio-fs" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "297a1206e0ca6302a0eed35b700d292b275256f596e2f3fea7729d5e629b6ff4" -dependencies = [ - "futures", - "tokio-io", - "tokio-threadpool", -] - -[[package]] -name = "tokio-io" -version = "0.1.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57fc868aae093479e3131e3d165c93b1c7474109d13c90ec0dda2a1bbfff0674" -dependencies = [ - "bytes", - "futures", - "log", -] - -[[package]] -name = "tokio-reactor" -version = "0.1.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09bc590ec4ba8ba87652da2068d150dcada2cfa2e07faae270a5e0409aa51351" -dependencies = [ - "crossbeam-utils", - "futures", - "lazy_static", - "log", - "mio", - "num_cpus", - "parking_lot 0.9.0", - "slab", - "tokio-executor", - "tokio-io", - "tokio-sync", -] - -[[package]] -name = "tokio-sync" -version = "0.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edfe50152bc8164fcc456dab7891fa9bf8beaf01c5ee7e1dd43a397c3cf87dee" -dependencies = [ - "fnv", - "futures", -] - -[[package]] -name = "tokio-tcp" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "98df18ed66e3b72e742f185882a9e201892407957e45fbff8da17ae7a7c51f72" -dependencies = [ - "bytes", - "futures", - "iovec", - "mio", - "tokio-io", - "tokio-reactor", -] - -[[package]] -name = "tokio-threadpool" -version = "0.1.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df720b6581784c118f0eb4310796b12b1d242a7eb95f716a8367855325c25f89" -dependencies = [ - "crossbeam-deque", - "crossbeam-queue", - "crossbeam-utils", - "futures", - "lazy_static", - "log", - "num_cpus", - "slab", - "tokio-executor", -] - -[[package]] -name = "tokio-timer" -version = "0.2.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93044f2d313c95ff1cb7809ce9a7a05735b012288a888b62d4434fd58c94f296" -dependencies = [ - "crossbeam-utils", - "futures", - "slab", - "tokio-executor", -] - -[[package]] -name = "tokio-udp" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2a0b10e610b39c38b031a2fcab08e4b82f16ece36504988dcbd81dbba650d82" -dependencies = [ - "bytes", - "futures", - "log", - "mio", - "tokio-codec", - "tokio-io", - "tokio-reactor", -] - -[[package]] -name = "tokio-uds" -version = "0.2.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab57a4ac4111c8c9dbcf70779f6fc8bc35ae4b2454809febac840ad19bd7e4e0" -dependencies = [ - "bytes", - "futures", - "iovec", - "libc", - "log", - "mio", - "mio-uds", - "tokio-codec", - "tokio-io", - "tokio-reactor", -] - -[[package]] -name = "try-lock" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642" - -[[package]] -name = "unicase" -version = "2.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50f37be617794602aabbeee0be4f259dc1778fabe05e2d67ee8f79326d5cb4f6" -dependencies = [ - "version_check 0.9.2", -] - -[[package]] -name = "unicode-xid" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" - -[[package]] -name = "unicode-xid" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564" - -[[package]] -name = "version_check" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "914b1a6776c4c929a602fafd8bc742e06365d4bcbe48c30f9cca5824f70dc9dd" - -[[package]] -name = "version_check" -version = "0.9.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5a972e5669d67ba988ce3dc826706fb0a8b01471c088cb0b6110b805cc36aed" - -[[package]] -name = "void" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" - -[[package]] -name = "want" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6395efa4784b027708f7451087e647ec73cc74f5d9bc2e418404248d679a230" -dependencies = [ - "futures", - "log", - "try-lock", -] - -[[package]] -name = "wasi" -version = "0.10.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f" - -[[package]] -name = "winapi" -version = "0.2.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" - -[[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-build" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" - -[[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.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" -dependencies = [ - "winapi 0.3.9", -] - -[[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 = "ws2_32-sys" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d59cefebd0c892fa2dd6de581e937301d8552cb44489cdff035c6187cb63fa5e" -dependencies = [ - "winapi 0.2.8", - "winapi-build", -] diff --git a/peach-web/src/common.rs b/peach-web/src/common.rs deleted file mode 100644 index b608500..0000000 --- a/peach-web/src/common.rs +++ /dev/null @@ -1,105 +0,0 @@ -//! This module contains core api functions shared by json_api.rs and by routes.rs -//! -//! These functions return Results which are then handled by the json api or the html routes -//! and turned into a rocket response appropriately. -use log::info; - -use crate::error::PeachWebError; -use crate::forms::{AddAdminForm, DnsForm, PasswordForm, ResetPasswordForm}; -use peach_lib::config_manager; -use peach_lib::dyndns_client; -use peach_lib::dyndns_client::{check_is_new_dyndns_domain, get_full_dynamic_domain}; -use peach_lib::error::PeachError; -use peach_lib::jsonrpc_client_core::{Error, ErrorKind}; -use peach_lib::jsonrpc_core::types::error::ErrorCode; -use peach_lib::password_utils; - -pub fn save_dns_configuration(dns_form: DnsForm) -> Result<(), PeachWebError> { - // first save local configurations - config_manager::set_external_domain(&dns_form.external_domain)?; - config_manager::set_dyndns_enabled_value(dns_form.enable_dyndns)?; - // if dynamic dns is enabled and this is a new domain name, then register it - if dns_form.enable_dyndns { - let full_dynamic_domain = get_full_dynamic_domain(&dns_form.dynamic_domain); - // check if this is a new domain or if its already registered - let is_new_domain = check_is_new_dyndns_domain(&full_dynamic_domain); - if is_new_domain { - match dyndns_client::register_domain(&full_dynamic_domain) { - Ok(_) => { - info!("Registered new dyndns domain"); - // successful update - Ok(()) - } - Err(err) => { - info!("Failed to register dyndns domain: {:?}", err); - // json response for failed update - let msg: String = match err { - PeachError::JsonRpcClientCore { source } => { - match source { - Error(ErrorKind::JsonRpcError(err), _state) => match err.code { - ErrorCode::ServerError(-32030) => { - format!("Error registering domain: {} was previously registered", full_dynamic_domain) - } - _ => { - format!("Failed to register dyndns domain {:?}", err) - } - }, - _ => { - format!("Failed to register dyndns domain: {:?}", source) - } - } - } - _ => "Failed to register dyndns domain".to_string(), - }; - Err(PeachWebError::FailedToRegisterDynDomain { msg }) - } - } - } - // if the domain is already registered, then dont re-register, and just return success - else { - Ok(()) - } - } else { - Ok(()) - } -} - -/// this function is for use by a user who is already logged in to change their password -pub fn save_password_form(password_form: PasswordForm) -> Result<(), PeachWebError> { - info!( - "change password!: {} {} {}", - password_form.old_password, password_form.new_password1, password_form.new_password2 - ); - password_utils::verify_password(&password_form.old_password)?; - // if the previous line did not throw an error, then the old password is correct - password_utils::validate_new_passwords( - &password_form.new_password1, - &password_form.new_password2, - )?; - // if the previous line did not throw an error, then the new password is valid - password_utils::set_new_password(&password_form.new_password1)?; - Ok(()) -} - -/// this function is publicly exposed for users who have forgotten their password -pub fn save_reset_password_form(password_form: ResetPasswordForm) -> Result<(), PeachWebError> { - info!( - "reset password!: {} {} {}", - password_form.temporary_password, password_form.new_password1, password_form.new_password2 - ); - password_utils::verify_temporary_password(&password_form.temporary_password)?; - // if the previous line did not throw an error, then the secret_link is correct - password_utils::validate_new_passwords( - &password_form.new_password1, - &password_form.new_password2, - )?; - // if the previous line did not throw an error, then the new password is valid - password_utils::set_new_password(&password_form.new_password1)?; - Ok(()) -} - -pub fn save_add_admin_form(admin_form: AddAdminForm) -> Result<(), PeachWebError> { - let _result = config_manager::add_ssb_admin_id(&admin_form.ssb_id)?; - // if the previous line didn't throw an error then it was a success - Ok(()) -} diff --git a/peach-web/src/context.rs b/peach-web/src/context.rs deleted file mode 100644 index 6bbeae5..0000000 --- a/peach-web/src/context.rs +++ /dev/null @@ -1,890 +0,0 @@ -//! Build context objects for inclusion in Tera templates. -//! -//! Each context object is represented by a struct which implements a build -//! method. Context objects provide the means by which application and device -//! state are made available for rendering in the templates. - -// Context object struct names: -// -// DeviceContext -// ErrorContext -// FlashContext -// HelpContext -// HomeContext -// LoginContext -// MessageContext -// NetworkContext -// NetworkAddContext -// NetworkAlertContext -// NetworkDetailContext -// NetworkListContext -// PeerContext -// ProfileContext -// ShutdownContext - -use std::collections::HashMap; - -use serde::Serialize; - -use peach_lib::config_manager::load_peach_config; -use peach_lib::dyndns_client; -use peach_lib::dyndns_client::{get_dyndns_subdomain, is_dns_updater_online}; -use peach_lib::network_client; -use peach_lib::network_client::{AccessPoint, Networks, Scan}; -use peach_lib::oled_client; -use peach_lib::sbot_client; -use peach_lib::stats_client; -use peach_lib::stats_client::{CpuStatPercentages, DiskUsage, LoadAverage, MemStat, Traffic}; - -use crate::monitor; -use crate::monitor::{Alert, Data, Threshold}; - -// used in /device for system statistics -#[derive(Debug, Serialize)] -pub struct DeviceContext { - pub back: Option, - pub cpu_stat_percent: Option, - pub disk_stats: Vec, - pub flash_name: Option, - pub flash_msg: Option, - pub load_average: Option, - pub mem_stats: Option, - pub network_ping: String, - pub oled_ping: String, - pub stats_ping: String, - pub dyndns_enabled: bool, - pub dyndns_is_online: bool, - pub config_is_valid: bool, - pub sbot_is_online: bool, - pub title: Option, - pub uptime: Option, -} - -impl DeviceContext { - pub fn build() -> DeviceContext { - // convert result to Option, discard any error - let cpu_stat_percent = stats_client::cpu_stats_percent().ok(); - let load_average = stats_client::load_average().ok(); - let mem_stats = stats_client::mem_stats().ok(); - let network_ping = match network_client::ping() { - Ok(_) => "ONLINE".to_string(), - Err(_) => "OFFLINE".to_string(), - }; - let oled_ping = match oled_client::ping() { - Ok(_) => "ONLINE".to_string(), - Err(_) => "OFFLINE".to_string(), - }; - let stats_ping = match stats_client::ping() { - Ok(_) => "ONLINE".to_string(), - Err(_) => "OFFLINE".to_string(), - }; - let uptime = match stats_client::uptime() { - Ok(mins) => mins, - Err(_) => "Unavailable".to_string(), - }; - - // serialize disk usage data into Vec - let disk_usage_stats = match stats_client::disk_usage() { - Ok(disks) => { - let partitions: Vec = serde_json::from_str(disks.as_str()) - .expect("Failed to deserialize disk_usage response"); - partitions - } - Err(_) => Vec::new(), - }; - - let mut disk_stats = Vec::new(); - // select only the partition we're interested in: /dev/mmcblk0p2 ("/") - for disk in disk_usage_stats { - if disk.mountpoint == "/" { - disk_stats.push(disk); - } - } - - // parse the uptime string to a signed integer (for math) - let uptime_parsed = uptime.parse::().ok(); - - // dyndns_is_online & config_is_valid - let dyndns_enabled: bool; - let dyndns_is_online: bool; - let config_is_valid: bool; - let load_peach_config_result = load_peach_config(); - match load_peach_config_result { - Ok(peach_config) => { - dyndns_enabled = peach_config.dyn_enabled; - config_is_valid = true; - if dyndns_enabled { - let is_dyndns_online_result = dyndns_client::is_dns_updater_online(); - match is_dyndns_online_result { - Ok(is_online) => { - dyndns_is_online = is_online; - } - Err(_err) => { - dyndns_is_online = false; - } - } - } else { - dyndns_is_online = false; - } - } - Err(_err) => { - dyndns_enabled = false; - dyndns_is_online = false; - config_is_valid = false; - } - } - - // test if go-sbot is running - let sbot_is_online: bool; - let sbot_is_online_result = sbot_client::is_sbot_online(); - match sbot_is_online_result { - Ok(val) => { - sbot_is_online = val; - } - Err(_err) => { - sbot_is_online = false; - } - } - - DeviceContext { - back: None, - cpu_stat_percent, - disk_stats, - flash_name: None, - flash_msg: None, - load_average, - mem_stats, - network_ping, - oled_ping, - stats_ping, - dyndns_enabled, - dyndns_is_online, - config_is_valid, - sbot_is_online, - title: None, - uptime: uptime_parsed, - } - } -} - -#[derive(Debug, Serialize)] -pub struct ErrorContext { - pub back: Option, - pub flash_name: Option, - pub flash_msg: Option, - pub title: Option, -} - -impl ErrorContext { - pub fn build() -> ErrorContext { - ErrorContext { - back: None, - flash_name: None, - flash_msg: None, - title: None, - } - } -} - -#[derive(Debug, Serialize)] -pub struct FlashContext { - pub flash_name: Option, - pub flash_msg: Option, -} - -#[derive(Debug, Serialize)] -pub struct HelpContext { - pub back: Option, - pub flash_name: Option, - pub flash_msg: Option, - pub title: Option, -} - -impl HelpContext { - pub fn build() -> HelpContext { - HelpContext { - back: None, - flash_name: None, - flash_msg: None, - title: None, - } - } -} - -#[derive(Debug, Serialize)] -pub struct HomeContext { - pub flash_name: Option, - pub flash_msg: Option, - pub title: Option, -} - -impl HomeContext { - pub fn build() -> HomeContext { - HomeContext { - flash_name: None, - flash_msg: None, - title: None, - } - } -} - -#[derive(Debug, Serialize)] -pub struct LoginContext { - pub back: Option, - pub flash_name: Option, - pub flash_msg: Option, - pub title: Option, -} - -impl LoginContext { - pub fn build() -> LoginContext { - LoginContext { - back: None, - flash_name: None, - flash_msg: None, - title: None, - } - } -} - -#[derive(Debug, Serialize)] -pub struct MessageContext { - pub back: Option, - pub flash_name: Option, - pub flash_msg: Option, - pub title: Option, -} - -impl MessageContext { - pub fn build() -> MessageContext { - MessageContext { - back: None, - flash_name: None, - flash_msg: None, - title: None, - } - } -} - -#[derive(Debug, Serialize)] -pub struct ConfigureDNSContext { - pub external_domain: String, - pub dyndns_subdomain: String, - pub enable_dyndns: bool, - pub is_dyndns_online: bool, - pub back: Option, - pub title: Option, - pub flash_name: Option, - pub flash_msg: Option, -} - -impl ConfigureDNSContext { - pub fn build() -> ConfigureDNSContext { - let peach_config = load_peach_config().unwrap(); - let dyndns_fulldomain = peach_config.dyn_domain; - let is_dyndns_online = is_dns_updater_online().unwrap(); - let dyndns_subdomain = - get_dyndns_subdomain(&dyndns_fulldomain).unwrap_or(dyndns_fulldomain); - ConfigureDNSContext { - external_domain: peach_config.external_domain, - dyndns_subdomain, - enable_dyndns: peach_config.dyn_enabled, - is_dyndns_online, - back: None, - title: None, - flash_name: None, - flash_msg: None, - } - } -} - -#[derive(Debug, Serialize)] -pub struct ChangePasswordContext { - pub back: Option, - pub title: Option, - pub flash_name: Option, - pub flash_msg: Option, -} - -impl ChangePasswordContext { - pub fn build() -> ChangePasswordContext { - ChangePasswordContext { - back: None, - title: None, - flash_name: None, - flash_msg: None, - } - } -} - -#[derive(Debug, Serialize)] -pub struct ConfigureAdminContext { - pub ssb_admin_ids: Vec, - pub back: Option, - pub title: Option, - pub flash_name: Option, - pub flash_msg: Option, -} - -impl ConfigureAdminContext { - pub fn build() -> ConfigureAdminContext { - let peach_config = load_peach_config().unwrap(); - let ssb_admin_ids = peach_config.ssb_admin_ids; - ConfigureAdminContext { - ssb_admin_ids, - back: None, - title: None, - flash_name: None, - flash_msg: None, - } - } -} - -#[derive(Debug, Serialize)] -pub struct AddAdminContext { - pub back: Option, - pub title: Option, - pub flash_name: Option, - pub flash_msg: Option, -} - -impl AddAdminContext { - pub fn build() -> AddAdminContext { - AddAdminContext { - back: None, - title: None, - flash_name: None, - flash_msg: None, - } - } -} - -#[derive(Debug, Serialize)] -pub struct ResetPasswordContext { - pub back: Option, - pub title: Option, - pub flash_name: Option, - pub flash_msg: Option, -} - -impl ResetPasswordContext { - pub fn build() -> ResetPasswordContext { - ResetPasswordContext { - back: None, - title: None, - flash_name: None, - flash_msg: None, - } - } -} - -#[derive(Debug, Serialize)] -pub struct SendPasswordResetContext { - pub back: Option, - pub title: Option, - pub flash_name: Option, - pub flash_msg: Option, -} - -impl SendPasswordResetContext { - pub fn build() -> SendPasswordResetContext { - SendPasswordResetContext { - back: None, - title: None, - flash_name: None, - flash_msg: None, - } - } -} - -#[derive(Debug, Serialize)] -pub struct NetworkContext { - pub ap_ip: String, - pub ap_ssid: String, - pub ap_state: String, - pub ap_traffic: Option, - pub wlan_ip: String, - pub wlan_rssi: Option, - pub wlan_scan: Option>, - pub wlan_ssid: String, - pub wlan_state: String, - pub wlan_status: String, - pub wlan_traffic: Option, - pub flash_name: Option, - pub flash_msg: Option, - // allows for passing in the ssid of a chosen access point - // this is used in the network_detail template - pub selected: Option, - // page title for header in navbar - pub title: Option, - // url for back-arrow link - pub back: Option, -} - -impl NetworkContext { - pub fn build() -> NetworkContext { - let ap_ip = match network_client::ip("ap0") { - Ok(ip) => ip, - Err(_) => "x.x.x.x".to_string(), - }; - let ap_ssid = match network_client::ssid("ap0") { - Ok(ssid) => ssid, - Err(_) => "Not currently activated".to_string(), - }; - let ap_state = match network_client::state("ap0") { - Ok(state) => state, - Err(_) => "Interface unavailable".to_string(), - }; - let ap_traffic = match network_client::traffic("ap0") { - Ok(traffic) => { - let mut t = traffic; - // modify traffic values & assign measurement unit - // based on received and transmitted values - // if received > 999 MB, convert it to GB - if t.received > 1_047_527_424 { - t.received /= 1_073_741_824; - t.rx_unit = Some("GB".to_string()); - } else if t.received > 0 { - // otherwise, convert it to MB - t.received = (t.received / 1024) / 1024; - t.rx_unit = Some("MB".to_string()); - } else { - t.received = 0; - t.rx_unit = Some("MB".to_string()); - } - - if t.transmitted > 1_047_527_424 { - t.transmitted /= 1_073_741_824; - t.tx_unit = Some("GB".to_string()); - } else if t.transmitted > 0 { - t.transmitted = (t.transmitted / 1024) / 1024; - t.tx_unit = Some("MB".to_string()); - } else { - t.transmitted = 0; - t.tx_unit = Some("MB".to_string()); - } - Some(t) - } - Err(_) => None, - }; - let wlan_ip = match network_client::ip("wlan0") { - Ok(ip) => ip, - Err(_) => "x.x.x.x".to_string(), - }; - let wlan_rssi = match network_client::rssi_percent("wlan0") { - Ok(rssi) => Some(rssi), - Err(_) => None, - }; - let wlan_scan = match network_client::available_networks("wlan0") { - Ok(networks) => { - let scan: Vec = serde_json::from_str(networks.as_str()) - .expect("Failed to deserialize scan_networks response"); - Some(scan) - } - Err(_) => None, - }; - let wlan_ssid = match network_client::ssid("wlan0") { - Ok(ssid) => ssid, - Err(_) => "Not connected".to_string(), - }; - let wlan_state = match network_client::state("wlan0") { - Ok(state) => state, - Err(_) => "Interface unavailable".to_string(), - }; - let wlan_status = match network_client::status("wlan0") { - Ok(status) => status, - Err(_) => "Interface unavailable".to_string(), - }; - let wlan_traffic = match network_client::traffic("wlan0") { - Ok(traffic) => { - let mut t = traffic; - // modify traffic values & assign measurement unit - // based on received and transmitted values - // if received > 999 MB, convert it to GB - if t.received > 1_047_527_424 { - t.received /= 1_073_741_824; - t.rx_unit = Some("GB".to_string()); - } else if t.received > 0 { - // otherwise, convert it to MB - t.received = (t.received / 1024) / 1024; - t.rx_unit = Some("MB".to_string()); - } else { - t.received = 0; - t.rx_unit = Some("MB".to_string()); - } - - if t.transmitted > 1_047_527_424 { - t.transmitted /= 1_073_741_824; - t.tx_unit = Some("GB".to_string()); - } else if t.transmitted > 0 { - t.transmitted = (t.transmitted / 1024) / 1024; - t.tx_unit = Some("MB".to_string()); - } else { - t.transmitted = 0; - t.tx_unit = Some("MB".to_string()); - } - Some(t) - } - Err(_) => None, - }; - - NetworkContext { - ap_ip, - ap_ssid, - ap_state, - ap_traffic, - wlan_ip, - wlan_rssi, - wlan_scan, - wlan_ssid, - wlan_state, - wlan_status, - wlan_traffic, - flash_name: None, - flash_msg: None, - selected: None, - title: None, - back: None, - } - } -} - -// used in /network/wifi/add? -#[derive(Debug, Serialize)] -pub struct NetworkAddContext { - pub back: Option, - pub flash_name: Option, - pub flash_msg: Option, - pub selected: Option, - pub title: Option, -} - -impl NetworkAddContext { - pub fn build() -> NetworkAddContext { - NetworkAddContext { - back: None, - flash_name: None, - flash_msg: None, - selected: None, - title: None, - } - } -} - -// used in /network/wifi/alert for traffic alerts -#[derive(Debug, Serialize)] -pub struct NetworkAlertContext { - pub alert: Alert, - pub back: Option, - pub data_total: Data, // combined stored and current wifi traffic in bytes - pub flash_name: Option, - pub flash_msg: Option, - pub threshold: Threshold, - pub title: Option, - pub traffic: Traffic, // current wifi traffic in bytes (since boot) -} - -impl NetworkAlertContext { - pub fn build() -> NetworkAlertContext { - let alert = monitor::get_alerts().unwrap(); - // stored wifi data values as bytes - let stored_traffic = monitor::get_data().unwrap(); - let threshold = monitor::get_thresholds().unwrap(); - // current wifi traffic values as bytes - let traffic = match network_client::traffic("wlan0") { - Ok(t) => t, - Err(_) => Traffic { - received: 0, - transmitted: 0, - rx_unit: None, - tx_unit: None, - }, - }; - - let current_traffic = traffic.received + traffic.transmitted; - let total = stored_traffic.total + current_traffic; - let data_total = Data { total }; - - NetworkAlertContext { - alert, - back: None, - data_total, - flash_name: None, - flash_msg: None, - threshold, - title: None, - traffic, - } - } -} - -#[derive(Debug, Serialize)] -pub struct NetworkDetailContext { - pub back: Option, - pub flash_name: Option, - pub flash_msg: Option, - pub saved_aps: Vec, - pub selected: Option, - pub title: Option, - pub wlan_ip: String, - pub wlan_networks: HashMap, - pub wlan_rssi: Option, - pub wlan_ssid: String, - pub wlan_state: String, - pub wlan_status: String, - pub wlan_traffic: Option, -} - -impl NetworkDetailContext { - pub fn build() -> NetworkDetailContext { - let wlan_ip = match network_client::ip("wlan0") { - Ok(ip) => ip, - Err(_) => "x.x.x.x".to_string(), - }; - // list of networks saved in wpa_supplicant.conf - let wlan_list = match network_client::saved_networks() { - Ok(ssids) => { - let networks: Vec = serde_json::from_str(ssids.as_str()) - .expect("Failed to deserialize scan_list response"); - networks - } - Err(_) => Vec::new(), - }; - // list of networks saved in wpa_supplicant.conf - // HACK: we're running the same function twice (wlan_list) - // see if we can implement clone for Vec instead - let saved_aps = match network_client::saved_networks() { - Ok(ssids) => { - let networks: Vec = serde_json::from_str(ssids.as_str()) - .expect("Failed to deserialize scan_list response"); - networks - } - Err(_) => Vec::new(), - }; - let wlan_rssi = match network_client::rssi_percent("wlan0") { - Ok(rssi) => Some(rssi), - Err(_) => None, - }; - // list of networks currently in range (online & accessible) - let wlan_scan = match network_client::available_networks("wlan0") { - Ok(networks) => { - let scan: Vec = serde_json::from_str(networks.as_str()) - .expect("Failed to deserialize scan_networks response"); - scan - } - Err(_) => Vec::new(), - }; - let wlan_ssid = match network_client::ssid("wlan0") { - Ok(ssid) => ssid, - Err(_) => "Not connected".to_string(), - }; - let wlan_state = match network_client::state("wlan0") { - Ok(state) => state, - Err(_) => "Interface unavailable".to_string(), - }; - let wlan_status = match network_client::status("wlan0") { - Ok(status) => status, - Err(_) => "Interface unavailable".to_string(), - }; - let wlan_traffic = match network_client::traffic("wlan0") { - Ok(traffic) => { - let mut t = traffic; - // modify traffic values & assign measurement unit - // based on received and transmitted values - // if received > 999 MB, convert it to GB - if t.received > 1_047_527_424 { - t.received /= 1_073_741_824; - t.rx_unit = Some("GB".to_string()); - } else if t.received > 0 { - // otherwise, convert it to MB - t.received = (t.received / 1024) / 1024; - t.rx_unit = Some("MB".to_string()); - } else { - t.received = 0; - t.rx_unit = Some("MB".to_string()); - } - - if t.transmitted > 1_047_527_424 { - t.transmitted /= 1_073_741_824; - t.tx_unit = Some("GB".to_string()); - } else if t.transmitted > 0 { - t.transmitted = (t.transmitted / 1024) / 1024; - t.tx_unit = Some("MB".to_string()); - } else { - t.transmitted = 0; - t.tx_unit = Some("MB".to_string()); - } - Some(t) - } - Err(_) => None, - }; - // create a hashmap to combine wlan_list & wlan_scan without repetition - let mut wlan_networks = HashMap::new(); - for ap in wlan_scan { - let ssid = ap.ssid.clone(); - let rssi = ap.signal_level.clone(); - // parse the string to a signed integer (for math) - let rssi_parsed = rssi.parse::().unwrap(); - // perform rssi (dBm) to quality (%) conversion - let quality_percent = 2 * (rssi_parsed + 100); - let ap_detail = AccessPoint { - detail: Some(ap), - state: "Available".to_string(), - signal: Some(quality_percent), - }; - wlan_networks.insert(ssid, ap_detail); - } - for network in wlan_list { - // avoid repetition by checking that ssid is not already in list - if !wlan_networks.contains_key(&network.ssid) { - let ssid = network.ssid.clone(); - let net_detail = AccessPoint { - detail: None, - state: "Not in range".to_string(), - signal: None, - }; - wlan_networks.insert(ssid, net_detail); - } - } - - NetworkDetailContext { - back: None, - flash_name: None, - flash_msg: None, - saved_aps, - selected: None, - title: None, - wlan_ip, - wlan_networks, - wlan_rssi, - wlan_ssid, - wlan_state, - wlan_status, - wlan_traffic, - } - } -} - -#[derive(Debug, Serialize)] -pub struct NetworkListContext { - pub ap_state: String, - pub back: Option, - pub flash_name: Option, - pub flash_msg: Option, - pub title: Option, - pub wlan_networks: HashMap, - pub wlan_ssid: String, -} - -impl NetworkListContext { - pub fn build() -> NetworkListContext { - // list of networks saved in the wpa_supplicant.conf - let wlan_list = match network_client::saved_networks() { - Ok(ssids) => { - let networks: Vec = serde_json::from_str(ssids.as_str()) - .expect("Failed to deserialize scan_list response"); - networks - } - Err(_) => Vec::new(), - }; - - // list of networks currently in range (online & accessible) - let wlan_scan = match network_client::available_networks("wlan0") { - Ok(networks) => { - let scan: Vec = serde_json::from_str(networks.as_str()) - .expect("Failed to deserialize scan_networks response"); - scan - } - Err(_) => Vec::new(), - }; - - let wlan_ssid = match network_client::ssid("wlan0") { - Ok(ssid) => ssid, - Err(_) => "Not connected".to_string(), - }; - - // create a hashmap to combine wlan_list & wlan_scan without repetition - let mut wlan_networks = HashMap::new(); - for ap in wlan_scan { - wlan_networks.insert(ap.ssid, "Available".to_string()); - } - for network in wlan_list { - // insert ssid (with state) only if it doesn't already exist - wlan_networks - .entry(network.ssid) - .or_insert_with(|| "Not in range".to_string()); - } - - let ap_state = match network_client::state("ap0") { - Ok(state) => state, - Err(_) => "Interface unavailable".to_string(), - }; - - NetworkListContext { - ap_state, - back: None, - flash_msg: None, - flash_name: None, - title: None, - wlan_networks, - wlan_ssid, - } - } -} - -#[derive(Debug, Serialize)] -pub struct PeerContext { - pub back: Option, - pub flash_name: Option, - pub flash_msg: Option, - pub title: Option, -} - -impl PeerContext { - pub fn build() -> PeerContext { - PeerContext { - back: None, - flash_name: None, - flash_msg: None, - title: None, - } - } -} - -#[derive(Debug, Serialize)] -pub struct ProfileContext { - pub back: Option, - pub flash_name: Option, - pub flash_msg: Option, - pub title: Option, -} - -impl ProfileContext { - pub fn build() -> ProfileContext { - ProfileContext { - back: None, - flash_name: None, - flash_msg: None, - title: None, - } - } -} - -#[derive(Debug, Serialize)] -pub struct ShutdownContext { - pub back: Option, - pub flash_name: Option, - pub flash_msg: Option, - pub title: Option, -} - -impl ShutdownContext { - pub fn build() -> ShutdownContext { - ShutdownContext { - back: None, - flash_name: None, - flash_msg: None, - title: None, - } - } -} diff --git a/peach-web/src/device.rs b/peach-web/src/device.rs deleted file mode 100644 index 5b715d9..0000000 --- a/peach-web/src/device.rs +++ /dev/null @@ -1,28 +0,0 @@ -//! System calls for modifying the state of the PeachCloud device. - -use std::io; -use std::process::{Command, Output}; - -use log::info; - -/// Executes a system command to reboot the device immediately. -pub fn reboot() -> io::Result { - info!("Rebooting the device"); - // ideally, we'd like to reboot after 5 seconds to allow time for JSON - // response but this is not possible with the `shutdown` command alone. - // TODO: send "rebooting..." message to `peach-oled` for display - Command::new("sudo") - .arg("shutdown") - .arg("-r") - .arg("now") - .output() -} - -/// Executes a system command to shutdown the device immediately. -pub fn shutdown() -> io::Result { - info!("Shutting down the device"); - // ideally, we'd like to reboot after 5 seconds to allow time for JSON - // response but this is not possible with the `shutdown` command alone. - // TODO: send "shutting down..." message to `peach-oled` for display - Command::new("sudo").arg("shutdown").arg("now").output() -} diff --git a/peach-web/src/error.rs b/peach-web/src/error.rs index e140586..a24d253 100644 --- a/peach-web/src/error.rs +++ b/peach-web/src/error.rs @@ -1,4 +1,4 @@ -//!! different types of PeachWebError +//! Custom error type representing all possible error variants for peach-web. use peach_lib::error::PeachError; use peach_lib::{serde_json, serde_yaml}; diff --git a/peach-web/src/forms.rs b/peach-web/src/forms.rs deleted file mode 100644 index 3983bb5..0000000 --- a/peach-web/src/forms.rs +++ /dev/null @@ -1,47 +0,0 @@ -//! Provides data structures which are used to parse forms from post requests. -//! -use rocket::request::FromForm; -use rocket::UriDisplayQuery; -use serde::Deserialize; - -#[derive(Debug, Deserialize, FromForm)] -pub struct DnsForm { - pub external_domain: String, - pub enable_dyndns: bool, - pub dynamic_domain: String, -} - -#[derive(Debug, Deserialize, FromForm)] -pub struct PasswordForm { - pub old_password: String, - pub new_password1: String, - pub new_password2: String, -} - -#[derive(Debug, Deserialize, FromForm)] -pub struct ResetPasswordForm { - pub temporary_password: String, - pub new_password1: String, - pub new_password2: String, -} - -#[derive(Debug, Deserialize, FromForm, UriDisplayQuery)] -pub struct Ssid { - pub ssid: String, -} - -#[derive(Debug, Deserialize, FromForm)] -pub struct WiFi { - pub ssid: String, - pub pass: String, -} - -#[derive(Debug, Deserialize, FromForm)] -pub struct AddAdminForm { - pub ssb_id: String, -} - -#[derive(Debug, Deserialize, FromForm)] -pub struct DeleteAdminForm { - pub ssb_id: String, -} diff --git a/peach-web/src/json_api.rs b/peach-web/src/json_api.rs deleted file mode 100644 index 54da07a..0000000 --- a/peach-web/src/json_api.rs +++ /dev/null @@ -1,539 +0,0 @@ -//! JSON API routes for PeachCloud. -//! -//! This module contains handlers which allow retrieval and modification of -//! device state via JSON. -//! -//! API ROUTES -//! -//! | Method | URL | Description | -//! | ------ | -------------------------------- | ----------------------------- | -//! | POST | /api/v1/device/reboot | Reboot device | -//! | POST | /api/v1/device/shutdown | Shutdown device | -//! | POST | /api/v1/network/activate_ap | | -//! | POST | /api/v1/network/activate_client | | -//! | GET | /api/v1/network/ip | | -//! | GET | /api/v1/network/rssi | | -//! | GET | /api/v1/network/ssid | | -//! | GET | /api/v1/network/state | | -//! | GET | /api/v1/network/status | | -//! | GET | /api/v1/network/wifi | Retrieve available networks | -//! | POST | /api/v1/network/wifi | Add WiFi AP credentials | -//! | POST | /api/v1/network/wifi/connect | Connect to WiFi access point | -//! | POST | /api/v1/network/wifi/disconnect | Disconnect WiFi access point | -//! | POST | /api/v1/network/wifi/forget | Forget / remove network | -//! | POST | /api/v1/network/wifi/modify | Modify network password | -//! | POST | /api/v1/network/wifi/usage | Update alert thresholds | -//! | POST | /api/v1/network/wifi/usage/reset | Reset stored data usage total | -//! | GET | /api/v1/ping | | -//! | GET | /api/v1/ping/network | Ping `peach-network` | -//! | GET | /api/v1/ping/oled | Ping `peach-oled` | -//! | GET | /api/v1/ping/stats | Ping `peach-stats` | -//! | POST | /api/v1/dns/configure | Modify dns configurations | -//! | POST | /api/v1/settings/change_password | Change password (logged in) | -//! | POST | /public/api/v1/reset_password | Change password (public) | - -use log::{debug, warn}; -use rocket::{get, post}; -use rocket_contrib::json; -use rocket_contrib::json::{Json, JsonValue}; -use serde::Serialize; - -use peach_lib::dyndns_client::is_dns_updater_online; -use peach_lib::network_client; -use peach_lib::oled_client; -use peach_lib::stats_client; -use peach_lib::stats_client::Traffic; - -use crate::common::{save_dns_configuration, save_password_form, save_reset_password_form}; -use crate::device; -use crate::forms::{DnsForm, PasswordForm, ResetPasswordForm, Ssid, WiFi}; -use crate::monitor; -use crate::monitor::Threshold; - -#[derive(Serialize)] -pub struct JsonResponse { - pub status: String, - #[serde(skip_serializing_if = "Option::is_none")] - pub data: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub msg: Option, -} - -// reboot the device -#[post("/api/v1/device/reboot")] -pub fn reboot_device() -> Json { - match device::reboot() { - Ok(_) => { - debug!("Going down for reboot..."); - let status = "success".to_string(); - let msg = "Going down for reboot.".to_string(); - Json(build_json_response(status, None, Some(msg))) - } - Err(_) => { - warn!("Reboot failed"); - let status = "error".to_string(); - let msg = "Failed to reboot the device.".to_string(); - Json(build_json_response(status, None, Some(msg))) - } - } -} - -// shutdown the device -#[post("/api/v1/device/shutdown")] -pub fn shutdown_device() -> Json { - match device::shutdown() { - Ok(_) => { - debug!("Going down for shutdown..."); - let status = "success".to_string(); - let msg = "Going down for shutdown.".to_string(); - Json(build_json_response(status, None, Some(msg))) - } - Err(_) => { - warn!("Shutdown failed"); - let status = "error".to_string(); - let msg = "Failed to shutdown the device.".to_string(); - Json(build_json_response(status, None, Some(msg))) - } - } -} - -#[post("/api/v1/network/activate_ap")] -pub fn activate_ap() -> Json { - // activate the wireless access point - debug!("Activating WiFi access point."); - match network_client::activate_ap() { - Ok(_) => { - let status = "success".to_string(); - Json(build_json_response(status, None, None)) - } - Err(_) => { - let status = "error".to_string(); - let msg = "Failed to activate WiFi access point.".to_string(); - Json(build_json_response(status, None, Some(msg))) - } - } -} - -#[post("/api/v1/network/activate_client")] -pub fn activate_client() -> Json { - // activate the wireless client - debug!("Activating WiFi client mode."); - match network_client::activate_client() { - Ok(_) => { - let status = "success".to_string(); - Json(build_json_response(status, None, None)) - } - Err(_) => { - let status = "error".to_string(); - let msg = "Failed to activate WiFi client mode.".to_string(); - Json(build_json_response(status, None, Some(msg))) - } - } -} - -#[get("/api/v1/network/ip")] -pub fn return_ip() -> Json { - // retrieve ip for wlan0 or set to x.x.x.x if not found - let wlan_ip = match network_client::ip("wlan0") { - Ok(ip) => ip, - Err(_) => "x.x.x.x".to_string(), - }; - // retrieve ip for ap0 or set to x.x.x.x if not found - let ap_ip = match network_client::ip("ap0") { - Ok(ip) => ip, - Err(_) => "x.x.x.x".to_string(), - }; - let data = json!({ - "wlan0": wlan_ip, - "ap0": ap_ip - }); - let status = "success".to_string(); - Json(build_json_response(status, Some(data), None)) -} - -#[get("/api/v1/network/rssi")] -pub fn return_rssi() -> Json { - // retrieve rssi for connected network - match network_client::rssi("wlan0") { - Ok(rssi) => { - let status = "success".to_string(); - let data = json!(rssi); - Json(build_json_response(status, Some(data), None)) - } - Err(_) => { - let status = "success".to_string(); - let msg = "Not currently connected to an access point.".to_string(); - Json(build_json_response(status, None, Some(msg))) - } - } -} - -#[get("/api/v1/network/ssid")] -pub fn return_ssid() -> Json { - // retrieve ssid for connected network - match network_client::ssid("wlan0") { - Ok(network) => { - let status = "success".to_string(); - let data = json!(network); - Json(build_json_response(status, Some(data), None)) - } - Err(_) => { - let status = "success".to_string(); - let msg = "Not currently connected to an access point.".to_string(); - Json(build_json_response(status, None, Some(msg))) - } - } -} - -#[get("/api/v1/network/state")] -pub fn return_state() -> Json { - // retrieve state of wlan0 or set to x.x.x.x if not found - let wlan_state = match network_client::state("wlan0") { - Ok(state) => state, - Err(_) => "unavailable".to_string(), - }; - // retrieve state for ap0 or set to x.x.x.x if not found - let ap_state = match network_client::state("ap0") { - Ok(state) => state, - Err(_) => "unavailable".to_string(), - }; - let data = json!({ - "wlan0": wlan_state, - "ap0": ap_state - }); - let status = "success".to_string(); - Json(build_json_response(status, Some(data), None)) -} - -#[get("/api/v1/network/status")] -pub fn return_status() -> Json { - // retrieve status info for wlan0 interface - match network_client::status("wlan0") { - Ok(network) => { - let status = "success".to_string(); - let data = json!(network); - Json(build_json_response(status, Some(data), None)) - } - Err(_) => { - let status = "success".to_string(); - let msg = "Not currently connected to an access point.".to_string(); - Json(build_json_response(status, None, Some(msg))) - } - } -} - -#[get("/api/v1/network/wifi")] -pub fn scan_networks() -> Json { - // retrieve scan results for access-points within range of wlan0 - match network_client::available_networks("wlan0") { - Ok(networks) => { - let status = "success".to_string(); - let data = json!(networks); - Json(build_json_response(status, Some(data), None)) - } - Err(_) => { - let status = "success".to_string(); - let msg = "Unable to scan for networks. Interface may be deactivated.".to_string(); - Json(build_json_response(status, None, Some(msg))) - } - } -} - -#[post("/api/v1/network/wifi", data = "")] -pub fn add_wifi(wifi: Json) -> Json { - // generate and write wifi config to wpa_supplicant - match network_client::add(&wifi.ssid, &wifi.pass) { - Ok(_) => { - debug!("Added WiFi credentials."); - // force reread of wpa_supplicant.conf file with new credentials - match network_client::reconfigure() { - Ok(_) => debug!("Successfully reconfigured wpa_supplicant."), - Err(_) => warn!("Failed to reconfigure wpa_supplicant."), - } - // json response for successful update - let status = "success".to_string(); - let msg = "WiFi credentials added.".to_string(); - Json(build_json_response(status, None, Some(msg))) - } - Err(_) => { - debug!("Failed to add WiFi credentials."); - // json response for failed update - let status = "error".to_string(); - let msg = "Failed to add WiFi credentials.".to_string(); - Json(build_json_response(status, None, Some(msg))) - } - } -} - -#[post("/api/v1/network/wifi/connect", data = "")] -pub fn connect_ap(ssid: Json) -> Json { - // retrieve the id for the given network ssid - match network_client::id("wlan0", &ssid.ssid) { - // attempt connection with the given network - Ok(id) => match network_client::connect(&id, "wlan0") { - Ok(_) => { - let status = "success".to_string(); - let msg = "Connected to chosen network.".to_string(); - Json(build_json_response(status, None, Some(msg))) - } - Err(_) => { - let status = "error".to_string(); - let msg = "Failed to connect to chosen network.".to_string(); - Json(build_json_response(status, None, Some(msg))) - } - }, - Err(_) => { - let status = "error".to_string(); - let msg = "Failed to retrieve the network ID.".to_string(); - Json(build_json_response(status, None, Some(msg))) - } - } -} - -#[post("/api/v1/network/wifi/disconnect", data = "")] -pub fn disconnect_ap(ssid: Json) -> Json { - // attempt to disable the current network for wlan0 interface - match network_client::disable("wlan0", &ssid.ssid) { - Ok(_) => { - let status = "success".to_string(); - let msg = "Disconnected from WiFi network.".to_string(); - Json(build_json_response(status, None, Some(msg))) - } - Err(_) => { - let status = "error".to_string(); - let msg = "Failed to disconnect from WiFi network.".to_string(); - Json(build_json_response(status, None, Some(msg))) - } - } -} - -#[post("/api/v1/network/wifi/forget", data = "")] -pub fn forget_ap(network: Json) -> Json { - let ssid = &network.ssid; - match network_client::forget("wlan0", ssid) { - Ok(_) => { - debug!("Removed WiFi credentials for chosen network."); - let status = "success".to_string(); - let msg = "WiFi network credentials removed.".to_string(); - Json(build_json_response(status, None, Some(msg))) - } - Err(_) => { - warn!("Failed to remove WiFi credentials."); - let status = "error".to_string(); - let msg = "Failed to remove WiFi network credentials.".to_string(); - Json(build_json_response(status, None, Some(msg))) - } - } -} - -#[post("/api/v1/network/wifi/modify", data = "")] -pub fn modify_password(wifi: Json) -> Json { - let ssid = &wifi.ssid; - let pass = &wifi.pass; - // we are using a helper function (`update`) to delete the old - // credentials and add the new ones. this is because the wpa_cli method - // for updating the password does not work. - match network_client::update("wlan0", ssid, pass) { - Ok(_) => { - debug!("WiFi password updated for chosen network."); - let status = "success".to_string(); - let msg = "WiFi password updated.".to_string(); - Json(build_json_response(status, None, Some(msg))) - } - Err(_) => { - warn!("Failed to update WiFi password."); - let status = "error".to_string(); - let msg = "Failed to update WiFi password.".to_string(); - Json(build_json_response(status, None, Some(msg))) - } - } -} - -#[post("/api/v1/network/wifi/usage", data = "")] -pub fn update_wifi_alerts(thresholds: Json) -> Json { - match monitor::update_store(thresholds.into_inner()) { - Ok(_) => { - debug!("WiFi data usage thresholds updated."); - let status = "success".to_string(); - let msg = "Updated alert threshold and flags.".to_string(); - Json(build_json_response(status, None, Some(msg))) - } - Err(_) => { - warn!("Failed to update WiFi data usage thresholds."); - let status = "error".to_string(); - let msg = "Failed to update WiFi data usage thresholds.".to_string(); - Json(build_json_response(status, None, Some(msg))) - } - } -} - -#[post("/api/v1/network/wifi/usage/reset")] -pub fn reset_data_total() -> Json { - match monitor::reset_data() { - Ok(_) => { - debug!("Reset network data usage total."); - let traffic = match network_client::traffic("wlan0") { - Ok(t) => t, - Err(_) => Traffic { - received: 0, - transmitted: 0, - rx_unit: None, - tx_unit: None, - }, - }; - // current wifi traffic values as bytes - let current_traffic = traffic.received + traffic.transmitted; - let data = json!(current_traffic); - let status = "success".to_string(); - let msg = "Reset network data usage total.".to_string(); - Json(build_json_response(status, Some(data), Some(msg))) - } - Err(_) => { - warn!("Failed to reset network data usage total."); - let status = "error".to_string(); - let msg = "Failed to reset network data usage total.".to_string(); - Json(build_json_response(status, None, Some(msg))) - } - } -} - -// status route: useful for checking connectivity from web client -#[get("/api/v1/ping")] -pub fn ping_pong() -> Json { - // ping pong - let status = "success".to_string(); - let msg = "pong!".to_string(); - Json(build_json_response(status, None, Some(msg))) -} - -// test route: useful for ad hoc testing -#[get("/api/v1/test")] -pub fn test_route() -> Json { - let val = is_dns_updater_online().unwrap(); - let status = "success".to_string(); - let msg = val.to_string(); - Json(build_json_response(status, None, Some(msg))) -} - -// status route: check availability of `peach-network` microservice -#[get("/api/v1/ping/network")] -pub fn ping_network() -> Json { - match network_client::ping() { - Ok(_) => { - debug!("peach-network responded successfully"); - let status = "success".to_string(); - let msg = "peach-network is available.".to_string(); - Json(build_json_response(status, None, Some(msg))) - } - Err(_) => { - warn!("peach-network failed to respond"); - let status = "error".to_string(); - let msg = "peach-network is unavailable.".to_string(); - Json(build_json_response(status, None, Some(msg))) - } - } -} - -// status route: check availability of `peach-oled` microservice -#[get("/api/v1/ping/oled")] -pub fn ping_oled() -> Json { - match oled_client::ping() { - Ok(_) => { - debug!("peach-oled responded successfully"); - let status = "success".to_string(); - let msg = "peach-oled is available.".to_string(); - Json(build_json_response(status, None, Some(msg))) - } - Err(_) => { - warn!("peach-oled failed to respond"); - let status = "error".to_string(); - let msg = "peach-oled is unavailable.".to_string(); - Json(build_json_response(status, None, Some(msg))) - } - } -} - -// status route: check availability of `peach-stats` microservice -#[get("/api/v1/ping/stats")] -pub fn ping_stats() -> Json { - match stats_client::ping() { - Ok(_) => { - debug!("peach-stats responded successfully"); - let status = "success".to_string(); - let msg = "peach-stats is available.".to_string(); - Json(build_json_response(status, None, Some(msg))) - } - Err(_) => { - warn!("peach-stats failed to respond"); - let status = "error".to_string(); - let msg = "peach-stats is unavailable.".to_string(); - Json(build_json_response(status, None, Some(msg))) - } - } -} - -#[post("/api/v1/dns/configure", data = "")] -pub fn save_dns_configuration_endpoint(dns_form: Json) -> Json { - let result = save_dns_configuration(dns_form.into_inner()); - match result { - Ok(_) => { - let status = "success".to_string(); - let msg = "New dynamic dns configuration is now enabled".to_string(); - Json(build_json_response(status, None, Some(msg))) - } - Err(err) => { - let status = "error".to_string(); - let msg = format!("{}", err); - Json(build_json_response(status, None, Some(msg))) - } - } -} - -#[post("/api/v1/settings/change_password", data = "")] -pub fn save_password_form_endpoint(password_form: Json) -> Json { - let result = save_password_form(password_form.into_inner()); - match result { - Ok(_) => { - let status = "success".to_string(); - let msg = "Your password was successfully changed".to_string(); - Json(build_json_response(status, None, Some(msg))) - } - Err(err) => { - let status = "error".to_string(); - let msg = format!("{}", err); - Json(build_json_response(status, None, Some(msg))) - } - } -} - -/// this reset password route is used by a user who is not logged in -/// and is specifically for users who have forgotten their password -/// all routes under /public/* are excluded from nginx basic auth via the nginx config -#[post("/public/api/v1/reset_password", data = "")] -pub fn reset_password_form_endpoint( - reset_password_form: Json, -) -> Json { - let result = save_reset_password_form(reset_password_form.into_inner()); - match result { - Ok(_) => { - let status = "success".to_string(); - let msg = "New password is now saved. Return home to login.".to_string(); - Json(build_json_response(status, None, Some(msg))) - } - Err(err) => { - let status = "error".to_string(); - let msg = format!("{}", err); - Json(build_json_response(status, None, Some(msg))) - } - } -} - -// HELPER FUNCTIONS - -pub fn build_json_response( - status: String, - data: Option, - msg: Option, -) -> JsonResponse { - JsonResponse { status, data, msg } -} diff --git a/peach-web/src/lib.rs b/peach-web/src/lib.rs index a9ec234..a692239 100644 --- a/peach-web/src/lib.rs +++ b/peach-web/src/lib.rs @@ -24,20 +24,12 @@ //! of the template to be rendered. #![feature(proc_macro_hygiene, decl_macro)] -// this is to ignore a clippy warning that suggests -// to replace code with the same code that is already there (possibly a bug) -#![allow(clippy::nonstandard_macro_braces)] -pub mod common; -pub mod context; -pub mod device; pub mod error; -pub mod forms; -pub mod json_api; -pub mod monitor; pub mod routes; #[cfg(test)] mod tests; +pub mod utils; mod ws; use std::{env, thread}; @@ -47,8 +39,16 @@ use log::{debug, error, info}; use rocket::{catchers, routes}; use rocket_contrib::templates::Template; -use crate::json_api::*; -use crate::routes::*; +use crate::routes::authentication::*; +use crate::routes::device::*; +use crate::routes::helpers::*; +use crate::routes::index::*; +use crate::routes::ping::*; +use crate::routes::scuttlebutt::*; + +use crate::routes::settings::admin::*; +use crate::routes::settings::dns::*; +use crate::routes::settings::network::*; use crate::ws::*; pub type BoxError = Box; diff --git a/peach-web/src/routes.rs b/peach-web/src/routes.rs deleted file mode 100644 index 53feb98..0000000 --- a/peach-web/src/routes.rs +++ /dev/null @@ -1,744 +0,0 @@ -//! Route handlers for PeachCloud web routes. -//! -//! This module contains handlers which serve templates and static assests, -//! generate flash messages, catch errors and handle redirects for PeachCloud. -//! -//! WEB ROUTES -//! -//! | Method | URL | Description | -//! | ------ | --------------------------- | --------------------------------- | -//! | GET | / | Home | -//! | GET | /device | Device statistics | -//! | GET | /device/reboot | Reboot device | -//! | GET | /device/shutdown | Shutdown device | -//! | GET | /help | Help and usage guidelines | -//! | GET | /login | Login form | -//! | POST | /login | Login form submission | -//! | POST | /logout | Logout authenticated user | -//! | GET | /network | Network overview | -//! | GET | /network/ap/activate | Activate WiFi access point mode | -//! | GET | /network/wifi | List of networks | -//! | GET | /network/wifi? | Details of single network | -//! | GET | /network/wifi/activate | Activate WiFi client mode | -//! | GET | /network/wifi/add | Add WiFi form | -//! | POST | /network/wifi/add | WiFi form submission | -//! | GET | /network/wifi/add? | Add WiFi form (SSID populated) | -//! | POST | /network/wifi/connect | Connect to WiFi access point | -//! | POST | /network/wifi/disconnect | Disconnect from WiFi access point | -//! | POST | /network/wifi/forget | Remove WiFi | -//! | GET | /network/wifi/modify? | Modify WiFi password form | -//! | POST | /network/wifi/modify | Modify network password | -//! | GET | /network/wifi/usage | WiFi data usage form | -//! | POST | /network/wifi/usage | WiFi data usage form submission | -//! | GET | /network/wifi/usage/reset | Reset stored data usage total | -//! | GET | /messages | Private Scuttlebutt messages | -//! | GET | /peers | Scuttlebutt peers overview | -//! | GET | /profile | Scuttlebutt user profile | -//! | GET | /shutdown | Shutdown menu | -//! | GET | /network/dns | View DNS configurations | -//! | POST | /network/dns | Modify DNS configurations | -//! | GET | /settings/change_password | View password settings form | -//! | POST | /settings/change_password | Change admin password | -//! | GET | /reset_password | Change password using temp pass | -//! | POST | /reset_password | Rhange password using temp pass | -//! | GET | /send_password_reset | Send new password reset link | -//! | POST | /send_password_reset | Send new password reset link | - -use std::path::{Path, PathBuf}; - -use log::{debug, info, warn}; -use percent_encoding::percent_decode; -use rocket::http::RawStr; -use rocket::request::{FlashMessage, Form}; -use rocket::response::{Flash, NamedFile, Redirect}; -use rocket::{catch, get, post, uri}; -use rocket_contrib::templates::Template; - -use peach_lib::config_manager; -use peach_lib::network_client; -use peach_lib::password_utils; - -use crate::common::{ - save_add_admin_form, save_dns_configuration, save_password_form, save_reset_password_form, -}; -use crate::context::{ - AddAdminContext, ChangePasswordContext, ConfigureAdminContext, ConfigureDNSContext, - DeviceContext, ErrorContext, HelpContext, HomeContext, LoginContext, MessageContext, - NetworkAddContext, NetworkAlertContext, NetworkContext, NetworkDetailContext, - NetworkListContext, PeerContext, ProfileContext, ResetPasswordContext, - SendPasswordResetContext, ShutdownContext, -}; -use crate::device; -use crate::forms::{ - AddAdminForm, DeleteAdminForm, DnsForm, PasswordForm, ResetPasswordForm, Ssid, WiFi, -}; -use crate::monitor; -use crate::monitor::Threshold; - -#[get("/")] -pub fn index() -> Template { - let context = HomeContext { - flash_name: None, - flash_msg: None, - title: None, - }; - Template::render("index", &context) -} - -#[get("/device")] -pub fn device_stats(flash: Option) -> Template { - // assign context through context_builder call - let mut context = DeviceContext::build(); - context.back = Some("/".to_string()); - context.title = Some("Device Status".to_string()); - // check to see if there is a flash message to display - if let Some(flash) = flash { - // add flash message contents to the context object - context.flash_name = Some(flash.name().to_string()); - context.flash_msg = Some(flash.msg().to_string()); - }; - // template_dir is set in Rocket.toml - Template::render("device", &context) -} - -#[get("/device/reboot")] -pub fn reboot_cmd() -> Flash { - match device::reboot() { - Ok(_) => Flash::success(Redirect::to("/shutdown"), "Rebooting the device"), - Err(_) => Flash::error(Redirect::to("/shutdown"), "Failed to reboot the device"), - } -} - -#[get("/device/shutdown")] -pub fn shutdown_cmd() -> Flash { - match device::shutdown() { - Ok(_) => Flash::success(Redirect::to("/shutdown"), "Shutting down the device"), - Err(_) => Flash::error(Redirect::to("/shutdown"), "Failed to shutdown the device"), - } -} - -#[get("/help")] -pub fn help(flash: Option) -> Template { - let mut context = HelpContext::build(); - context.back = Some("/".to_string()); - context.title = Some("Help".to_string()); - // check to see if there is a flash message to display - if let Some(flash) = flash { - // add flash message contents to the context object - context.flash_name = Some(flash.name().to_string()); - context.flash_msg = Some(flash.msg().to_string()); - }; - Template::render("help", &context) -} - -#[get("/login")] -pub fn login(flash: Option) -> Template { - let mut context = LoginContext::build(); - context.back = Some("/".to_string()); - context.title = Some("Login".to_string()); - // check to see if there is a flash message to display - if let Some(flash) = flash { - // add flash message contents to the context object - context.flash_name = Some(flash.name().to_string()); - context.flash_msg = Some(flash.msg().to_string()); - }; - Template::render("login", &context) -} - -#[post("/logout")] -pub fn logout() -> Flash { - // logout authenticated user - debug!("Attempting deauthentication of user."); - /* - match logout_user() { - Ok(_) => Flash::success(Redirect::to("/"), "Logout success"), - Err(_) => Flash::error( - Redirect::to("/"), - "Failed to logout", - ), - } - */ - Flash::success(Redirect::to("/"), "Logged out") -} - -#[get("/network")] -pub fn network_home(flash: Option) -> Template { - // assign context through context_builder call - let mut context = NetworkContext::build(); - // set back button (nav) url - context.back = Some("/".to_string()); - // set page title - context.title = Some("Network Configuration".to_string()); - // check to see if there is a flash message to display - if let Some(flash) = flash { - // add flash message contents to the context object - context.flash_name = Some(flash.name().to_string()); - context.flash_msg = Some(flash.msg().to_string()); - }; - // template_dir is set in Rocket.toml - Template::render("network_card", &context) -} - -#[get("/network/ap/activate")] -pub fn deploy_ap() -> Flash { - // activate the wireless access point - debug!("Activating WiFi access point."); - match network_client::activate_ap() { - Ok(_) => Flash::success(Redirect::to("/network"), "Activated WiFi access point"), - Err(_) => Flash::error( - Redirect::to("/network"), - "Failed to activate WiFi access point", - ), - } -} - -#[get("/network/wifi")] -pub fn wifi_list(flash: Option) -> Template { - // assign context through context_builder call - let mut context = NetworkListContext::build(); - context.back = Some("/network".to_string()); - context.title = Some("WiFi Networks".to_string()); - // check to see if there is a flash message to display - if let Some(flash) = flash { - // add flash message contents to the context object - context.flash_name = Some(flash.name().to_string()); - context.flash_msg = Some(flash.msg().to_string()); - }; - // template_dir is set in Rocket.toml - Template::render("network_list", &context) -} - -#[get("/network/wifi?")] -pub fn network_detail(ssid: &RawStr, flash: Option) -> Template { - // assign context through context_builder call - let mut context = NetworkDetailContext::build(); - context.back = Some("/network/wifi".to_string()); - context.title = Some("WiFi Network".to_string()); - // decode ssid from url - let decoded_ssid = percent_decode(ssid.as_bytes()).decode_utf8().unwrap(); - context.selected = Some(decoded_ssid.to_string()); - // check to see if there is a flash message to display - if let Some(flash) = flash { - // add flash message contents to the context object - context.flash_name = Some(flash.name().to_string()); - context.flash_msg = Some(flash.msg().to_string()); - }; - // template_dir is set in Rocket.toml - Template::render("network_detail", &context) -} - -#[get("/network/wifi/activate")] -pub fn deploy_client() -> Flash { - // activate the wireless client - debug!("Activating WiFi client mode."); - match network_client::activate_client() { - Ok(_) => Flash::success(Redirect::to("/network"), "Activated WiFi client"), - Err(_) => Flash::error(Redirect::to("/network"), "Failed to activate WiFi client"), - } -} - -#[get("/network/wifi/add")] -pub fn network_add_wifi(flash: Option) -> Template { - let mut context = NetworkContext::build(); - // set back icon link to network route - context.back = Some("/network".to_string()); - context.title = Some("Add WiFi Network".to_string()); - // check to see if there is a flash message to display - if let Some(flash) = flash { - // add flash message contents to the context object - context.flash_name = Some(flash.name().to_string()); - context.flash_msg = Some(flash.msg().to_string()); - }; - // template_dir is set in Rocket.toml - Template::render("network_add", &context) -} - -#[get("/network/wifi/add?")] -pub fn network_add_ssid(ssid: &RawStr, flash: Option) -> Template { - // decode ssid from url - let decoded_ssid = percent_decode(ssid.as_bytes()).decode_utf8().unwrap(); - let mut context = NetworkAddContext::build(); - context.back = Some("/network/wifi".to_string()); - context.selected = Some(decoded_ssid.to_string()); - context.title = Some("Add WiFi Network".to_string()); - // check to see if there is a flash message to display - if let Some(flash) = flash { - // add flash message contents to the context object - context.flash_name = Some(flash.name().to_string()); - context.flash_msg = Some(flash.msg().to_string()); - }; - // template_dir is set in Rocket.toml - Template::render("network_add", &context) -} - -#[post("/network/wifi/add", data = "")] -pub fn add_credentials(wifi: Form) -> Template { - // check if the credentials already exist for this access point - // note: this is nicer but it's an unstable feature: - // if check_saved_aps(&wifi.ssid).contains(true) - // use unwrap_or instead, set value to false if err is returned - let creds_exist = network_client::saved_ap(&wifi.ssid).unwrap_or(false); - if creds_exist { - let mut context = NetworkAddContext::build(); - context.back = Some("/network".to_string()); - context.flash_name = Some("error".to_string()); - context.flash_msg = - Some("Network credentials already exist for this access point".to_string()); - context.title = Some("Add WiFi Network".to_string()); - // return early from handler with "creds already exist" message - return Template::render("network_add", &context); - }; - - // if credentials not found, generate and write wifi config to wpa_supplicant - match network_client::add(&wifi.ssid, &wifi.pass) { - Ok(_) => { - debug!("Added WiFi credentials."); - // force reread of wpa_supplicant.conf file with new credentials - match network_client::reconfigure() { - Ok(_) => debug!("Successfully reconfigured wpa_supplicant"), - Err(_) => warn!("Failed to reconfigure wpa_supplicant"), - } - let mut context = NetworkAddContext::build(); - context.back = Some("/network".to_string()); - context.flash_name = Some("success".to_string()); - context.flash_msg = Some("Added WiFi credentials".to_string()); - context.title = Some("Add WiFi Network".to_string()); - Template::render("network_add", &context) - } - Err(_) => { - debug!("Failed to add WiFi credentials."); - let mut context = NetworkAddContext::build(); - context.back = Some("/network".to_string()); - context.flash_name = Some("error".to_string()); - context.flash_msg = Some("Failed to add WiFi credentials".to_string()); - context.title = Some("Add WiFi Network".to_string()); - Template::render("network_add", &context) - } - } -} - -#[get("/network/wifi/usage")] -pub fn wifi_usage(flash: Option) -> Template { - let mut context = NetworkAlertContext::build(); - // set back icon link to network route - context.back = Some("/network".to_string()); - context.title = Some("Network Data Usage".to_string()); - // check to see if there is a flash message to display - if let Some(flash) = flash { - // add flash message contents to the context object - context.flash_name = Some(flash.name().to_string()); - context.flash_msg = Some(flash.msg().to_string()); - }; - // template_dir is set in Rocket.toml - Template::render("network_usage", &context) -} - -#[post("/network/wifi/usage", data = "")] -pub fn wifi_usage_alerts(thresholds: Form) -> Flash { - match monitor::update_store(thresholds.into_inner()) { - Ok(_) => { - debug!("WiFi data usage thresholds updated."); - Flash::success( - Redirect::to("/network/wifi/usage"), - "Updated alert thresholds and flags", - ) - } - Err(_) => { - warn!("Failed to update WiFi data usage thresholds."); - Flash::error( - Redirect::to("/network/wifi/usage"), - "Failed to update alert thresholds and flags", - ) - } - } -} - -#[get("/network/dns")] -pub fn configure_dns(flash: Option) -> Template { - let mut context = ConfigureDNSContext::build(); - // set back icon link to network route - context.back = Some("/network".to_string()); - context.title = Some("Configure DNS".to_string()); - // check to see if there is a flash message to display - if let Some(flash) = flash { - // add flash message contents to the context object - context.flash_name = Some(flash.name().to_string()); - context.flash_msg = Some(flash.msg().to_string()); - }; - Template::render("configure_dns", &context) -} - -#[post("/network/dns", data = "")] -pub fn configure_dns_post(dns: Form) -> Template { - let result = save_dns_configuration(dns.into_inner()); - match result { - Ok(_) => { - let mut context = ConfigureDNSContext::build(); - // set back icon link to network route - context.back = Some("/network".to_string()); - context.title = Some("Configure DNS".to_string()); - context.flash_name = Some("success".to_string()); - context.flash_msg = Some("New dynamic dns configuration is now enabled".to_string()); - Template::render("configure_dns", &context) - } - Err(err) => { - let mut context = ConfigureDNSContext::build(); - // set back icon link to network route - context.back = Some("/network".to_string()); - context.title = Some("Configure DNS".to_string()); - context.flash_name = Some("error".to_string()); - context.flash_msg = Some(format!("Failed to save dns configurations: {}", err)); - Template::render("configure_dns", &context) - } - } -} - -/// this change password route is used by a user who is already logged in -#[get("/settings/change_password")] -pub fn change_password(flash: Option) -> Template { - let mut context = ChangePasswordContext::build(); - // set back icon link to network route - context.back = Some("/network".to_string()); - context.title = Some("Change Password".to_string()); - // check to see if there is a flash message to display - if let Some(flash) = flash { - // add flash message contents to the context object - context.flash_name = Some(flash.name().to_string()); - context.flash_msg = Some(flash.msg().to_string()); - }; - Template::render("password/change_password", &context) -} - -/// this change password route is used by a user who is already logged in -#[post("/settings/change_password", data = "")] -pub fn change_password_post(password_form: Form) -> Template { - let result = save_password_form(password_form.into_inner()); - match result { - Ok(_) => { - let mut context = ChangePasswordContext::build(); - // set back icon link to network route - context.back = Some("/network".to_string()); - context.title = Some("Change Password".to_string()); - context.flash_name = Some("success".to_string()); - context.flash_msg = Some("New password is now saved".to_string()); - // template_dir is set in Rocket.toml - Template::render("password/change_password", &context) - } - Err(err) => { - let mut context = ChangePasswordContext::build(); - // set back icon link to network route - context.back = Some("/network".to_string()); - context.title = Some("Configure DNS".to_string()); - context.flash_name = Some("error".to_string()); - context.flash_msg = Some(format!("Failed to save new password: {}", err)); - Template::render("password/change_password", &context) - } - } -} - -/// this reset password route is used by a user who is not logged in -/// and is specifically for users who have forgotten their password -/// all routes under /public/* are excluded from nginx basic auth via the nginx config -#[get("/reset_password")] -pub fn reset_password(flash: Option) -> Template { - let mut context = ResetPasswordContext::build(); - context.back = Some("/".to_string()); - context.title = Some("Reset Password".to_string()); - // check to see if there is a flash message to display - if let Some(flash) = flash { - // add flash message contents to the context object - context.flash_name = Some(flash.name().to_string()); - context.flash_msg = Some(flash.msg().to_string()); - }; - Template::render("password/reset_password", &context) -} - -/// this reset password route is used by a user who is not logged in -/// and is specifically for users who have forgotten their password -/// and is excluded from nginx basic auth via the nginx config -#[post("/reset_password", data = "")] -pub fn reset_password_post(reset_password_form: Form) -> Template { - let result = save_reset_password_form(reset_password_form.into_inner()); - match result { - Ok(_) => { - let mut context = ChangePasswordContext::build(); - context.back = Some("/".to_string()); - context.title = Some("Reset Password".to_string()); - context.flash_name = Some("success".to_string()); - let flash_msg = "New password is now saved. Return home to login".to_string(); - context.flash_msg = Some(flash_msg); - Template::render("password/reset_password", &context) - } - Err(err) => { - let mut context = ChangePasswordContext::build(); - // set back icon link to network route - context.back = Some("/".to_string()); - context.title = Some("Reset Password".to_string()); - context.flash_name = Some("error".to_string()); - context.flash_msg = Some(format!("Failed to reset password: {}", err)); - Template::render("password/reset_password", &context) - } - } -} - -/// this route is used by a user who is not logged in to send a new password reset link -#[get("/send_password_reset")] -pub fn send_password_reset_page(flash: Option) -> Template { - let mut context = SendPasswordResetContext::build(); - context.back = Some("/".to_string()); - context.title = Some("Send Password Reset".to_string()); - // check to see if there is a flash message to display - if let Some(flash) = flash { - // add flash message contents to the context object - context.flash_name = Some(flash.name().to_string()); - context.flash_msg = Some(flash.msg().to_string()); - }; - Template::render("password/send_password_reset", &context) -} - -/// this send_password_reset route is used by a user who is not logged in -/// and is specifically for users who have forgotten their password -#[post("/send_password_reset")] -pub fn send_password_reset_post() -> Template { - info!("++ send password reset post"); - let result = password_utils::send_password_reset(); - match result { - Ok(_) => { - let mut context = ChangePasswordContext::build(); - context.back = Some("/".to_string()); - context.title = Some("Send Password Reset".to_string()); - context.flash_name = Some("success".to_string()); - let flash_msg = - "A password reset link has been sent to the admin of this device".to_string(); - context.flash_msg = Some(flash_msg); - Template::render("password/send_password_reset", &context) - } - Err(err) => { - let mut context = ChangePasswordContext::build(); - context.back = Some("/".to_string()); - context.title = Some("Send Password Reset".to_string()); - context.flash_name = Some("error".to_string()); - context.flash_msg = Some(format!("Failed to send password reset link: {}", err)); - Template::render("password/send_password_reset", &context) - } - } -} - -/// this is a route for viewing and deleting currently configured admin -#[get("/settings/configure_admin")] -pub fn configure_admin(flash: Option) -> Template { - let mut context = ConfigureAdminContext::build(); - // set back icon link to network route - context.back = Some("/network".to_string()); - context.title = Some("Configure Admin".to_string()); - // check to see if there is a flash message to display - if let Some(flash) = flash { - // add flash message contents to the context object - context.flash_name = Some(flash.name().to_string()); - context.flash_msg = Some(flash.msg().to_string()); - }; - Template::render("admin/configure_admin", &context) -} - -#[get("/settings/admin/add")] -pub fn add_admin(flash: Option) -> Template { - let mut context = AddAdminContext::build(); - context.back = Some("/settings/configure_admin".to_string()); - context.title = Some("Add Admin".to_string()); - // check to see if there is a flash message to display - if let Some(flash) = flash { - // add flash message contents to the context object - context.flash_name = Some(flash.name().to_string()); - context.flash_msg = Some(flash.msg().to_string()); - }; - // template_dir is set in Rocket.toml - Template::render("admin/add_admin", &context) -} - -#[post("/settings/admin/add", data = "")] -pub fn add_admin_post(add_admin_form: Form) -> Flash { - let result = save_add_admin_form(add_admin_form.into_inner()); - let url = uri!(configure_admin); - match result { - Ok(_) => Flash::success(Redirect::to(url), "Successfully added new admin"), - Err(_) => Flash::error(Redirect::to(url), "Failed to add new admin"), - } -} - -#[post("/settings/admin/delete", data = "")] -pub fn delete_admin_post(delete_admin_form: Form) -> Flash { - let result = config_manager::delete_ssb_admin_id(&delete_admin_form.ssb_id); - let url = uri!(configure_admin); - match result { - Ok(_) => Flash::success(Redirect::to(url), "Successfully removed admin id"), - Err(_) => Flash::error(Redirect::to(url), "Failed to remove admin id"), - } -} - -#[get("/network/wifi/usage/reset")] -pub fn wifi_usage_reset() -> Flash { - let url = uri!(wifi_usage); - match monitor::reset_data() { - Ok(_) => Flash::success(Redirect::to(url), "Reset stored network traffic total"), - Err(_) => Flash::error( - Redirect::to(url), - "Failed to reset stored network traffic total", - ), - } -} - -#[post("/network/wifi/connect", data = "")] -pub fn connect_wifi(network: Form) -> Flash { - let ssid = &network.ssid; - let url = uri!(network_detail: ssid); - match network_client::id("wlan0", ssid) { - Ok(id) => match network_client::connect(&id, "wlan0") { - Ok(_) => Flash::success(Redirect::to(url), "Connected to chosen network"), - Err(_) => Flash::error(Redirect::to(url), "Failed to connect to chosen network"), - }, - Err(_) => Flash::error(Redirect::to(url), "Failed to retrieve the network ID"), - } -} - -#[post("/network/wifi/disconnect", data = "")] -pub fn disconnect_wifi(network: Form) -> Flash { - let ssid = &network.ssid; - let url = uri!(network_home); - match network_client::disable("wlan0", ssid) { - Ok(_) => Flash::success(Redirect::to(url), "Disconnected from WiFi network"), - Err(_) => Flash::error(Redirect::to(url), "Failed to disconnect from WiFi network"), - } -} - -#[post("/network/wifi/forget", data = "")] -pub fn forget_wifi(network: Form) -> Flash { - let ssid = &network.ssid; - let url = uri!(network_home); - match network_client::forget("wlan0", ssid) { - Ok(_) => Flash::success(Redirect::to(url), "WiFi credentials removed"), - Err(_) => Flash::error( - Redirect::to(url), - "Failed to remove WiFi credentials".to_string(), - ), - } -} - -#[get("/network/wifi/modify?")] -pub fn wifi_password(ssid: &RawStr, flash: Option) -> Template { - // decode ssid from url - let decoded_ssid = percent_decode(ssid.as_bytes()).decode_utf8().unwrap(); - let mut context = NetworkAddContext { - back: Some("/network/wifi".to_string()), - flash_name: None, - flash_msg: None, - selected: Some(decoded_ssid.to_string()), - title: Some("Update WiFi Password".to_string()), - }; - // check to see if there is a flash message to display - if let Some(flash) = flash { - // add flash message contents to the context object - context.flash_name = Some(flash.name().to_string()); - context.flash_msg = Some(flash.msg().to_string()); - }; - // template_dir is set in Rocket.toml - Template::render("network_modify", &context) -} - -#[post("/network/wifi/modify", data = "")] -pub fn wifi_set_password(wifi: Form) -> Flash { - let ssid = &wifi.ssid; - let pass = &wifi.pass; - let url = uri!(network_detail: ssid); - match network_client::update("wlan0", ssid, pass) { - Ok(_) => Flash::success(Redirect::to(url), "WiFi password updated".to_string()), - Err(_) => Flash::error( - Redirect::to(url), - "Failed to update WiFi password".to_string(), - ), - } -} - -#[get("/messages")] -pub fn messages(flash: Option) -> Template { - let mut context = MessageContext::build(); - context.back = Some("/".to_string()); - context.title = Some("Private Messages".to_string()); - // check to see if there is a flash message to display - if let Some(flash) = flash { - // add flash message contents to the context object - context.flash_name = Some(flash.name().to_string()); - context.flash_msg = Some(flash.msg().to_string()); - }; - Template::render("messages", &context) -} - -#[get("/peers")] -pub fn peers(flash: Option) -> Template { - let mut context = PeerContext::build(); - context.back = Some("/".to_string()); - context.title = Some("Scuttlebutt Peers".to_string()); - // check to see if there is a flash message to display - if let Some(flash) = flash { - // add flash message contents to the context object - context.flash_name = Some(flash.name().to_string()); - context.flash_msg = Some(flash.msg().to_string()); - }; - Template::render("peers", &context) -} - -#[get("/profile")] -pub fn profile(flash: Option) -> Template { - let mut context = ProfileContext::build(); - context.back = Some("/".to_string()); - context.title = Some("Profile".to_string()); - // check to see if there is a flash message to display - if let Some(flash) = flash { - // add flash message contents to the context object - context.flash_name = Some(flash.name().to_string()); - context.flash_msg = Some(flash.msg().to_string()); - }; - Template::render("profile", &context) -} - -#[get("/shutdown")] -pub fn shutdown_menu(flash: Option) -> Template { - let mut context = ShutdownContext::build(); - context.back = Some("/".to_string()); - context.title = Some("Shutdown Device".to_string()); - // check to see if there is a flash message to display - if let Some(flash) = flash { - // add flash message contents to the context object - context.flash_name = Some(flash.name().to_string()); - context.flash_msg = Some(flash.msg().to_string()); - }; - Template::render("shutdown", &context) -} - -#[get("/", rank = 2)] -pub fn files(file: PathBuf) -> Option { - NamedFile::open(Path::new("static/").join(file)).ok() -} - -#[catch(404)] -pub fn not_found() -> Template { - debug!("404 Page Not Found"); - let mut context = ErrorContext::build(); - context.back = Some("/".to_string()); - context.title = Some("404: Page Not Found".to_string()); - context.flash_name = Some("error".to_string()); - context.flash_msg = Some("No resource found for given URL".to_string()); - - Template::render("not_found", context) -} - -#[catch(500)] -pub fn internal_error() -> Template { - debug!("500 Internal Server Error"); - let mut context = ErrorContext::build(); - context.back = Some("/".to_string()); - context.title = Some("500: Internal Server Error".to_string()); - context.flash_name = Some("error".to_string()); - context.flash_msg = Some("Internal server error".to_string()); - - Template::render("internal_error", context) -} diff --git a/peach-web/src/routes/authentication.rs b/peach-web/src/routes/authentication.rs new file mode 100644 index 0000000..3e59d9c --- /dev/null +++ b/peach-web/src/routes/authentication.rs @@ -0,0 +1,347 @@ +use log::{debug, info}; +use rocket::request::{FlashMessage, Form, FromForm}; +use rocket::response::{Flash, Redirect}; +use rocket::{get, post}; +use rocket_contrib::{json::Json, templates::Template}; +use serde::{Deserialize, Serialize}; + +use peach_lib::password_utils; + +use crate::error::PeachWebError; +use crate::utils::{build_json_response, JsonResponse}; + +// HELPERS AND ROUTES FOR /login + +#[derive(Debug, Serialize)] +pub struct LoginContext { + pub back: Option, + pub flash_name: Option, + pub flash_msg: Option, + pub title: Option, +} + +impl LoginContext { + pub fn build() -> LoginContext { + LoginContext { + back: None, + flash_name: None, + flash_msg: None, + title: None, + } + } +} + +#[get("/login")] +pub fn login(flash: Option) -> Template { + let mut context = LoginContext::build(); + context.back = Some("/".to_string()); + context.title = Some("Login".to_string()); + // check to see if there is a flash message to display + if let Some(flash) = flash { + // add flash message contents to the context object + context.flash_name = Some(flash.name().to_string()); + context.flash_msg = Some(flash.msg().to_string()); + }; + Template::render("login", &context) +} + +// HELPERS AND ROUTES FOR /logout + +#[post("/logout")] +pub fn logout() -> Flash { + // logout authenticated user + debug!("Attempting deauthentication of user."); + /* + match logout_user() { + Ok(_) => Flash::success(Redirect::to("/"), "Logout success"), + Err(_) => Flash::error( + Redirect::to("/"), + "Failed to logout", + ), + } + */ + Flash::success(Redirect::to("/"), "Logged out") +} + +// HELPERS AND ROUTES FOR /reset_password + +#[derive(Debug, Deserialize, FromForm)] +pub struct ResetPasswordForm { + pub temporary_password: String, + pub new_password1: String, + pub new_password2: String, +} + +#[derive(Debug, Serialize)] +pub struct ResetPasswordContext { + pub back: Option, + pub title: Option, + pub flash_name: Option, + pub flash_msg: Option, +} + +impl ResetPasswordContext { + pub fn build() -> ResetPasswordContext { + ResetPasswordContext { + back: None, + title: None, + flash_name: None, + flash_msg: None, + } + } +} + +#[derive(Debug, Serialize)] +pub struct ChangePasswordContext { + pub back: Option, + pub title: Option, + pub flash_name: Option, + pub flash_msg: Option, +} + +impl ChangePasswordContext { + pub fn build() -> ChangePasswordContext { + ChangePasswordContext { + back: None, + title: None, + flash_name: None, + flash_msg: None, + } + } +} + +/// Verify, validate and save the submitted password. This function is publicly exposed for users who have forgotten their password. +pub fn save_reset_password_form(password_form: ResetPasswordForm) -> Result<(), PeachWebError> { + info!( + "reset password!: {} {} {}", + password_form.temporary_password, password_form.new_password1, password_form.new_password2 + ); + password_utils::verify_temporary_password(&password_form.temporary_password)?; + // if the previous line did not throw an error, then the secret_link is correct + password_utils::validate_new_passwords( + &password_form.new_password1, + &password_form.new_password2, + )?; + // if the previous line did not throw an error, then the new password is valid + password_utils::set_new_password(&password_form.new_password1)?; + Ok(()) +} + +/// Password reset request handler. This route is used by a user who is not logged in +/// and is specifically for users who have forgotten their password. +/// All routes under /public/* are excluded from nginx basic auth via the nginx config. +#[get("/reset_password")] +pub fn reset_password(flash: Option) -> Template { + let mut context = ResetPasswordContext::build(); + context.back = Some("/".to_string()); + context.title = Some("Reset Password".to_string()); + // check to see if there is a flash message to display + if let Some(flash) = flash { + // add flash message contents to the context object + context.flash_name = Some(flash.name().to_string()); + context.flash_msg = Some(flash.msg().to_string()); + }; + Template::render("password/reset_password", &context) +} + +/// Password reset form request handler. This route is used by a user who is not logged in +/// and is specifically for users who have forgotten their password. +/// This route is excluded from nginx basic auth via the nginx config. +#[post("/reset_password", data = "")] +pub fn reset_password_post(reset_password_form: Form) -> Template { + let result = save_reset_password_form(reset_password_form.into_inner()); + match result { + Ok(_) => { + let mut context = ChangePasswordContext::build(); + context.back = Some("/".to_string()); + context.title = Some("Reset Password".to_string()); + context.flash_name = Some("success".to_string()); + let flash_msg = "New password is now saved. Return home to login".to_string(); + context.flash_msg = Some(flash_msg); + Template::render("password/reset_password", &context) + } + Err(err) => { + let mut context = ChangePasswordContext::build(); + // set back icon link to network route + context.back = Some("/".to_string()); + context.title = Some("Reset Password".to_string()); + context.flash_name = Some("error".to_string()); + context.flash_msg = Some(format!("Failed to reset password: {}", err)); + Template::render("password/reset_password", &context) + } + } +} + +/// JSON password reset form request handler. This route is used by a user who is not logged in +/// and is specifically for users who have forgotten their password. +/// All routes under /public/* are excluded from nginx basic auth via the nginx config. +#[post("/public/api/v1/reset_password", data = "")] +pub fn reset_password_form_endpoint( + reset_password_form: Json, +) -> Json { + let result = save_reset_password_form(reset_password_form.into_inner()); + match result { + Ok(_) => { + let status = "success".to_string(); + let msg = "New password is now saved. Return home to login.".to_string(); + Json(build_json_response(status, None, Some(msg))) + } + Err(err) => { + let status = "error".to_string(); + let msg = format!("{}", err); + Json(build_json_response(status, None, Some(msg))) + } + } +} + +// HELPERS AND ROUTES FOR /send_password_reset + +#[derive(Debug, Serialize)] +pub struct SendPasswordResetContext { + pub back: Option, + pub title: Option, + pub flash_name: Option, + pub flash_msg: Option, +} + +impl SendPasswordResetContext { + pub fn build() -> SendPasswordResetContext { + SendPasswordResetContext { + back: None, + title: None, + flash_name: None, + flash_msg: None, + } + } +} + +/// Password reset request handler. This route is used by a user who is not logged in to send a new password reset link. +#[get("/send_password_reset")] +pub fn send_password_reset_page(flash: Option) -> Template { + let mut context = SendPasswordResetContext::build(); + context.back = Some("/".to_string()); + context.title = Some("Send Password Reset".to_string()); + // check to see if there is a flash message to display + if let Some(flash) = flash { + // add flash message contents to the context object + context.flash_name = Some(flash.name().to_string()); + context.flash_msg = Some(flash.msg().to_string()); + }; + Template::render("password/send_password_reset", &context) +} + +/// Send password reset request handler. This route is used by a user who is not logged in +/// and is specifically for users who have forgotten their password. A successful request results +/// in a Scuttlebutt private message being sent to the account of the device admin. +#[post("/send_password_reset")] +pub fn send_password_reset_post() -> Template { + info!("++ send password reset post"); + let result = password_utils::send_password_reset(); + match result { + Ok(_) => { + let mut context = ChangePasswordContext::build(); + context.back = Some("/".to_string()); + context.title = Some("Send Password Reset".to_string()); + context.flash_name = Some("success".to_string()); + let flash_msg = + "A password reset link has been sent to the admin of this device".to_string(); + context.flash_msg = Some(flash_msg); + Template::render("password/send_password_reset", &context) + } + Err(err) => { + let mut context = ChangePasswordContext::build(); + context.back = Some("/".to_string()); + context.title = Some("Send Password Reset".to_string()); + context.flash_name = Some("error".to_string()); + context.flash_msg = Some(format!("Failed to send password reset link: {}", err)); + Template::render("password/send_password_reset", &context) + } + } +} + +// HELPERS AND ROUTES FOR /settings/change_password + +#[derive(Debug, Deserialize, FromForm)] +pub struct PasswordForm { + pub old_password: String, + pub new_password1: String, + pub new_password2: String, +} + +/// Password save form request handler. This function is for use by a user who is already logged in to change their password. +pub fn save_password_form(password_form: PasswordForm) -> Result<(), PeachWebError> { + info!( + "change password!: {} {} {}", + password_form.old_password, password_form.new_password1, password_form.new_password2 + ); + password_utils::verify_password(&password_form.old_password)?; + // if the previous line did not throw an error, then the old password is correct + password_utils::validate_new_passwords( + &password_form.new_password1, + &password_form.new_password2, + )?; + // if the previous line did not throw an error, then the new password is valid + password_utils::set_new_password(&password_form.new_password1)?; + Ok(()) +} + +/// Change password request handler. This is used by a user who is already logged in. +#[get("/settings/change_password")] +pub fn change_password(flash: Option) -> Template { + let mut context = ChangePasswordContext::build(); + // set back icon link to network route + context.back = Some("/network".to_string()); + context.title = Some("Change Password".to_string()); + // check to see if there is a flash message to display + if let Some(flash) = flash { + // add flash message contents to the context object + context.flash_name = Some(flash.name().to_string()); + context.flash_msg = Some(flash.msg().to_string()); + }; + Template::render("password/change_password", &context) +} + +/// Change password form request handler. This route is used by a user who is already logged in. +#[post("/settings/change_password", data = "")] +pub fn change_password_post(password_form: Form) -> Template { + let result = save_password_form(password_form.into_inner()); + match result { + Ok(_) => { + let mut context = ChangePasswordContext::build(); + // set back icon link to network route + context.back = Some("/network".to_string()); + context.title = Some("Change Password".to_string()); + context.flash_name = Some("success".to_string()); + context.flash_msg = Some("New password is now saved".to_string()); + // template_dir is set in Rocket.toml + Template::render("password/change_password", &context) + } + Err(err) => { + let mut context = ChangePasswordContext::build(); + // set back icon link to network route + context.back = Some("/network".to_string()); + context.title = Some("Configure DNS".to_string()); + context.flash_name = Some("error".to_string()); + context.flash_msg = Some(format!("Failed to save new password: {}", err)); + Template::render("password/change_password", &context) + } + } +} + +/// JSON change password form request handler. +#[post("/api/v1/settings/change_password", data = "")] +pub fn save_password_form_endpoint(password_form: Json) -> Json { + let result = save_password_form(password_form.into_inner()); + match result { + Ok(_) => { + let status = "success".to_string(); + let msg = "Your password was successfully changed".to_string(); + Json(build_json_response(status, None, Some(msg))) + } + Err(err) => { + let status = "error".to_string(); + let msg = format!("{}", err); + Json(build_json_response(status, None, Some(msg))) + } + } +} diff --git a/peach-web/src/routes/device.rs b/peach-web/src/routes/device.rs new file mode 100644 index 0000000..9289730 --- /dev/null +++ b/peach-web/src/routes/device.rs @@ -0,0 +1,279 @@ +use log::{debug, info, warn}; +use rocket::{ + get, post, + request::FlashMessage, + response::{Flash, Redirect}, +}; +use rocket_contrib::{json::Json, templates::Template}; +use serde::Serialize; +use std::{ + io, + process::{Command, Output}, +}; + +use peach_lib::config_manager::load_peach_config; +use peach_lib::stats_client::{CpuStatPercentages, DiskUsage, LoadAverage, MemStat}; +use peach_lib::{dyndns_client, network_client, oled_client, sbot_client, stats_client}; + +use crate::utils::{build_json_response, JsonResponse}; + +// HELPERS AND ROUTES FOR /device + +/// System statistics data. +#[derive(Debug, Serialize)] +pub struct DeviceContext { + pub back: Option, + pub cpu_stat_percent: Option, + pub disk_stats: Vec, + pub flash_name: Option, + pub flash_msg: Option, + pub load_average: Option, + pub mem_stats: Option, + pub network_ping: String, + pub oled_ping: String, + pub stats_ping: String, + pub dyndns_enabled: bool, + pub dyndns_is_online: bool, + pub config_is_valid: bool, + pub sbot_is_online: bool, + pub title: Option, + pub uptime: Option, +} + +impl DeviceContext { + pub fn build() -> DeviceContext { + // convert result to Option, discard any error + let cpu_stat_percent = stats_client::cpu_stats_percent().ok(); + let load_average = stats_client::load_average().ok(); + let mem_stats = stats_client::mem_stats().ok(); + let network_ping = match network_client::ping() { + Ok(_) => "ONLINE".to_string(), + Err(_) => "OFFLINE".to_string(), + }; + let oled_ping = match oled_client::ping() { + Ok(_) => "ONLINE".to_string(), + Err(_) => "OFFLINE".to_string(), + }; + let stats_ping = match stats_client::ping() { + Ok(_) => "ONLINE".to_string(), + Err(_) => "OFFLINE".to_string(), + }; + let uptime = match stats_client::uptime() { + Ok(mins) => mins, + Err(_) => "Unavailable".to_string(), + }; + + // serialize disk usage data into Vec + let disk_usage_stats = match stats_client::disk_usage() { + Ok(disks) => { + let partitions: Vec = serde_json::from_str(disks.as_str()) + .expect("Failed to deserialize disk_usage response"); + partitions + } + Err(_) => Vec::new(), + }; + + let mut disk_stats = Vec::new(); + // select only the partition we're interested in: /dev/mmcblk0p2 ("/") + for disk in disk_usage_stats { + if disk.mountpoint == "/" { + disk_stats.push(disk); + } + } + + // parse the uptime string to a signed integer (for math) + let uptime_parsed = uptime.parse::().ok(); + + // dyndns_is_online & config_is_valid + let dyndns_enabled: bool; + let dyndns_is_online: bool; + let config_is_valid: bool; + let load_peach_config_result = load_peach_config(); + match load_peach_config_result { + Ok(peach_config) => { + dyndns_enabled = peach_config.dyn_enabled; + config_is_valid = true; + if dyndns_enabled { + let is_dyndns_online_result = dyndns_client::is_dns_updater_online(); + match is_dyndns_online_result { + Ok(is_online) => { + dyndns_is_online = is_online; + } + Err(_err) => { + dyndns_is_online = false; + } + } + } else { + dyndns_is_online = false; + } + } + Err(_err) => { + dyndns_enabled = false; + dyndns_is_online = false; + config_is_valid = false; + } + } + + // test if go-sbot is running + let sbot_is_online: bool; + let sbot_is_online_result = sbot_client::is_sbot_online(); + match sbot_is_online_result { + Ok(val) => { + sbot_is_online = val; + } + Err(_err) => { + sbot_is_online = false; + } + } + + DeviceContext { + back: None, + cpu_stat_percent, + disk_stats, + flash_name: None, + flash_msg: None, + load_average, + mem_stats, + network_ping, + oled_ping, + stats_ping, + dyndns_enabled, + dyndns_is_online, + config_is_valid, + sbot_is_online, + title: None, + uptime: uptime_parsed, + } + } +} + +#[get("/device")] +pub fn device_stats(flash: Option) -> Template { + // assign context through context_builder call + let mut context = DeviceContext::build(); + context.back = Some("/".to_string()); + context.title = Some("Device Status".to_string()); + // check to see if there is a flash message to display + if let Some(flash) = flash { + // add flash message contents to the context object + context.flash_name = Some(flash.name().to_string()); + context.flash_msg = Some(flash.msg().to_string()); + }; + // template_dir is set in Rocket.toml + Template::render("device", &context) +} + +// HELPERS AND ROUTES FOR /device/reboot + +/// Executes a system command to reboot the device immediately. +pub fn reboot() -> io::Result { + info!("Rebooting the device"); + // ideally, we'd like to reboot after 5 seconds to allow time for JSON + // response but this is not possible with the `shutdown` command alone. + // TODO: send "rebooting..." message to `peach-oled` for display + Command::new("sudo") + .arg("shutdown") + .arg("-r") + .arg("now") + .output() +} + +#[get("/device/reboot")] +pub fn reboot_cmd() -> Flash { + match reboot() { + Ok(_) => Flash::success(Redirect::to("/shutdown"), "Rebooting the device"), + Err(_) => Flash::error(Redirect::to("/shutdown"), "Failed to reboot the device"), + } +} + +/// JSON request handler for device reboot. +#[post("/api/v1/device/reboot")] +pub fn reboot_device() -> Json { + match reboot() { + Ok(_) => { + debug!("Going down for reboot..."); + let status = "success".to_string(); + let msg = "Going down for reboot.".to_string(); + Json(build_json_response(status, None, Some(msg))) + } + Err(_) => { + warn!("Reboot failed"); + let status = "error".to_string(); + let msg = "Failed to reboot the device.".to_string(); + Json(build_json_response(status, None, Some(msg))) + } + } +} + +// HELPERS AND ROUTES FOR /device/shutdown + +/// Executes a system command to shutdown the device immediately. +pub fn shutdown() -> io::Result { + info!("Shutting down the device"); + // ideally, we'd like to reboot after 5 seconds to allow time for JSON + // response but this is not possible with the `shutdown` command alone. + // TODO: send "shutting down..." message to `peach-oled` for display + Command::new("sudo").arg("shutdown").arg("now").output() +} + +#[get("/device/shutdown")] +pub fn shutdown_cmd() -> Flash { + match shutdown() { + Ok(_) => Flash::success(Redirect::to("/shutdown"), "Shutting down the device"), + Err(_) => Flash::error(Redirect::to("/shutdown"), "Failed to shutdown the device"), + } +} + +// shutdown the device +#[post("/api/v1/device/shutdown")] +pub fn shutdown_device() -> Json { + match shutdown() { + Ok(_) => { + debug!("Going down for shutdown..."); + let status = "success".to_string(); + let msg = "Going down for shutdown.".to_string(); + Json(build_json_response(status, None, Some(msg))) + } + Err(_) => { + warn!("Shutdown failed"); + let status = "error".to_string(); + let msg = "Failed to shutdown the device.".to_string(); + Json(build_json_response(status, None, Some(msg))) + } + } +} + +// HELPERS AND ROUTES FOR /shutdown + +#[derive(Debug, Serialize)] +pub struct ShutdownContext { + pub back: Option, + pub flash_name: Option, + pub flash_msg: Option, + pub title: Option, +} + +impl ShutdownContext { + pub fn build() -> ShutdownContext { + ShutdownContext { + back: None, + flash_name: None, + flash_msg: None, + title: None, + } + } +} + +#[get("/shutdown")] +pub fn shutdown_menu(flash: Option) -> Template { + let mut context = ShutdownContext::build(); + context.back = Some("/".to_string()); + context.title = Some("Shutdown Device".to_string()); + // check to see if there is a flash message to display + if let Some(flash) = flash { + // add flash message contents to the context object + context.flash_name = Some(flash.name().to_string()); + context.flash_msg = Some(flash.msg().to_string()); + }; + Template::render("shutdown", &context) +} diff --git a/peach-web/src/routes/helpers.rs b/peach-web/src/routes/helpers.rs new file mode 100644 index 0000000..11fa1b2 --- /dev/null +++ b/peach-web/src/routes/helpers.rs @@ -0,0 +1,57 @@ +use log::debug; +use rocket::{catch, get, response::NamedFile}; +use rocket_contrib::templates::Template; +use serde::Serialize; +use std::path::{Path, PathBuf}; + +#[get("/", rank = 2)] +pub fn files(file: PathBuf) -> Option { + NamedFile::open(Path::new("static/").join(file)).ok() +} + +// HELPERS AND ROUTES FOR 404 ERROR + +#[derive(Debug, Serialize)] +pub struct ErrorContext { + pub back: Option, + pub flash_name: Option, + pub flash_msg: Option, + pub title: Option, +} + +impl ErrorContext { + pub fn build() -> ErrorContext { + ErrorContext { + back: None, + flash_name: None, + flash_msg: None, + title: None, + } + } +} + +#[catch(404)] +pub fn not_found() -> Template { + debug!("404 Page Not Found"); + let mut context = ErrorContext::build(); + context.back = Some("/".to_string()); + context.title = Some("404: Page Not Found".to_string()); + context.flash_name = Some("error".to_string()); + context.flash_msg = Some("No resource found for given URL".to_string()); + + Template::render("not_found", context) +} + +// HELPERS AND ROUTES FOR 500 ERROR + +#[catch(500)] +pub fn internal_error() -> Template { + debug!("500 Internal Server Error"); + let mut context = ErrorContext::build(); + context.back = Some("/".to_string()); + context.title = Some("500: Internal Server Error".to_string()); + context.flash_name = Some("error".to_string()); + context.flash_msg = Some("Internal server error".to_string()); + + Template::render("internal_error", context) +} diff --git a/peach-web/src/routes/index.rs b/peach-web/src/routes/index.rs new file mode 100644 index 0000000..5d57d2d --- /dev/null +++ b/peach-web/src/routes/index.rs @@ -0,0 +1,67 @@ +use rocket::{get, request::FlashMessage}; +use rocket_contrib::templates::Template; +use serde::Serialize; + +// HELPERS AND ROUTES FOR / (HOME PAGE) + +#[derive(Debug, Serialize)] +pub struct HomeContext { + pub flash_name: Option, + pub flash_msg: Option, + pub title: Option, +} + +impl HomeContext { + pub fn build() -> HomeContext { + HomeContext { + flash_name: None, + flash_msg: None, + title: None, + } + } +} + +#[get("/")] +pub fn index() -> Template { + let context = HomeContext { + flash_name: None, + flash_msg: None, + title: None, + }; + Template::render("index", &context) +} + +// HELPERS AND ROUTES FOR /help + +#[derive(Debug, Serialize)] +pub struct HelpContext { + pub back: Option, + pub flash_name: Option, + pub flash_msg: Option, + pub title: Option, +} + +impl HelpContext { + pub fn build() -> HelpContext { + HelpContext { + back: None, + flash_name: None, + flash_msg: None, + title: None, + } + } +} + +#[get("/help")] +pub fn help(flash: Option) -> Template { + let mut context = HelpContext::build(); + context.back = Some("/".to_string()); + context.title = Some("Help".to_string()); + // check to see if there is a flash message to display + if let Some(flash) = flash { + // add flash message contents to the context object + context.flash_name = Some(flash.name().to_string()); + context.flash_msg = Some(flash.msg().to_string()); + }; + Template::render("help", &context) +} diff --git a/peach-web/src/routes/mod.rs b/peach-web/src/routes/mod.rs new file mode 100644 index 0000000..87368cc --- /dev/null +++ b/peach-web/src/routes/mod.rs @@ -0,0 +1,7 @@ +pub mod authentication; +pub mod device; +pub mod helpers; +pub mod index; +pub mod ping; +pub mod scuttlebutt; +pub mod settings; \ No newline at end of file diff --git a/peach-web/src/routes/ping.rs b/peach-web/src/routes/ping.rs new file mode 100644 index 0000000..2eac821 --- /dev/null +++ b/peach-web/src/routes/ping.rs @@ -0,0 +1,86 @@ +//! Helper routes for pinging services to check that they are active +use log::{debug, warn}; +use rocket::get; +use rocket_contrib::json::Json; + +use peach_lib::dyndns_client::is_dns_updater_online; +use peach_lib::network_client; +use peach_lib::oled_client; +use peach_lib::stats_client; + +use crate::utils::{build_json_response, JsonResponse}; + +/// Status route: useful for checking connectivity from web client. +#[get("/api/v1/ping")] +pub fn ping_pong() -> Json { + // ping pong + let status = "success".to_string(); + let msg = "pong!".to_string(); + Json(build_json_response(status, None, Some(msg))) +} + +/// Test route: useful for ad hoc testing. +#[get("/api/v1/test")] +pub fn test_route() -> Json { + let val = is_dns_updater_online().unwrap(); + let status = "success".to_string(); + let msg = val.to_string(); + Json(build_json_response(status, None, Some(msg))) +} + +/// Status route: check availability of `peach-network` microservice. +#[get("/api/v1/ping/network")] +pub fn ping_network() -> Json { + match network_client::ping() { + Ok(_) => { + debug!("peach-network responded successfully"); + let status = "success".to_string(); + let msg = "peach-network is available.".to_string(); + Json(build_json_response(status, None, Some(msg))) + } + Err(_) => { + warn!("peach-network failed to respond"); + let status = "error".to_string(); + let msg = "peach-network is unavailable.".to_string(); + Json(build_json_response(status, None, Some(msg))) + } + } +} + +/// Status route: check availability of `peach-oled` microservice. +#[get("/api/v1/ping/oled")] +pub fn ping_oled() -> Json { + match oled_client::ping() { + Ok(_) => { + debug!("peach-oled responded successfully"); + let status = "success".to_string(); + let msg = "peach-oled is available.".to_string(); + Json(build_json_response(status, None, Some(msg))) + } + Err(_) => { + warn!("peach-oled failed to respond"); + let status = "error".to_string(); + let msg = "peach-oled is unavailable.".to_string(); + Json(build_json_response(status, None, Some(msg))) + } + } +} + +/// Status route: check availability of `peach-stats` microservice. +#[get("/api/v1/ping/stats")] +pub fn ping_stats() -> Json { + match stats_client::ping() { + Ok(_) => { + debug!("peach-stats responded successfully"); + let status = "success".to_string(); + let msg = "peach-stats is available.".to_string(); + Json(build_json_response(status, None, Some(msg))) + } + Err(_) => { + warn!("peach-stats failed to respond"); + let status = "error".to_string(); + let msg = "peach-stats is unavailable.".to_string(); + Json(build_json_response(status, None, Some(msg))) + } + } +} diff --git a/peach-web/src/routes/scuttlebutt.rs b/peach-web/src/routes/scuttlebutt.rs new file mode 100644 index 0000000..a68095c --- /dev/null +++ b/peach-web/src/routes/scuttlebutt.rs @@ -0,0 +1,110 @@ +//! Routes for ScuttleButt related functionality. + +use rocket::{get, request::FlashMessage}; +use rocket_contrib::templates::Template; +use serde::Serialize; + +// HELPERS AND ROUTES FOR /messages + +#[derive(Debug, Serialize)] +pub struct MessageContext { + pub back: Option, + pub flash_name: Option, + pub flash_msg: Option, + pub title: Option, +} + +impl MessageContext { + pub fn build() -> MessageContext { + MessageContext { + back: None, + flash_name: None, + flash_msg: None, + title: None, + } + } +} + +#[get("/messages")] +pub fn messages(flash: Option) -> Template { + let mut context = MessageContext::build(); + context.back = Some("/".to_string()); + context.title = Some("Private Messages".to_string()); + // check to see if there is a flash message to display + if let Some(flash) = flash { + // add flash message contents to the context object + context.flash_name = Some(flash.name().to_string()); + context.flash_msg = Some(flash.msg().to_string()); + }; + Template::render("messages", &context) +} + +// HELPERS AND ROUTES FOR /peers + +#[derive(Debug, Serialize)] +pub struct PeerContext { + pub back: Option, + pub flash_name: Option, + pub flash_msg: Option, + pub title: Option, +} + +impl PeerContext { + pub fn build() -> PeerContext { + PeerContext { + back: None, + flash_name: None, + flash_msg: None, + title: None, + } + } +} + +#[get("/peers")] +pub fn peers(flash: Option) -> Template { + let mut context = PeerContext::build(); + context.back = Some("/".to_string()); + context.title = Some("Scuttlebutt Peers".to_string()); + // check to see if there is a flash message to display + if let Some(flash) = flash { + // add flash message contents to the context object + context.flash_name = Some(flash.name().to_string()); + context.flash_msg = Some(flash.msg().to_string()); + }; + Template::render("peers", &context) +} + +// HELPERS AND ROUTES FOR /profile + +#[derive(Debug, Serialize)] +pub struct ProfileContext { + pub back: Option, + pub flash_name: Option, + pub flash_msg: Option, + pub title: Option, +} + +impl ProfileContext { + pub fn build() -> ProfileContext { + ProfileContext { + back: None, + flash_name: None, + flash_msg: None, + title: None, + } + } +} + +#[get("/profile")] +pub fn profile(flash: Option) -> Template { + let mut context = ProfileContext::build(); + context.back = Some("/".to_string()); + context.title = Some("Profile".to_string()); + // check to see if there is a flash message to display + if let Some(flash) = flash { + // add flash message contents to the context object + context.flash_name = Some(flash.name().to_string()); + context.flash_msg = Some(flash.msg().to_string()); + }; + Template::render("profile", &context) +} diff --git a/peach-web/src/routes/settings/admin.rs b/peach-web/src/routes/settings/admin.rs new file mode 100644 index 0000000..0e0f4b2 --- /dev/null +++ b/peach-web/src/routes/settings/admin.rs @@ -0,0 +1,128 @@ +use rocket::{ + get, post, + request::{FlashMessage, Form, FromForm}, + response::{Flash, Redirect}, + uri, +}; +use rocket_contrib::templates::Template; +use serde::{Deserialize, Serialize}; + +use peach_lib::config_manager; +use peach_lib::config_manager::load_peach_config; + +use crate::error::PeachWebError; + +// HELPERS AND ROUTES FOR /settings/configure_admin + +#[derive(Debug, Serialize)] +pub struct ConfigureAdminContext { + pub ssb_admin_ids: Vec, + pub back: Option, + pub title: Option, + pub flash_name: Option, + pub flash_msg: Option, +} + +impl ConfigureAdminContext { + pub fn build() -> ConfigureAdminContext { + let peach_config = load_peach_config().unwrap(); + let ssb_admin_ids = peach_config.ssb_admin_ids; + ConfigureAdminContext { + ssb_admin_ids, + back: None, + title: None, + flash_name: None, + flash_msg: None, + } + } +} + +/// View and delete currently configured admin. +#[get("/settings/configure_admin")] +pub fn configure_admin(flash: Option) -> Template { + let mut context = ConfigureAdminContext::build(); + // set back icon link to network route + context.back = Some("/network".to_string()); + context.title = Some("Configure Admin".to_string()); + // check to see if there is a flash message to display + if let Some(flash) = flash { + // add flash message contents to the context object + context.flash_name = Some(flash.name().to_string()); + context.flash_msg = Some(flash.msg().to_string()); + }; + Template::render("admin/configure_admin", &context) +} + +// HELPERS AND ROUTES FOR /settings/admin/add + +#[derive(Debug, Deserialize, FromForm)] +pub struct AddAdminForm { + pub ssb_id: String, +} + +#[derive(Debug, Serialize)] +pub struct AddAdminContext { + pub back: Option, + pub title: Option, + pub flash_name: Option, + pub flash_msg: Option, +} + +impl AddAdminContext { + pub fn build() -> AddAdminContext { + AddAdminContext { + back: None, + title: None, + flash_name: None, + flash_msg: None, + } + } +} + +pub fn save_add_admin_form(admin_form: AddAdminForm) -> Result<(), PeachWebError> { + let _result = config_manager::add_ssb_admin_id(&admin_form.ssb_id)?; + // if the previous line didn't throw an error then it was a success + Ok(()) +} + +#[get("/settings/admin/add")] +pub fn add_admin(flash: Option) -> Template { + let mut context = AddAdminContext::build(); + context.back = Some("/settings/configure_admin".to_string()); + context.title = Some("Add Admin".to_string()); + // check to see if there is a flash message to display + if let Some(flash) = flash { + // add flash message contents to the context object + context.flash_name = Some(flash.name().to_string()); + context.flash_msg = Some(flash.msg().to_string()); + }; + // template_dir is set in Rocket.toml + Template::render("admin/add_admin", &context) +} + +#[post("/settings/admin/add", data = "")] +pub fn add_admin_post(add_admin_form: Form) -> Flash { + let result = save_add_admin_form(add_admin_form.into_inner()); + let url = uri!(configure_admin); + match result { + Ok(_) => Flash::success(Redirect::to(url), "Successfully added new admin"), + Err(_) => Flash::error(Redirect::to(url), "Failed to add new admin"), + } +} + +// HELPERS AND ROUTES FOR /settings/admin/delete + +#[derive(Debug, Deserialize, FromForm)] +pub struct DeleteAdminForm { + pub ssb_id: String, +} + +#[post("/settings/admin/delete", data = "")] +pub fn delete_admin_post(delete_admin_form: Form) -> Flash { + let result = config_manager::delete_ssb_admin_id(&delete_admin_form.ssb_id); + let url = uri!(configure_admin); + match result { + Ok(_) => Flash::success(Redirect::to(url), "Successfully removed admin id"), + Err(_) => Flash::error(Redirect::to(url), "Failed to remove admin id"), + } +} diff --git a/peach-web/src/routes/settings/dns.rs b/peach-web/src/routes/settings/dns.rs new file mode 100644 index 0000000..4e212c4 --- /dev/null +++ b/peach-web/src/routes/settings/dns.rs @@ -0,0 +1,167 @@ +use log::info; +use rocket::{ + get, post, + request::{FlashMessage, Form, FromForm}, +}; +use rocket_contrib::{json::Json, templates::Template}; +use serde::{Deserialize, Serialize}; + +use peach_lib::config_manager; +use peach_lib::config_manager::load_peach_config; +use peach_lib::dyndns_client; +use peach_lib::dyndns_client::{ + check_is_new_dyndns_domain, get_dyndns_subdomain, get_full_dynamic_domain, + is_dns_updater_online, +}; +use peach_lib::error::PeachError; +use peach_lib::jsonrpc_client_core::{Error, ErrorKind}; +use peach_lib::jsonrpc_core::types::error::ErrorCode; + +use crate::error::PeachWebError; +use crate::utils::{build_json_response, JsonResponse}; + +#[derive(Debug, Deserialize, FromForm)] +pub struct DnsForm { + pub external_domain: String, + pub enable_dyndns: bool, + pub dynamic_domain: String, +} + +pub fn save_dns_configuration(dns_form: DnsForm) -> Result<(), PeachWebError> { + // first save local configurations + config_manager::set_external_domain(&dns_form.external_domain)?; + config_manager::set_dyndns_enabled_value(dns_form.enable_dyndns)?; + // if dynamic dns is enabled and this is a new domain name, then register it + if dns_form.enable_dyndns { + let full_dynamic_domain = get_full_dynamic_domain(&dns_form.dynamic_domain); + // check if this is a new domain or if its already registered + let is_new_domain = check_is_new_dyndns_domain(&full_dynamic_domain); + if is_new_domain { + match dyndns_client::register_domain(&full_dynamic_domain) { + Ok(_) => { + info!("Registered new dyndns domain"); + // successful update + Ok(()) + } + Err(err) => { + info!("Failed to register dyndns domain: {:?}", err); + // json response for failed update + let msg: String = match err { + PeachError::JsonRpcClientCore { source } => { + match source { + Error(ErrorKind::JsonRpcError(err), _state) => match err.code { + ErrorCode::ServerError(-32030) => { + format!("Error registering domain: {} was previously registered", full_dynamic_domain) + } + _ => { + format!("Failed to register dyndns domain {:?}", err) + } + }, + _ => { + format!("Failed to register dyndns domain: {:?}", source) + } + } + } + _ => "Failed to register dyndns domain".to_string(), + }; + Err(PeachWebError::FailedToRegisterDynDomain { msg }) + } + } + } + // if the domain is already registered, then dont re-register, and just return success + else { + Ok(()) + } + } else { + Ok(()) + } +} + +#[derive(Debug, Serialize)] +pub struct ConfigureDNSContext { + pub external_domain: String, + pub dyndns_subdomain: String, + pub enable_dyndns: bool, + pub is_dyndns_online: bool, + pub back: Option, + pub title: Option, + pub flash_name: Option, + pub flash_msg: Option, +} + +impl ConfigureDNSContext { + pub fn build() -> ConfigureDNSContext { + let peach_config = load_peach_config().unwrap(); + let dyndns_fulldomain = peach_config.dyn_domain; + let is_dyndns_online = is_dns_updater_online().unwrap(); + let dyndns_subdomain = + get_dyndns_subdomain(&dyndns_fulldomain).unwrap_or(dyndns_fulldomain); + ConfigureDNSContext { + external_domain: peach_config.external_domain, + dyndns_subdomain, + enable_dyndns: peach_config.dyn_enabled, + is_dyndns_online, + back: None, + title: None, + flash_name: None, + flash_msg: None, + } + } +} + +#[get("/network/dns")] +pub fn configure_dns(flash: Option) -> Template { + let mut context = ConfigureDNSContext::build(); + // set back icon link to network route + context.back = Some("/network".to_string()); + context.title = Some("Configure DNS".to_string()); + // check to see if there is a flash message to display + if let Some(flash) = flash { + // add flash message contents to the context object + context.flash_name = Some(flash.name().to_string()); + context.flash_msg = Some(flash.msg().to_string()); + }; + Template::render("configure_dns", &context) +} + +#[post("/network/dns", data = "")] +pub fn configure_dns_post(dns: Form) -> Template { + let result = save_dns_configuration(dns.into_inner()); + match result { + Ok(_) => { + let mut context = ConfigureDNSContext::build(); + // set back icon link to network route + context.back = Some("/network".to_string()); + context.title = Some("Configure DNS".to_string()); + context.flash_name = Some("success".to_string()); + context.flash_msg = Some("New dynamic dns configuration is now enabled".to_string()); + Template::render("configure_dns", &context) + } + Err(err) => { + let mut context = ConfigureDNSContext::build(); + // set back icon link to network route + context.back = Some("/network".to_string()); + context.title = Some("Configure DNS".to_string()); + context.flash_name = Some("error".to_string()); + context.flash_msg = Some(format!("Failed to save dns configurations: {}", err)); + Template::render("configure_dns", &context) + } + } +} + +#[post("/api/v1/dns/configure", data = "")] +pub fn save_dns_configuration_endpoint(dns_form: Json) -> Json { + let result = save_dns_configuration(dns_form.into_inner()); + match result { + Ok(_) => { + let status = "success".to_string(); + let msg = "New dynamic dns configuration is now enabled".to_string(); + Json(build_json_response(status, None, Some(msg))) + } + Err(err) => { + let status = "error".to_string(); + let msg = format!("{}", err); + Json(build_json_response(status, None, Some(msg))) + } + } +} diff --git a/peach-web/src/routes/settings/mod.rs b/peach-web/src/routes/settings/mod.rs new file mode 100644 index 0000000..8fee4d7 --- /dev/null +++ b/peach-web/src/routes/settings/mod.rs @@ -0,0 +1,3 @@ +pub mod admin; +pub mod dns; +pub mod network; \ No newline at end of file diff --git a/peach-web/src/routes/settings/network.rs b/peach-web/src/routes/settings/network.rs new file mode 100644 index 0000000..ee67fd2 --- /dev/null +++ b/peach-web/src/routes/settings/network.rs @@ -0,0 +1,1065 @@ +use log::{debug, warn}; +use percent_encoding::percent_decode; +use rocket::{ + get, + http::RawStr, + post, + request::{FlashMessage, Form, FromForm}, + response::{Flash, Redirect}, + uri, UriDisplayQuery, +}; +use rocket_contrib::{json, json::Json, templates::Template}; +use serde::{Deserialize, Serialize}; +use std::collections::HashMap; + +use peach_lib::network_client; +use peach_lib::network_client::{AccessPoint, Networks, Scan}; +use peach_lib::stats_client::Traffic; + +use crate::utils::monitor; +use crate::utils::monitor::{Alert, Data, Threshold}; +use crate::utils::{build_json_response, JsonResponse}; + +// STRUCTS USED BY NETWORK ROUTES + +#[derive(Debug, Deserialize, FromForm, UriDisplayQuery)] +pub struct Ssid { + pub ssid: String, +} + +#[derive(Debug, Deserialize, FromForm)] +pub struct WiFi { + pub ssid: String, + pub pass: String, +} + +// HELPERS AND ROUTES FOR /network/wifi/usage/reset + +#[get("/network/wifi/usage/reset")] +pub fn wifi_usage_reset() -> Flash { + let url = uri!(wifi_usage); + match monitor::reset_data() { + Ok(_) => Flash::success(Redirect::to(url), "Reset stored network traffic total"), + Err(_) => Flash::error( + Redirect::to(url), + "Failed to reset stored network traffic total", + ), + } +} + +#[post("/network/wifi/connect", data = "")] +pub fn connect_wifi(network: Form) -> Flash { + let ssid = &network.ssid; + let url = uri!(network_detail: ssid); + match network_client::id("wlan0", ssid) { + Ok(id) => match network_client::connect(&id, "wlan0") { + Ok(_) => Flash::success(Redirect::to(url), "Connected to chosen network"), + Err(_) => Flash::error(Redirect::to(url), "Failed to connect to chosen network"), + }, + Err(_) => Flash::error(Redirect::to(url), "Failed to retrieve the network ID"), + } +} + +#[post("/network/wifi/disconnect", data = "")] +pub fn disconnect_wifi(network: Form) -> Flash { + let ssid = &network.ssid; + let url = uri!(network_home); + match network_client::disable("wlan0", ssid) { + Ok(_) => Flash::success(Redirect::to(url), "Disconnected from WiFi network"), + Err(_) => Flash::error(Redirect::to(url), "Failed to disconnect from WiFi network"), + } +} + +#[post("/network/wifi/forget", data = "")] +pub fn forget_wifi(network: Form) -> Flash { + let ssid = &network.ssid; + let url = uri!(network_home); + match network_client::forget("wlan0", ssid) { + Ok(_) => Flash::success(Redirect::to(url), "WiFi credentials removed"), + Err(_) => Flash::error( + Redirect::to(url), + "Failed to remove WiFi credentials".to_string(), + ), + } +} + +#[get("/network/wifi/modify?")] +pub fn wifi_password(ssid: &RawStr, flash: Option) -> Template { + // decode ssid from url + let decoded_ssid = percent_decode(ssid.as_bytes()).decode_utf8().unwrap(); + let mut context = NetworkAddContext { + back: Some("/network/wifi".to_string()), + flash_name: None, + flash_msg: None, + selected: Some(decoded_ssid.to_string()), + title: Some("Update WiFi Password".to_string()), + }; + // check to see if there is a flash message to display + if let Some(flash) = flash { + // add flash message contents to the context object + context.flash_name = Some(flash.name().to_string()); + context.flash_msg = Some(flash.msg().to_string()); + }; + // template_dir is set in Rocket.toml + Template::render("network_modify", &context) +} + +#[post("/network/wifi/modify", data = "")] +pub fn wifi_set_password(wifi: Form) -> Flash { + let ssid = &wifi.ssid; + let pass = &wifi.pass; + let url = uri!(network_detail: ssid); + match network_client::update("wlan0", ssid, pass) { + Ok(_) => Flash::success(Redirect::to(url), "WiFi password updated".to_string()), + Err(_) => Flash::error( + Redirect::to(url), + "Failed to update WiFi password".to_string(), + ), + } +} + +// HELPERS AND ROUTES FOR /network + +#[derive(Debug, Serialize)] +pub struct NetworkContext { + pub ap_ip: String, + pub ap_ssid: String, + pub ap_state: String, + pub ap_traffic: Option, + pub wlan_ip: String, + pub wlan_rssi: Option, + pub wlan_scan: Option>, + pub wlan_ssid: String, + pub wlan_state: String, + pub wlan_status: String, + pub wlan_traffic: Option, + pub flash_name: Option, + pub flash_msg: Option, + // allows for passing in the ssid of a chosen access point + // this is used in the network_detail template + pub selected: Option, + // page title for header in navbar + pub title: Option, + // url for back-arrow link + pub back: Option, +} + +impl NetworkContext { + pub fn build() -> NetworkContext { + let ap_ip = match network_client::ip("ap0") { + Ok(ip) => ip, + Err(_) => "x.x.x.x".to_string(), + }; + let ap_ssid = match network_client::ssid("ap0") { + Ok(ssid) => ssid, + Err(_) => "Not currently activated".to_string(), + }; + let ap_state = match network_client::state("ap0") { + Ok(state) => state, + Err(_) => "Interface unavailable".to_string(), + }; + let ap_traffic = match network_client::traffic("ap0") { + Ok(traffic) => { + let mut t = traffic; + // modify traffic values & assign measurement unit + // based on received and transmitted values + // if received > 999 MB, convert it to GB + if t.received > 1_047_527_424 { + t.received /= 1_073_741_824; + t.rx_unit = Some("GB".to_string()); + } else if t.received > 0 { + // otherwise, convert it to MB + t.received = (t.received / 1024) / 1024; + t.rx_unit = Some("MB".to_string()); + } else { + t.received = 0; + t.rx_unit = Some("MB".to_string()); + } + + if t.transmitted > 1_047_527_424 { + t.transmitted /= 1_073_741_824; + t.tx_unit = Some("GB".to_string()); + } else if t.transmitted > 0 { + t.transmitted = (t.transmitted / 1024) / 1024; + t.tx_unit = Some("MB".to_string()); + } else { + t.transmitted = 0; + t.tx_unit = Some("MB".to_string()); + } + Some(t) + } + Err(_) => None, + }; + let wlan_ip = match network_client::ip("wlan0") { + Ok(ip) => ip, + Err(_) => "x.x.x.x".to_string(), + }; + let wlan_rssi = match network_client::rssi_percent("wlan0") { + Ok(rssi) => Some(rssi), + Err(_) => None, + }; + let wlan_scan = match network_client::available_networks("wlan0") { + Ok(networks) => { + let scan: Vec = serde_json::from_str(networks.as_str()) + .expect("Failed to deserialize scan_networks response"); + Some(scan) + } + Err(_) => None, + }; + let wlan_ssid = match network_client::ssid("wlan0") { + Ok(ssid) => ssid, + Err(_) => "Not connected".to_string(), + }; + let wlan_state = match network_client::state("wlan0") { + Ok(state) => state, + Err(_) => "Interface unavailable".to_string(), + }; + let wlan_status = match network_client::status("wlan0") { + Ok(status) => status, + Err(_) => "Interface unavailable".to_string(), + }; + let wlan_traffic = match network_client::traffic("wlan0") { + Ok(traffic) => { + let mut t = traffic; + // modify traffic values & assign measurement unit + // based on received and transmitted values + // if received > 999 MB, convert it to GB + if t.received > 1_047_527_424 { + t.received /= 1_073_741_824; + t.rx_unit = Some("GB".to_string()); + } else if t.received > 0 { + // otherwise, convert it to MB + t.received = (t.received / 1024) / 1024; + t.rx_unit = Some("MB".to_string()); + } else { + t.received = 0; + t.rx_unit = Some("MB".to_string()); + } + + if t.transmitted > 1_047_527_424 { + t.transmitted /= 1_073_741_824; + t.tx_unit = Some("GB".to_string()); + } else if t.transmitted > 0 { + t.transmitted = (t.transmitted / 1024) / 1024; + t.tx_unit = Some("MB".to_string()); + } else { + t.transmitted = 0; + t.tx_unit = Some("MB".to_string()); + } + Some(t) + } + Err(_) => None, + }; + + NetworkContext { + ap_ip, + ap_ssid, + ap_state, + ap_traffic, + wlan_ip, + wlan_rssi, + wlan_scan, + wlan_ssid, + wlan_state, + wlan_status, + wlan_traffic, + flash_name: None, + flash_msg: None, + selected: None, + title: None, + back: None, + } + } +} + +#[get("/network")] +pub fn network_home(flash: Option) -> Template { + // assign context through context_builder call + let mut context = NetworkContext::build(); + // set back button (nav) url + context.back = Some("/".to_string()); + // set page title + context.title = Some("Network Configuration".to_string()); + // check to see if there is a flash message to display + if let Some(flash) = flash { + // add flash message contents to the context object + context.flash_name = Some(flash.name().to_string()); + context.flash_msg = Some(flash.msg().to_string()); + }; + // template_dir is set in Rocket.toml + Template::render("network_card", &context) +} + +// HELPERS AND ROUTES FOR /network/ap/activate + +#[get("/network/ap/activate")] +pub fn deploy_ap() -> Flash { + // activate the wireless access point + debug!("Activating WiFi access point."); + match network_client::activate_ap() { + Ok(_) => Flash::success(Redirect::to("/network"), "Activated WiFi access point"), + Err(_) => Flash::error( + Redirect::to("/network"), + "Failed to activate WiFi access point", + ), + } +} + +// HELPERS AND ROUTES FOR /network/wifi + +#[derive(Debug, Serialize)] +pub struct NetworkListContext { + pub ap_state: String, + pub back: Option, + pub flash_name: Option, + pub flash_msg: Option, + pub title: Option, + pub wlan_networks: HashMap, + pub wlan_ssid: String, +} + +impl NetworkListContext { + pub fn build() -> NetworkListContext { + // list of networks saved in the wpa_supplicant.conf + let wlan_list = match network_client::saved_networks() { + Ok(ssids) => { + let networks: Vec = serde_json::from_str(ssids.as_str()) + .expect("Failed to deserialize scan_list response"); + networks + } + Err(_) => Vec::new(), + }; + + // list of networks currently in range (online & accessible) + let wlan_scan = match network_client::available_networks("wlan0") { + Ok(networks) => { + let scan: Vec = serde_json::from_str(networks.as_str()) + .expect("Failed to deserialize scan_networks response"); + scan + } + Err(_) => Vec::new(), + }; + + let wlan_ssid = match network_client::ssid("wlan0") { + Ok(ssid) => ssid, + Err(_) => "Not connected".to_string(), + }; + + // create a hashmap to combine wlan_list & wlan_scan without repetition + let mut wlan_networks = HashMap::new(); + for ap in wlan_scan { + wlan_networks.insert(ap.ssid, "Available".to_string()); + } + for network in wlan_list { + // insert ssid (with state) only if it doesn't already exist + wlan_networks + .entry(network.ssid) + .or_insert_with(|| "Not in range".to_string()); + } + + let ap_state = match network_client::state("ap0") { + Ok(state) => state, + Err(_) => "Interface unavailable".to_string(), + }; + + NetworkListContext { + ap_state, + back: None, + flash_msg: None, + flash_name: None, + title: None, + wlan_networks, + wlan_ssid, + } + } +} + +#[get("/network/wifi")] +pub fn wifi_list(flash: Option) -> Template { + // assign context through context_builder call + let mut context = NetworkListContext::build(); + context.back = Some("/network".to_string()); + context.title = Some("WiFi Networks".to_string()); + // check to see if there is a flash message to display + if let Some(flash) = flash { + // add flash message contents to the context object + context.flash_name = Some(flash.name().to_string()); + context.flash_msg = Some(flash.msg().to_string()); + }; + // template_dir is set in Rocket.toml + Template::render("network_list", &context) +} + +// HELPERS AND ROUTES FOR /network/wifi + +#[derive(Debug, Serialize)] +pub struct NetworkDetailContext { + pub back: Option, + pub flash_name: Option, + pub flash_msg: Option, + pub saved_aps: Vec, + pub selected: Option, + pub title: Option, + pub wlan_ip: String, + pub wlan_networks: HashMap, + pub wlan_rssi: Option, + pub wlan_ssid: String, + pub wlan_state: String, + pub wlan_status: String, + pub wlan_traffic: Option, +} + +impl NetworkDetailContext { + pub fn build() -> NetworkDetailContext { + let wlan_ip = match network_client::ip("wlan0") { + Ok(ip) => ip, + Err(_) => "x.x.x.x".to_string(), + }; + // list of networks saved in wpa_supplicant.conf + let wlan_list = match network_client::saved_networks() { + Ok(ssids) => { + let networks: Vec = serde_json::from_str(ssids.as_str()) + .expect("Failed to deserialize scan_list response"); + networks + } + Err(_) => Vec::new(), + }; + // list of networks saved in wpa_supplicant.conf + // HACK: we're running the same function twice (wlan_list) + // see if we can implement clone for Vec instead + let saved_aps = match network_client::saved_networks() { + Ok(ssids) => { + let networks: Vec = serde_json::from_str(ssids.as_str()) + .expect("Failed to deserialize scan_list response"); + networks + } + Err(_) => Vec::new(), + }; + let wlan_rssi = match network_client::rssi_percent("wlan0") { + Ok(rssi) => Some(rssi), + Err(_) => None, + }; + // list of networks currently in range (online & accessible) + let wlan_scan = match network_client::available_networks("wlan0") { + Ok(networks) => { + let scan: Vec = serde_json::from_str(networks.as_str()) + .expect("Failed to deserialize scan_networks response"); + scan + } + Err(_) => Vec::new(), + }; + let wlan_ssid = match network_client::ssid("wlan0") { + Ok(ssid) => ssid, + Err(_) => "Not connected".to_string(), + }; + let wlan_state = match network_client::state("wlan0") { + Ok(state) => state, + Err(_) => "Interface unavailable".to_string(), + }; + let wlan_status = match network_client::status("wlan0") { + Ok(status) => status, + Err(_) => "Interface unavailable".to_string(), + }; + let wlan_traffic = match network_client::traffic("wlan0") { + Ok(traffic) => { + let mut t = traffic; + // modify traffic values & assign measurement unit + // based on received and transmitted values + // if received > 999 MB, convert it to GB + if t.received > 1_047_527_424 { + t.received /= 1_073_741_824; + t.rx_unit = Some("GB".to_string()); + } else if t.received > 0 { + // otherwise, convert it to MB + t.received = (t.received / 1024) / 1024; + t.rx_unit = Some("MB".to_string()); + } else { + t.received = 0; + t.rx_unit = Some("MB".to_string()); + } + + if t.transmitted > 1_047_527_424 { + t.transmitted /= 1_073_741_824; + t.tx_unit = Some("GB".to_string()); + } else if t.transmitted > 0 { + t.transmitted = (t.transmitted / 1024) / 1024; + t.tx_unit = Some("MB".to_string()); + } else { + t.transmitted = 0; + t.tx_unit = Some("MB".to_string()); + } + Some(t) + } + Err(_) => None, + }; + // create a hashmap to combine wlan_list & wlan_scan without repetition + let mut wlan_networks = HashMap::new(); + for ap in wlan_scan { + let ssid = ap.ssid.clone(); + let rssi = ap.signal_level.clone(); + // parse the string to a signed integer (for math) + let rssi_parsed = rssi.parse::().unwrap(); + // perform rssi (dBm) to quality (%) conversion + let quality_percent = 2 * (rssi_parsed + 100); + let ap_detail = AccessPoint { + detail: Some(ap), + state: "Available".to_string(), + signal: Some(quality_percent), + }; + wlan_networks.insert(ssid, ap_detail); + } + for network in wlan_list { + // avoid repetition by checking that ssid is not already in list + if !wlan_networks.contains_key(&network.ssid) { + let ssid = network.ssid.clone(); + let net_detail = AccessPoint { + detail: None, + state: "Not in range".to_string(), + signal: None, + }; + wlan_networks.insert(ssid, net_detail); + } + } + + NetworkDetailContext { + back: None, + flash_name: None, + flash_msg: None, + saved_aps, + selected: None, + title: None, + wlan_ip, + wlan_networks, + wlan_rssi, + wlan_ssid, + wlan_state, + wlan_status, + wlan_traffic, + } + } +} + +#[get("/network/wifi?")] +pub fn network_detail(ssid: &RawStr, flash: Option) -> Template { + // assign context through context_builder call + let mut context = NetworkDetailContext::build(); + context.back = Some("/network/wifi".to_string()); + context.title = Some("WiFi Network".to_string()); + // decode ssid from url + let decoded_ssid = percent_decode(ssid.as_bytes()).decode_utf8().unwrap(); + context.selected = Some(decoded_ssid.to_string()); + // check to see if there is a flash message to display + if let Some(flash) = flash { + // add flash message contents to the context object + context.flash_name = Some(flash.name().to_string()); + context.flash_msg = Some(flash.msg().to_string()); + }; + // template_dir is set in Rocket.toml + Template::render("network_detail", &context) +} + +// HELPERS AND ROUTES FOR /network/wifi/activate + +#[get("/network/wifi/activate")] +pub fn deploy_client() -> Flash { + // activate the wireless client + debug!("Activating WiFi client mode."); + match network_client::activate_client() { + Ok(_) => Flash::success(Redirect::to("/network"), "Activated WiFi client"), + Err(_) => Flash::error(Redirect::to("/network"), "Failed to activate WiFi client"), + } +} + +// HELPERS AND ROUTES FOR /network/wifi/add + +#[get("/network/wifi/add")] +pub fn network_add_wifi(flash: Option) -> Template { + let mut context = NetworkContext::build(); + // set back icon link to network route + context.back = Some("/network".to_string()); + context.title = Some("Add WiFi Network".to_string()); + // check to see if there is a flash message to display + if let Some(flash) = flash { + // add flash message contents to the context object + context.flash_name = Some(flash.name().to_string()); + context.flash_msg = Some(flash.msg().to_string()); + }; + // template_dir is set in Rocket.toml + Template::render("network_add", &context) +} + +// used in /network/wifi/add? +#[derive(Debug, Serialize)] +pub struct NetworkAddContext { + pub back: Option, + pub flash_name: Option, + pub flash_msg: Option, + pub selected: Option, + pub title: Option, +} + +impl NetworkAddContext { + pub fn build() -> NetworkAddContext { + NetworkAddContext { + back: None, + flash_name: None, + flash_msg: None, + selected: None, + title: None, + } + } +} + +#[get("/network/wifi/add?")] +pub fn network_add_ssid(ssid: &RawStr, flash: Option) -> Template { + // decode ssid from url + let decoded_ssid = percent_decode(ssid.as_bytes()).decode_utf8().unwrap(); + let mut context = NetworkAddContext::build(); + context.back = Some("/network/wifi".to_string()); + context.selected = Some(decoded_ssid.to_string()); + context.title = Some("Add WiFi Network".to_string()); + // check to see if there is a flash message to display + if let Some(flash) = flash { + // add flash message contents to the context object + context.flash_name = Some(flash.name().to_string()); + context.flash_msg = Some(flash.msg().to_string()); + }; + // template_dir is set in Rocket.toml + Template::render("network_add", &context) +} + +#[post("/network/wifi/add", data = "")] +pub fn add_credentials(wifi: Form) -> Template { + // check if the credentials already exist for this access point + // note: this is nicer but it's an unstable feature: + // if check_saved_aps(&wifi.ssid).contains(true) + // use unwrap_or instead, set value to false if err is returned + let creds_exist = network_client::saved_ap(&wifi.ssid).unwrap_or(false); + if creds_exist { + let mut context = NetworkAddContext::build(); + context.back = Some("/network".to_string()); + context.flash_name = Some("error".to_string()); + context.flash_msg = + Some("Network credentials already exist for this access point".to_string()); + context.title = Some("Add WiFi Network".to_string()); + // return early from handler with "creds already exist" message + return Template::render("network_add", &context); + }; + + // if credentials not found, generate and write wifi config to wpa_supplicant + match network_client::add(&wifi.ssid, &wifi.pass) { + Ok(_) => { + debug!("Added WiFi credentials."); + // force reread of wpa_supplicant.conf file with new credentials + match network_client::reconfigure() { + Ok(_) => debug!("Successfully reconfigured wpa_supplicant"), + Err(_) => warn!("Failed to reconfigure wpa_supplicant"), + } + let mut context = NetworkAddContext::build(); + context.back = Some("/network".to_string()); + context.flash_name = Some("success".to_string()); + context.flash_msg = Some("Added WiFi credentials".to_string()); + context.title = Some("Add WiFi Network".to_string()); + Template::render("network_add", &context) + } + Err(_) => { + debug!("Failed to add WiFi credentials."); + let mut context = NetworkAddContext::build(); + context.back = Some("/network".to_string()); + context.flash_name = Some("error".to_string()); + context.flash_msg = Some("Failed to add WiFi credentials".to_string()); + context.title = Some("Add WiFi Network".to_string()); + Template::render("network_add", &context) + } + } +} + +// HELPERS AND ROUTES FOR WIFI USAGE + +#[derive(Debug, Serialize)] +pub struct NetworkAlertContext { + pub alert: Alert, + pub back: Option, + pub data_total: Data, // combined stored and current wifi traffic in bytes + pub flash_name: Option, + pub flash_msg: Option, + pub threshold: Threshold, + pub title: Option, + pub traffic: Traffic, // current wifi traffic in bytes (since boot) +} + +impl NetworkAlertContext { + pub fn build() -> NetworkAlertContext { + let alert = monitor::get_alerts().unwrap(); + // stored wifi data values as bytes + let stored_traffic = monitor::get_data().unwrap(); + let threshold = monitor::get_thresholds().unwrap(); + // current wifi traffic values as bytes + let traffic = match network_client::traffic("wlan0") { + Ok(t) => t, + Err(_) => Traffic { + received: 0, + transmitted: 0, + rx_unit: None, + tx_unit: None, + }, + }; + + let current_traffic = traffic.received + traffic.transmitted; + let total = stored_traffic.total + current_traffic; + let data_total = Data { total }; + + NetworkAlertContext { + alert, + back: None, + data_total, + flash_name: None, + flash_msg: None, + threshold, + title: None, + traffic, + } + } +} + +#[get("/network/wifi/usage")] +pub fn wifi_usage(flash: Option) -> Template { + let mut context = NetworkAlertContext::build(); + // set back icon link to network route + context.back = Some("/network".to_string()); + context.title = Some("Network Data Usage".to_string()); + // check to see if there is a flash message to display + if let Some(flash) = flash { + // add flash message contents to the context object + context.flash_name = Some(flash.name().to_string()); + context.flash_msg = Some(flash.msg().to_string()); + }; + // template_dir is set in Rocket.toml + Template::render("network_usage", &context) +} + +#[post("/network/wifi/usage", data = "")] +pub fn wifi_usage_alerts(thresholds: Form) -> Flash { + match monitor::update_store(thresholds.into_inner()) { + Ok(_) => { + debug!("WiFi data usage thresholds updated."); + Flash::success( + Redirect::to("/network/wifi/usage"), + "Updated alert thresholds and flags", + ) + } + Err(_) => { + warn!("Failed to update WiFi data usage thresholds."); + Flash::error( + Redirect::to("/network/wifi/usage"), + "Failed to update alert thresholds and flags", + ) + } + } +} + +#[post("/api/v1/network/wifi/usage", data = "")] +pub fn update_wifi_alerts(thresholds: Json) -> Json { + match monitor::update_store(thresholds.into_inner()) { + Ok(_) => { + debug!("WiFi data usage thresholds updated."); + let status = "success".to_string(); + let msg = "Updated alert threshold and flags.".to_string(); + Json(build_json_response(status, None, Some(msg))) + } + Err(_) => { + warn!("Failed to update WiFi data usage thresholds."); + let status = "error".to_string(); + let msg = "Failed to update WiFi data usage thresholds.".to_string(); + Json(build_json_response(status, None, Some(msg))) + } + } +} + +#[post("/api/v1/network/wifi/usage/reset")] +pub fn reset_data_total() -> Json { + match monitor::reset_data() { + Ok(_) => { + debug!("Reset network data usage total."); + let traffic = match network_client::traffic("wlan0") { + Ok(t) => t, + Err(_) => Traffic { + received: 0, + transmitted: 0, + rx_unit: None, + tx_unit: None, + }, + }; + // current wifi traffic values as bytes + let current_traffic = traffic.received + traffic.transmitted; + let data = json!(current_traffic); + let status = "success".to_string(); + let msg = "Reset network data usage total.".to_string(); + Json(build_json_response(status, Some(data), Some(msg))) + } + Err(_) => { + warn!("Failed to reset network data usage total."); + let status = "error".to_string(); + let msg = "Failed to reset network data usage total.".to_string(); + Json(build_json_response(status, None, Some(msg))) + } + } +} + +// HELPERS AND ROUTES FOR ACCESS POINT ACTIVATION + +#[post("/api/v1/network/activate_ap")] +pub fn activate_ap() -> Json { + // activate the wireless access point + debug!("Activating WiFi access point."); + match network_client::activate_ap() { + Ok(_) => { + let status = "success".to_string(); + Json(build_json_response(status, None, None)) + } + Err(_) => { + let status = "error".to_string(); + let msg = "Failed to activate WiFi access point.".to_string(); + Json(build_json_response(status, None, Some(msg))) + } + } +} + +// HELPERS AND ROUTES FOR WIFI CLIENT MANAGEMENT + +#[post("/api/v1/network/activate_client")] +pub fn activate_client() -> Json { + // activate the wireless client + debug!("Activating WiFi client mode."); + match network_client::activate_client() { + Ok(_) => { + let status = "success".to_string(); + Json(build_json_response(status, None, None)) + } + Err(_) => { + let status = "error".to_string(); + let msg = "Failed to activate WiFi client mode.".to_string(); + Json(build_json_response(status, None, Some(msg))) + } + } +} + +#[post("/api/v1/network/wifi", data = "")] +pub fn add_wifi(wifi: Json) -> Json { + // generate and write wifi config to wpa_supplicant + match network_client::add(&wifi.ssid, &wifi.pass) { + Ok(_) => { + debug!("Added WiFi credentials."); + // force reread of wpa_supplicant.conf file with new credentials + match network_client::reconfigure() { + Ok(_) => debug!("Successfully reconfigured wpa_supplicant."), + Err(_) => warn!("Failed to reconfigure wpa_supplicant."), + } + // json response for successful update + let status = "success".to_string(); + let msg = "WiFi credentials added.".to_string(); + Json(build_json_response(status, None, Some(msg))) + } + Err(_) => { + debug!("Failed to add WiFi credentials."); + // json response for failed update + let status = "error".to_string(); + let msg = "Failed to add WiFi credentials.".to_string(); + Json(build_json_response(status, None, Some(msg))) + } + } +} + +#[post("/api/v1/network/wifi/connect", data = "")] +pub fn connect_ap(ssid: Json) -> Json { + // retrieve the id for the given network ssid + match network_client::id("wlan0", &ssid.ssid) { + // attempt connection with the given network + Ok(id) => match network_client::connect(&id, "wlan0") { + Ok(_) => { + let status = "success".to_string(); + let msg = "Connected to chosen network.".to_string(); + Json(build_json_response(status, None, Some(msg))) + } + Err(_) => { + let status = "error".to_string(); + let msg = "Failed to connect to chosen network.".to_string(); + Json(build_json_response(status, None, Some(msg))) + } + }, + Err(_) => { + let status = "error".to_string(); + let msg = "Failed to retrieve the network ID.".to_string(); + Json(build_json_response(status, None, Some(msg))) + } + } +} + +#[post("/api/v1/network/wifi/disconnect", data = "")] +pub fn disconnect_ap(ssid: Json) -> Json { + // attempt to disable the current network for wlan0 interface + match network_client::disable("wlan0", &ssid.ssid) { + Ok(_) => { + let status = "success".to_string(); + let msg = "Disconnected from WiFi network.".to_string(); + Json(build_json_response(status, None, Some(msg))) + } + Err(_) => { + let status = "error".to_string(); + let msg = "Failed to disconnect from WiFi network.".to_string(); + Json(build_json_response(status, None, Some(msg))) + } + } +} + +#[post("/api/v1/network/wifi/forget", data = "")] +pub fn forget_ap(network: Json) -> Json { + let ssid = &network.ssid; + match network_client::forget("wlan0", ssid) { + Ok(_) => { + debug!("Removed WiFi credentials for chosen network."); + let status = "success".to_string(); + let msg = "WiFi network credentials removed.".to_string(); + Json(build_json_response(status, None, Some(msg))) + } + Err(_) => { + warn!("Failed to remove WiFi credentials."); + let status = "error".to_string(); + let msg = "Failed to remove WiFi network credentials.".to_string(); + Json(build_json_response(status, None, Some(msg))) + } + } +} + +#[post("/api/v1/network/wifi/modify", data = "")] +pub fn modify_password(wifi: Json) -> Json { + let ssid = &wifi.ssid; + let pass = &wifi.pass; + // we are using a helper function (`update`) to delete the old + // credentials and add the new ones. this is because the wpa_cli method + // for updating the password does not work. + match network_client::update("wlan0", ssid, pass) { + Ok(_) => { + debug!("WiFi password updated for chosen network."); + let status = "success".to_string(); + let msg = "WiFi password updated.".to_string(); + Json(build_json_response(status, None, Some(msg))) + } + Err(_) => { + warn!("Failed to update WiFi password."); + let status = "error".to_string(); + let msg = "Failed to update WiFi password.".to_string(); + Json(build_json_response(status, None, Some(msg))) + } + } +} + +// HELPERS AND ROUTES FOR NETWORK STATE QUERIES + +#[get("/api/v1/network/ip")] +pub fn return_ip() -> Json { + // retrieve ip for wlan0 or set to x.x.x.x if not found + let wlan_ip = match network_client::ip("wlan0") { + Ok(ip) => ip, + Err(_) => "x.x.x.x".to_string(), + }; + // retrieve ip for ap0 or set to x.x.x.x if not found + let ap_ip = match network_client::ip("ap0") { + Ok(ip) => ip, + Err(_) => "x.x.x.x".to_string(), + }; + let data = json!({ + "wlan0": wlan_ip, + "ap0": ap_ip + }); + let status = "success".to_string(); + Json(build_json_response(status, Some(data), None)) +} + +#[get("/api/v1/network/rssi")] +pub fn return_rssi() -> Json { + // retrieve rssi for connected network + match network_client::rssi("wlan0") { + Ok(rssi) => { + let status = "success".to_string(); + let data = json!(rssi); + Json(build_json_response(status, Some(data), None)) + } + Err(_) => { + let status = "success".to_string(); + let msg = "Not currently connected to an access point.".to_string(); + Json(build_json_response(status, None, Some(msg))) + } + } +} + +#[get("/api/v1/network/ssid")] +pub fn return_ssid() -> Json { + // retrieve ssid for connected network + match network_client::ssid("wlan0") { + Ok(network) => { + let status = "success".to_string(); + let data = json!(network); + Json(build_json_response(status, Some(data), None)) + } + Err(_) => { + let status = "success".to_string(); + let msg = "Not currently connected to an access point.".to_string(); + Json(build_json_response(status, None, Some(msg))) + } + } +} + +#[get("/api/v1/network/state")] +pub fn return_state() -> Json { + // retrieve state of wlan0 or set to x.x.x.x if not found + let wlan_state = match network_client::state("wlan0") { + Ok(state) => state, + Err(_) => "unavailable".to_string(), + }; + // retrieve state for ap0 or set to x.x.x.x if not found + let ap_state = match network_client::state("ap0") { + Ok(state) => state, + Err(_) => "unavailable".to_string(), + }; + let data = json!({ + "wlan0": wlan_state, + "ap0": ap_state + }); + let status = "success".to_string(); + Json(build_json_response(status, Some(data), None)) +} + +#[get("/api/v1/network/status")] +pub fn return_status() -> Json { + // retrieve status info for wlan0 interface + match network_client::status("wlan0") { + Ok(network) => { + let status = "success".to_string(); + let data = json!(network); + Json(build_json_response(status, Some(data), None)) + } + Err(_) => { + let status = "success".to_string(); + let msg = "Not currently connected to an access point.".to_string(); + Json(build_json_response(status, None, Some(msg))) + } + } +} + +#[get("/api/v1/network/wifi")] +pub fn scan_networks() -> Json { + // retrieve scan results for access-points within range of wlan0 + match network_client::available_networks("wlan0") { + Ok(networks) => { + let status = "success".to_string(); + let data = json!(networks); + Json(build_json_response(status, Some(data), None)) + } + Err(_) => { + let status = "success".to_string(); + let msg = "Unable to scan for networks. Interface may be deactivated.".to_string(); + Json(build_json_response(status, None, Some(msg))) + } + } +} diff --git a/peach-web/src/tests.rs b/peach-web/src/tests.rs index 42d3197..a6402ae 100644 --- a/peach-web/src/tests.rs +++ b/peach-web/src/tests.rs @@ -5,8 +5,9 @@ use rocket::http::{ContentType, Status}; use rocket::local::Client; use rocket_contrib::json; +use crate::utils::build_json_response; + use super::rocket; -use crate::json_api::build_json_response; // helper function to test correct retrieval and content of a file fn test_query_file(path: &str, file: T, status: Status) diff --git a/peach-web/src/utils.rs b/peach-web/src/utils.rs new file mode 100644 index 0000000..aee2f14 --- /dev/null +++ b/peach-web/src/utils.rs @@ -0,0 +1,29 @@ +pub mod monitor; + +use rocket_contrib::json::JsonValue; +use serde::Serialize; + +// HELPER FUNCTIONS + +#[derive(Serialize)] +pub struct JsonResponse { + pub status: String, + #[serde(skip_serializing_if = "Option::is_none")] + pub data: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub msg: Option, +} + +pub fn build_json_response( + status: String, + data: Option, + msg: Option, +) -> JsonResponse { + JsonResponse { status, data, msg } +} + +#[derive(Debug, Serialize)] +pub struct FlashContext { + pub flash_name: Option, + pub flash_msg: Option, +} diff --git a/peach-web/src/monitor.rs b/peach-web/src/utils/monitor.rs similarity index 100% rename from peach-web/src/monitor.rs rename to peach-web/src/utils/monitor.rs diff --git a/peach-web/src/ws.rs b/peach-web/src/ws.rs index 50591a0..fb83b89 100644 --- a/peach-web/src/ws.rs +++ b/peach-web/src/ws.rs @@ -9,12 +9,12 @@ use websocket::sync::Server; use websocket::{Message, OwnedMessage}; pub fn websocket_server(address: String) -> io::Result<()> { - // Start listening for WebSocket connections + // start listening for WebSocket connections let ws_server = Server::bind(address)?; info!("Listening for WebSocket connections."); for connection in ws_server.filter_map(Result::ok) { - // Spawn a new thread for each connection. + // spawn a new thread for each connection thread::spawn(move || { if !connection .protocols()