diff --git a/Cargo.lock b/Cargo.lock index e0c301e..34d4ec6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -26,6 +26,21 @@ dependencies = [ "memchr", ] +[[package]] +name = "android-tzdata" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" + +[[package]] +name = "android_system_properties" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", +] + [[package]] name = "async-trait" version = "0.1.80" @@ -51,13 +66,19 @@ checksum = "26b05800d2e817c8b3b4b54abd461726265fa9789ae34330622f2db9ee696f9d" dependencies = [ "addr2line", "cc", - "cfg-if 1.0.0", + "cfg-if", "libc", "miniz_oxide", "object", "rustc-demangle", ] +[[package]] +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + [[package]] name = "bitflags" version = "1.3.2" @@ -71,21 +92,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1" [[package]] -name = "byteorder" -version = "1.5.0" +name = "bumpalo" +version = "3.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" - -[[package]] -name = "bytes" -version = "0.4.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "206fdffcfa2df7cbe15601ef46c813fce0965eb3286db6b56c583b814b51c81c" -dependencies = [ - "byteorder", - "either", - "iovec", -] +checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" [[package]] name = "bytes" @@ -99,12 +109,6 @@ version = "1.0.95" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d32a725bc159af97c3e629873bb9f88fb8cf8a4867175f76dc987815ea07c83b" -[[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" @@ -112,12 +116,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] -name = "cloudabi" -version = "0.0.3" +name = "chrono" +version = "0.4.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" +checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401" dependencies = [ - "bitflags 1.3.2", + "android-tzdata", + "iana-time-zone", + "js-sys", + "num-traits", + "wasm-bindgen", + "windows-targets 0.52.4", ] [[package]] @@ -136,54 +145,6 @@ version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" -[[package]] -name = "crossbeam-deque" -version = "0.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c20ff29ded3204c5106278a81a38f4b482636ed4fa1e6cfbeef193291beb29ed" -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", - "cfg-if 0.1.10", - "crossbeam-utils", - "lazy_static", - "maybe-uninit", - "memoffset", - "scopeguard", -] - -[[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", - "cfg-if 0.1.10", - "lazy_static", -] - [[package]] name = "ctor" version = "0.2.8" @@ -204,12 +165,6 @@ dependencies = [ "serde", ] -[[package]] -name = "either" -version = "1.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3dca9240753cf90908d7e4aac30f630662b02aebaa1b58a3cadabdb23385b58b" - [[package]] name = "env_logger" version = "0.10.2" @@ -266,28 +221,6 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" -[[package]] -name = "fuchsia-zircon" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82" -dependencies = [ - "bitflags 1.3.2", - "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.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a471a38ef8ed83cd6e40aa59c1ffe17db6855c18e3604d9c4ed8c08ebc28678" - [[package]] name = "futures-channel" version = "0.3.30" @@ -303,16 +236,6 @@ version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" -[[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 = "futures-sink" version = "0.3.30" @@ -343,9 +266,9 @@ version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94b22e06ecb0110981051723910cbf0b5f5e09a2062dd7663334ee79a9d1286c" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "libc", - "wasi 0.11.0+wasi-snapshot-preview1", + "wasi", ] [[package]] @@ -354,49 +277,25 @@ version = "0.28.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" -[[package]] -name = "h2" -version = "0.1.26" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5b34c246847f938a410a03c5458c7fee2274436675e76d8b903c08efc29c462" -dependencies = [ - "byteorder", - "bytes 0.4.12", - "fnv", - "futures", - "http 0.1.21", - "indexmap 1.9.3", - "log", - "slab", - "string", - "tokio-io", -] - [[package]] name = "h2" version = "0.3.26" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "81fe527a889e1532da5c525686d96d4c2e74cdd345badf8dfef9f6b39dd5f5e8" dependencies = [ - "bytes 1.6.0", + "bytes", "fnv", "futures-core", "futures-sink", "futures-util", - "http 0.2.12", - "indexmap 2.2.6", + "http", + "indexmap", "slab", - "tokio 1.37.0", + "tokio", "tokio-util", "tracing", ] -[[package]] -name = "hashbrown" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" - [[package]] name = "hashbrown" version = "0.14.3" @@ -409,49 +308,15 @@ version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d77f7ec81a6d05a3abb01ab6eb7590f6083d08449fe5a1c8b1e620283546ccb7" -[[package]] -name = "http" -version = "0.1.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6ccf5ede3a895d8856620237b2f02972c1bbc78d2965ad7fe8838d4a0ed41f0" -dependencies = [ - "bytes 0.4.12", - "fnv", - "itoa 0.4.8", -] - [[package]] name = "http" version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1" dependencies = [ - "bytes 1.6.0", + "bytes", "fnv", - "itoa 1.0.11", -] - -[[package]] -name = "http" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21b9ddb458710bc376481b842f5da65cdf31522de232c1ca8146abce2a358258" -dependencies = [ - "bytes 1.6.0", - "fnv", - "itoa 1.0.11", -] - -[[package]] -name = "http-body" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6741c859c1b2463a423a1dbce98d418e6c3c3fc720fb0d45528657320920292d" -dependencies = [ - "bytes 0.4.12", - "futures", - "http 0.1.21", - "tokio-buf", + "itoa", ] [[package]] @@ -460,44 +325,11 @@ version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" dependencies = [ - "bytes 1.6.0", - "http 0.2.12", + "bytes", + "http", "pin-project-lite", ] -[[package]] -name = "http-body" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cac85db508abc24a2e48553ba12a996e87244a0395ce011e62b37158745d643" -dependencies = [ - "bytes 1.6.0", - "http 1.1.0", -] - -[[package]] -name = "http-body-util" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0475f8b2ac86659c21b64320d5d653f9efe42acd2a4e560073ec61a155a34f1d" -dependencies = [ - "bytes 1.6.0", - "futures-core", - "http 1.1.0", - "http-body 1.0.0", - "pin-project-lite", -] - -[[package]] -name = "http-connection" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f6080cea47f7371d4da9a46dd52787c598ce93886393e400bc178f9039bac27" -dependencies = [ - "http 0.1.21", - "tokio-tcp", -] - [[package]] name = "httparse" version = "1.8.0" @@ -516,58 +348,28 @@ version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" -[[package]] -name = "hyper" -version = "0.12.36" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c843caf6296fc1f93444735205af9ed4e109a539005abb2564ae1d6fad34c52" -dependencies = [ - "bytes 0.4.12", - "futures", - "futures-cpupool", - "h2 0.1.26", - "http 0.1.21", - "http-body 0.1.0", - "httparse", - "iovec", - "itoa 0.4.8", - "log", - "net2", - "rustc_version", - "time 0.1.45", - "tokio 0.1.22", - "tokio-buf", - "tokio-executor", - "tokio-io", - "tokio-reactor", - "tokio-tcp", - "tokio-threadpool", - "tokio-timer", - "want 0.2.0", -] - [[package]] name = "hyper" version = "0.14.28" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bf96e135eb83a2a8ddf766e426a841d8ddd7449d5f00d34ea02b41d2f19eef80" dependencies = [ - "bytes 1.6.0", + "bytes", "futures-channel", "futures-core", "futures-util", - "h2 0.3.26", - "http 0.2.12", - "http-body 0.4.6", + "h2", + "http", + "http-body", "httparse", "httpdate", - "itoa 1.0.11", + "itoa", "pin-project-lite", "socket2", - "tokio 1.37.0", - "tower-service 0.3.2", + "tokio", + "tower-service", "tracing", - "want 0.3.1", + "want", ] [[package]] @@ -576,21 +378,34 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905" dependencies = [ - "bytes 1.6.0", - "hyper 0.14.28", + "bytes", + "hyper", "native-tls", - "tokio 1.37.0", + "tokio", "tokio-native-tls", ] [[package]] -name = "indexmap" -version = "1.9.3" +name = "iana-time-zone" +version = "0.1.60" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" +checksum = "e7ffbb5a1b541ea2561f8c41c087286cc091e21e556a4f09a8f6cbf17b69b141" dependencies = [ - "autocfg", - "hashbrown 0.12.3", + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "wasm-bindgen", + "windows-core", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +dependencies = [ + "cc", ] [[package]] @@ -600,16 +415,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26" dependencies = [ "equivalent", - "hashbrown 0.14.3", -] - -[[package]] -name = "iovec" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2b3ea6ff95e175473f8ffe6a7eb7c00d054240321b84c57051175fe3c1e075e" -dependencies = [ - "libc", + "hashbrown", ] [[package]] @@ -623,12 +429,6 @@ dependencies = [ "windows-sys 0.52.0", ] -[[package]] -name = "itoa" -version = "0.4.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4" - [[package]] name = "itoa" version = "1.0.11" @@ -636,13 +436,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" [[package]] -name = "kernel32-sys" -version = "0.2.2" +name = "js-sys" +version = "0.3.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" +checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d" dependencies = [ - "winapi 0.2.8", - "winapi-build", + "wasm-bindgen", ] [[package]] @@ -650,19 +449,18 @@ name = "kordophone" version = "0.1.0" dependencies = [ "async-trait", + "base64", + "chrono", "ctor", - "hyper 0.14.28", + "hyper", "hyper-tls", "log", "pretty_env_logger", "serde", "serde_json", "serde_plain", - "time 0.3.36", - "tokio 1.37.0", - "tower", - "tower-http", - "tower-hyper", + "time", + "tokio", "uuid", ] @@ -684,15 +482,6 @@ version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c" -[[package]] -name = "lock_api" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4da24a77a3d8a6d4862d95f72e6fdb9c09a643ecdb402d754004a557f2bec75" -dependencies = [ - "scopeguard", -] - [[package]] name = "lock_api" version = "0.4.11" @@ -709,27 +498,12 @@ version = "0.4.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" -[[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.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d" -[[package]] -name = "memoffset" -version = "0.5.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "043175f069eda7b85febe4a74abbaeff828d9f8b448515d3151a14a3542811aa" -dependencies = [ - "autocfg", -] - [[package]] name = "miniz_oxide" version = "0.7.2" @@ -739,25 +513,6 @@ dependencies = [ "adler", ] -[[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" version = "0.8.11" @@ -765,22 +520,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c" dependencies = [ "libc", - "wasi 0.11.0+wasi-snapshot-preview1", + "wasi", "windows-sys 0.48.0", ] -[[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 = "native-tls" version = "0.2.11" @@ -799,23 +542,21 @@ dependencies = [ "tempfile", ] -[[package]] -name = "net2" -version = "0.2.39" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b13b648036a2339d06de780866fbdfda0dde886de7b3af2ddeba8b14f4ee34ac" -dependencies = [ - "cfg-if 0.1.10", - "libc", - "winapi 0.3.9", -] - [[package]] name = "num-conv" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] + [[package]] name = "num_cpus" version = "1.16.0" @@ -848,7 +589,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "95a0481286a310808298130d22dd1fef0fa571e05a8f44ec801801e84b216b1f" dependencies = [ "bitflags 2.5.0", - "cfg-if 1.0.0", + "cfg-if", "foreign-types", "libc", "once_cell", @@ -885,40 +626,14 @@ dependencies = [ "vcpkg", ] -[[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.3", - "rustc_version", -] - [[package]] name = "parking_lot" version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" dependencies = [ - "lock_api 0.4.11", - "parking_lot_core 0.9.9", -] - -[[package]] -name = "parking_lot_core" -version = "0.6.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bda66b810a62be75176a80873726630147a5ca780cd33921e0b5709033e66b0a" -dependencies = [ - "cfg-if 0.1.10", - "cloudabi", - "libc", - "redox_syscall 0.1.57", - "rustc_version", - "smallvec 0.6.14", - "winapi 0.3.9", + "lock_api", + "parking_lot_core", ] [[package]] @@ -927,10 +642,10 @@ version = "0.9.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4c42a9226546d68acdd9c0a280d17ce19bfe27a46bf68784e4066115788d008e" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "libc", - "redox_syscall 0.4.1", - "smallvec 1.11.2", + "redox_syscall", + "smallvec", "windows-targets 0.48.5", ] @@ -1022,12 +737,6 @@ dependencies = [ "getrandom", ] -[[package]] -name = "redox_syscall" -version = "0.1.57" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce" - [[package]] name = "redox_syscall" version = "0.4.1" @@ -1072,15 +781,6 @@ version = "0.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" -[[package]] -name = "rustc_version" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" -dependencies = [ - "semver", -] - [[package]] name = "rustix" version = "0.38.34" @@ -1138,21 +838,6 @@ dependencies = [ "libc", ] -[[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.198" @@ -1179,7 +864,7 @@ version = "1.0.116" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3e17db7126d17feb94eb3fad46bf1a96b034e8aacbc2e775fe81505f8b0b2813" dependencies = [ - "itoa 1.0.11", + "itoa", "ryu", "serde", ] @@ -1211,15 +896,6 @@ dependencies = [ "autocfg", ] -[[package]] -name = "smallvec" -version = "0.6.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b97fcaeba89edba30f044a10c6a3cc39df9c3f17d7cd829dd1446cab35f890e0" -dependencies = [ - "maybe-uninit", -] - [[package]] name = "smallvec" version = "1.11.2" @@ -1236,15 +912,6 @@ dependencies = [ "windows-sys 0.52.0", ] -[[package]] -name = "string" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d24114bfcceb867ca7f71a0d3fe45d45619ec47a6fbfa98cb14e14250bfa5d6d" -dependencies = [ - "bytes 0.4.12", -] - [[package]] name = "syn" version = "2.0.60" @@ -1262,7 +929,7 @@ version = "3.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "85b77fafb263dd9d05cbeac119526425676db3784113aa9295c88498cbf8bff1" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "fastrand", "rustix", "windows-sys 0.52.0", @@ -1277,17 +944,6 @@ dependencies = [ "winapi-util", ] -[[package]] -name = "time" -version = "0.1.45" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b797afad3f312d1c66a56d11d0316f916356d11bd158fbc6ca6389ff6bf805a" -dependencies = [ - "libc", - "wasi 0.10.0+wasi-snapshot-preview1", - "winapi 0.3.9", -] - [[package]] name = "time" version = "0.3.36" @@ -1318,24 +974,6 @@ dependencies = [ "time-core", ] -[[package]] -name = "tokio" -version = "0.1.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a09c0b5bb588872ab2f09afa13ee6e9dac11e10a0ec9e8e3ba39a5a5d530af6" -dependencies = [ - "bytes 0.4.12", - "futures", - "mio 0.6.23", - "num_cpus", - "tokio-current-thread", - "tokio-executor", - "tokio-io", - "tokio-reactor", - "tokio-threadpool", - "tokio-timer", -] - [[package]] name = "tokio" version = "1.37.0" @@ -1343,11 +981,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1adbebffeca75fcfd058afa480fb6c0b81e165a0323f9c9d39c9697e37c46787" dependencies = [ "backtrace", - "bytes 1.6.0", + "bytes", "libc", - "mio 0.8.11", + "mio", "num_cpus", - "parking_lot 0.12.1", + "parking_lot", "pin-project-lite", "signal-hook-registry", "socket2", @@ -1355,48 +993,6 @@ dependencies = [ "windows-sys 0.48.0", ] -[[package]] -name = "tokio-buf" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fb220f46c53859a4b7ec083e41dec9778ff0b1851c0942b211edb89e0ccdc46" -dependencies = [ - "bytes 0.4.12", - "either", - "futures", -] - -[[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-io" -version = "0.1.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57fc868aae093479e3131e3d165c93b1c7474109d13c90ec0dda2a1bbfff0674" -dependencies = [ - "bytes 0.4.12", - "futures", - "log", -] - [[package]] name = "tokio-macros" version = "2.2.0" @@ -1415,79 +1011,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2" dependencies = [ "native-tls", - "tokio 1.37.0", -] - -[[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 0.6.23", - "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 0.4.12", - "futures", - "iovec", - "mio 0.6.23", - "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", + "tokio", ] [[package]] @@ -1496,126 +1020,26 @@ version = "0.7.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5419f34732d9eb6ee4c3578b7989078579b7f039cbbb9ca2c4da015749371e15" dependencies = [ - "bytes 1.6.0", + "bytes", "futures-core", "futures-sink", "pin-project-lite", - "tokio 1.37.0", + "tokio", "tracing", ] -[[package]] -name = "tower" -version = "0.4.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c" -dependencies = [ - "tower-layer 0.3.2", - "tower-service 0.3.2", - "tracing", -] - -[[package]] -name = "tower-http" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e9cd434a998747dd2c4276bc96ee2e0c7a2eadf3cae88e52be55a05fa9053f5" -dependencies = [ - "bitflags 2.5.0", - "bytes 1.6.0", - "http 1.1.0", - "http-body 1.0.0", - "http-body-util", - "pin-project-lite", - "tower-layer 0.3.2", - "tower-service 0.3.2", - "tracing", -] - -[[package]] -name = "tower-http-util" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "442ba79e23bda499cdaa5ee52b3776bf08cb84a1d5ca6d3d82bfd4f12c1eefc3" -dependencies = [ - "futures", - "http 0.1.21", - "http-body 0.1.0", - "http-connection", - "tokio-buf", - "tokio-io", - "tower-service 0.2.0", -] - -[[package]] -name = "tower-hyper" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cff60538bc14baa9cc84fbe4c040d498163daf23bc9846a9aef0e2e40dcc1d51" -dependencies = [ - "futures", - "http 0.1.21", - "http-body 0.1.0", - "http-connection", - "hyper 0.12.36", - "log", - "tokio-buf", - "tokio-executor", - "tokio-io", - "tower-http-util", - "tower-service 0.2.0", - "tower-util", -] - -[[package]] -name = "tower-layer" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ddf07e10c07dcc8f41da6de036dc66def1a85b70eb8a385159e3908bb258328" -dependencies = [ - "futures", - "tower-service 0.2.0", -] - -[[package]] -name = "tower-layer" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c20c8dbed6283a09604c3e69b4b7eeb54e298b8a600d4d5ecb5ad39de609f1d0" - -[[package]] -name = "tower-service" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2cc0c98637d23732f8de6dfd16494c9f1559c3b9e20b4a46462c8f9b9e827bfa" -dependencies = [ - "futures", -] - [[package]] name = "tower-service" version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" -[[package]] -name = "tower-util" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4792342fac093db5d2558655055a89a04ca909663467a4310c7739d9f8b64698" -dependencies = [ - "futures", - "tower-layer 0.1.0", - "tower-service 0.2.0", -] - [[package]] name = "tracing" version = "0.1.40" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" dependencies = [ - "log", "pin-project-lite", "tracing-core", ] @@ -1669,17 +1093,6 @@ version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" -[[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 = "want" version = "0.3.1" @@ -1689,12 +1102,6 @@ dependencies = [ "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 = "wasi" version = "0.11.0+wasi-snapshot-preview1" @@ -1702,32 +1109,58 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] -name = "winapi" -version = "0.2.8" +name = "wasm-bindgen" +version = "0.2.92" 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" +checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8" dependencies = [ - "winapi-i686-pc-windows-gnu", - "winapi-x86_64-pc-windows-gnu", + "cfg-if", + "wasm-bindgen-macro", ] [[package]] -name = "winapi-build" -version = "0.1.1" +name = "wasm-bindgen-backend" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" +checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da" +dependencies = [ + "bumpalo", + "log", + "once_cell", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] [[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" +name = "wasm-bindgen-macro" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" +checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" [[package]] name = "winapi-util" @@ -1739,10 +1172,13 @@ dependencies = [ ] [[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" +name = "windows-core" +version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" +dependencies = [ + "windows-targets 0.52.4", +] [[package]] name = "windows-sys" @@ -1875,13 +1311,3 @@ name = "windows_x86_64_msvc" version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32b752e52a2da0ddfbdbcc6fceadfeede4c939ed16d13e648833a61dfb611ed8" - -[[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/kordophone/Cargo.toml b/kordophone/Cargo.toml index c527300..cc21210 100644 --- a/kordophone/Cargo.toml +++ b/kordophone/Cargo.toml @@ -7,6 +7,8 @@ edition = "2021" [dependencies] async-trait = "0.1.80" +base64 = "0.22.1" +chrono = "0.4.38" ctor = "0.2.8" hyper = { version = "0.14", features = ["full"] } hyper-tls = "0.5.0" @@ -17,7 +19,4 @@ serde_json = "1.0.91" serde_plain = "1.0.2" time = { version = "0.3.17", features = ["parsing", "serde"] } tokio = { version = "1.37.0", features = ["full"] } -tower = "0.4.13" -tower-http = { version = "0.5.2", features = ["trace"] } -tower-hyper = "0.1.1" uuid = { version = "1.6.1", features = ["v4", "fast-rng", "macro-diagnostics"] } diff --git a/kordophone/src/api/http_client.rs b/kordophone/src/api/http_client.rs index 96b5c91..c500715 100644 --- a/kordophone/src/api/http_client.rs +++ b/kordophone/src/api/http_client.rs @@ -1,24 +1,31 @@ extern crate hyper; extern crate serde; -use std::{path::PathBuf, str}; +use std::{borrow::Cow, default, path::PathBuf, str}; use log::{error}; -use hyper::{Body, Client, Method, Request, Uri}; -use tower::{ServiceBuilder}; +use hyper::{client::ResponseFuture, Body, Client, Method, Request, Uri}; use async_trait::async_trait; -use serde::de::DeserializeOwned; +use serde::{de::DeserializeOwned, Deserialize, Serialize}; -use crate::{APIInterface, model::Conversation}; +use crate::{model::{Conversation, JwtToken}, APIInterface}; type HttpClient = Client; -pub struct HTTPClient { +pub struct HTTPAPIClient { pub base_url: Uri, + credentials: Option, + auth_token: Option, client: HttpClient, } +#[derive(Clone, Serialize, Deserialize, Debug)] +pub struct Credentials { + pub username: String, + pub password: String, +} + #[derive(Debug)] pub enum Error { ClientError(String), @@ -39,29 +46,65 @@ impl From for Error { } } +trait AuthBuilder { + fn with_auth(self, token: &Option) -> Self; +} + +impl AuthBuilder for hyper::http::request::Builder { + fn with_auth(self, token: &Option) -> Self { + if let Some(token) = &token { + self.header("Authorization", token.to_header_value()) + } else { self } + } +} + +trait AuthSetting { + fn authenticate(&mut self, token: &Option); +} + +impl AuthSetting for hyper::http::Request { + fn authenticate(&mut self, token: &Option) { + if let Some(token) = &token { + self.headers_mut().insert("Authorization", token.to_header_value()); + } + } +} + #[async_trait] -impl APIInterface for HTTPClient { +impl APIInterface for HTTPAPIClient { type Error = Error; - async fn get_version(&self) -> Result { + async fn get_version(&mut self) -> Result { let version: String = self.request("/version", Method::GET).await?; Ok(version) } - async fn get_conversations(&self) -> Result, Self::Error> { + async fn get_conversations(&mut self) -> Result, Self::Error> { let conversations: Vec = self.request("/conversations", Method::GET).await?; Ok(conversations) } + + async fn authenticate(&mut self, credentials: Credentials) -> Result { + #[derive(Deserialize, Debug)] + struct AuthResponse { + jwt: String, + } + + let body = || -> Body { serde_json::to_string(&credentials).unwrap().into() }; + let token: AuthResponse = self.request_with_body_retry("/authenticate", Method::POST, body, false).await?; + let token = JwtToken::new(&token.jwt).map_err(|_| Error::DecodeError)?; + self.auth_token = Some(token.clone()); + Ok(token) + } } -impl HTTPClient { - pub fn new(base_url: Uri) -> HTTPClient { - let client = ServiceBuilder::new() - .service(Client::new()); - - HTTPClient { - base_url, - client, +impl HTTPAPIClient { + pub fn new(base_url: Uri, credentials: Option) -> HTTPAPIClient { + HTTPAPIClient { + base_url: base_url, + credentials: credentials, + auth_token: Option::None, + client: Client::new(), } } @@ -74,29 +117,67 @@ impl HTTPClient { Uri::try_from(parts).unwrap() } - async fn request(&self, endpoint: &str, method: Method) -> Result { - self.request_with_body(endpoint, method, Body::empty()).await + async fn request(&mut self, endpoint: &str, method: Method) -> Result { + self.request_with_body(endpoint, method, || { Body::empty() }).await } - async fn request_with_body(&self, endpoint: &str, method: Method, body: Body) -> Result { + async fn request_with_body(&mut self, endpoint: &str, method: Method, body_fn: B) -> Result + where T: DeserializeOwned, B: Fn() -> Body + { + self.request_with_body_retry(endpoint, method, body_fn, true).await + } + + async fn request_with_body_retry( + &mut self, + endpoint: &str, + method: Method, + body_fn: B, + retry_auth: bool) -> Result + where + T: DeserializeOwned, + B: Fn() -> Body + { + use hyper::StatusCode; + let uri = self.uri_for_endpoint(endpoint); - let request = Request::builder() - .method(method) - .uri(uri) - .body(body) - .unwrap(); + let build_request = move |auth: &Option| { + let body = body_fn(); + Request::builder() + .method(&method) + .uri(&uri) + .with_auth(auth) + .body(body) + .expect("Unable to build request") + }; - let future = self.client.request(request); - let res = future.await?; - let status = res.status(); + let request = build_request(&self.auth_token); + let mut response = self.client.request(request).await?; + match response.status() { + StatusCode::OK => { /* cool */ }, - if status != hyper::StatusCode::OK { - let message = format!("Request failed ({:})", status); - return Err(Error::ClientError(message)); + // 401: Unauthorized. Token may have expired or is invalid. Attempt to renew. + StatusCode::UNAUTHORIZED => { + if !retry_auth { + return Err(Error::ClientError("Unauthorized".into())); + } + + if let Some(credentials) = &self.credentials { + self.authenticate(credentials.clone()).await?; + + let request = build_request(&self.auth_token); + response = self.client.request(request).await?; + } + }, + + // Other errors: bubble up. + _ => { + let message = format!("Request failed ({:})", response.status()); + return Err(Error::ClientError(message)); + } } // Read and parse response body - let body = hyper::body::to_bytes(res.into_body()).await?; + let body = hyper::body::to_bytes(response.into_body()).await?; let parsed: T = match serde_json::from_slice(&body) { Ok(result) => Ok(result), Err(json_err) => { @@ -121,13 +202,18 @@ mod test { log::set_max_level(log::LevelFilter::Trace); } - fn local_mock_client() -> HTTPClient { + fn local_mock_client() -> HTTPAPIClient { let base_url = "http://localhost:5738".parse().unwrap(); - HTTPClient::new(base_url) + let credentials = Credentials { + username: "test".to_string(), + password: "test".to_string(), + }; + + HTTPAPIClient::new(base_url, credentials.into()) } async fn mock_client_is_reachable() -> bool { - let client = local_mock_client(); + let mut client = local_mock_client(); let version = client.get_version().await; match version { @@ -146,7 +232,7 @@ mod test { return; } - let client = local_mock_client(); + let mut client = local_mock_client(); let version = client.get_version().await.unwrap(); assert!(version.starts_with("KordophoneMock-")); } @@ -158,7 +244,7 @@ mod test { return; } - let client = local_mock_client(); + let mut client = local_mock_client(); let conversations = client.get_conversations().await.unwrap(); assert!(!conversations.is_empty()); } diff --git a/kordophone/src/api/mod.rs b/kordophone/src/api/mod.rs index da28032..0cd5c99 100644 --- a/kordophone/src/api/mod.rs +++ b/kordophone/src/api/mod.rs @@ -1,17 +1,23 @@ use async_trait::async_trait; pub use crate::model::Conversation; +use crate::model::JwtToken; pub mod http_client; -pub use http_client::HTTPClient; +pub use http_client::HTTPAPIClient; + +use self::http_client::Credentials; #[async_trait] pub trait APIInterface { type Error; // (GET) /version - async fn get_version(&self) -> Result; + async fn get_version(&mut self) -> Result; // (GET) /conversations - async fn get_conversations(&self) -> Result, Self::Error>; + async fn get_conversations(&mut self) -> Result, Self::Error>; + + // (POST) /authenticate + async fn authenticate(&mut self, credentials: Credentials) -> Result; } diff --git a/kordophone/src/model/jwt.rs b/kordophone/src/model/jwt.rs new file mode 100644 index 0000000..6810c2e --- /dev/null +++ b/kordophone/src/model/jwt.rs @@ -0,0 +1,112 @@ +use std::error::Error; + +use base64::{ + engine::{self, general_purpose}, + Engine, +}; + +use chrono::{DateTime, Utc}; +use hyper::http::HeaderValue; +use serde::Deserialize; + +#[derive(Deserialize, Debug, Clone)] +struct JwtHeader { + alg: String, + typ: String, +} + +#[derive(Deserialize, Debug, Clone)] +enum ExpValue { + Integer(i64), + String(String), +} + +#[derive(Deserialize, Debug, Clone)] +struct JwtPayload { + exp: serde_json::Value, + iss: Option, + user: Option, +} + +#[derive(Debug, Clone)] +pub struct JwtToken { + header: JwtHeader, + payload: JwtPayload, + signature: Vec, + expiration_date: DateTime, + token: String, +} + +impl JwtToken { + fn decode_token_using_engine( + token: &str, + engine: engine::GeneralPurpose, + ) -> Result> { + let mut parts = token.split('.'); + let header = parts.next().unwrap(); + let payload = parts.next().unwrap(); + let signature = parts.next().unwrap(); + + let header = engine.decode(header)?; + let payload = engine.decode(payload)?; + let signature = engine.decode(signature)?; + + // Parse jwt header + let header: JwtHeader = serde_json::from_slice(&header)?; + + // Parse jwt payload + let payload: JwtPayload = serde_json::from_slice(&payload)?; + + // Parse jwt expiration date + // Annoyingly, because of my own fault, this could be either an integer or string. + let exp: i64 = payload.exp.as_i64().unwrap_or_else(|| { + let exp: String = payload.exp.as_str().unwrap().to_string(); + exp.parse().unwrap() + }); + + let timestamp = chrono::NaiveDateTime::from_timestamp_opt(exp, 0).unwrap(); + let expiration_date = DateTime::::from_utc(timestamp, Utc); + + Ok(JwtToken { + header, + payload, + signature, + expiration_date, + token: token.to_string(), + }) + } + + pub fn new(token: &str) -> Result> { + // STUPID: My mock server uses a different encoding than the real server, so we have to + // try both encodings here. + + Self::decode_token_using_engine(token, general_purpose::STANDARD).or( + Self::decode_token_using_engine(token, general_purpose::URL_SAFE_NO_PAD), + ) + } + + pub fn dummy() -> Self { + JwtToken { + header: JwtHeader { + alg: "none".to_string(), + typ: "JWT".to_string(), + }, + payload: JwtPayload { + exp: serde_json::Value::Null, + iss: None, + user: None, + }, + signature: vec![], + expiration_date: Utc::now(), + token: "".to_string(), + } + } + + pub fn is_valid(&self) -> bool { + self.expiration_date > Utc::now() + } + + pub fn to_header_value(&self) -> HeaderValue { + format!("Bearer {}", self.token).parse().unwrap() + } +} diff --git a/kordophone/src/model/mod.rs b/kordophone/src/model/mod.rs index 291ac75..92607cd 100644 --- a/kordophone/src/model/mod.rs +++ b/kordophone/src/model/mod.rs @@ -1,3 +1,5 @@ - pub mod conversation; pub use conversation::Conversation; + +pub mod jwt; +pub use jwt::JwtToken; \ No newline at end of file diff --git a/kordophone/src/tests/mod.rs b/kordophone/src/tests/mod.rs index b4e065a..43f21ef 100644 --- a/kordophone/src/tests/mod.rs +++ b/kordophone/src/tests/mod.rs @@ -9,7 +9,7 @@ pub mod api_interface { #[tokio::test] async fn test_version() { - let client = TestClient::new(); + let mut client = TestClient::new(); let version = client.get_version().await.unwrap(); assert_eq!(version, client.version); } diff --git a/kordophone/src/tests/test_client.rs b/kordophone/src/tests/test_client.rs index e38882e..455dff8 100644 --- a/kordophone/src/tests/test_client.rs +++ b/kordophone/src/tests/test_client.rs @@ -1,7 +1,7 @@ use async_trait::async_trait; pub use crate::APIInterface; -use crate::model::Conversation; +use crate::{api::http_client::Credentials, model::{Conversation, JwtToken}}; pub struct TestClient { pub version: &'static str, @@ -24,11 +24,15 @@ impl TestClient { impl APIInterface for TestClient { type Error = TestError; - async fn get_version(&self) -> Result { + async fn authenticate(&mut self, credentials: Credentials) -> Result { + Ok(JwtToken::dummy()) + } + + async fn get_version(&mut self) -> Result { Ok(self.version.to_string()) } - async fn get_conversations(&self) -> Result, Self::Error> { + async fn get_conversations(&mut self) -> Result, Self::Error> { Ok(self.conversations.clone()) } }