From 6095ead99248963ae70091c5bb3399eed49c0826 Mon Sep 17 00:00:00 2001 From: Rutger Broekhoff Date: Wed, 24 Jan 2024 18:58:58 +0100 Subject: Remove Go and C source The Rust implementation now implements all features I need --- rs/.gitignore | 1 - rs/Cargo.lock | 2364 ----------------------------------- rs/Cargo.toml | 8 - rs/common/Cargo.toml | 10 - rs/common/src/lib.rs | 368 ------ rs/git-lfs-authenticate/Cargo.toml | 8 - rs/git-lfs-authenticate/src/main.rs | 236 ---- rs/server/Cargo.toml | 19 - rs/server/src/main.rs | 1028 --------------- rs/shell/Cargo.toml | 6 - rs/shell/src/main.rs | 143 --- 11 files changed, 4191 deletions(-) delete mode 100644 rs/.gitignore delete mode 100644 rs/Cargo.lock delete mode 100644 rs/Cargo.toml delete mode 100644 rs/common/Cargo.toml delete mode 100644 rs/common/src/lib.rs delete mode 100644 rs/git-lfs-authenticate/Cargo.toml delete mode 100644 rs/git-lfs-authenticate/src/main.rs delete mode 100644 rs/server/Cargo.toml delete mode 100644 rs/server/src/main.rs delete mode 100644 rs/shell/Cargo.toml delete mode 100644 rs/shell/src/main.rs (limited to 'rs') diff --git a/rs/.gitignore b/rs/.gitignore deleted file mode 100644 index b83d222..0000000 --- a/rs/.gitignore +++ /dev/null @@ -1 +0,0 @@ -/target/ diff --git a/rs/Cargo.lock b/rs/Cargo.lock deleted file mode 100644 index f3beb9e..0000000 --- a/rs/Cargo.lock +++ /dev/null @@ -1,2364 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 3 - -[[package]] -name = "addr2line" -version = "0.21.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" -dependencies = [ - "gimli", -] - -[[package]] -name = "adler" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" - -[[package]] -name = "aho-corasick" -version = "1.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0" -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.77" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c980ee35e870bd1a4d2c8294d4c04d0499e67bca1e4b5cefcc693c2fa00caea9" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "autocfg" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" - -[[package]] -name = "aws-config" -version = "1.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e64b72d4bdbb41a73d27709c65a25b6e4bfc8321bf70fa3a8b19ce7d4eb81b0" -dependencies = [ - "aws-credential-types", - "aws-http", - "aws-runtime", - "aws-sdk-sso", - "aws-sdk-ssooidc", - "aws-sdk-sts", - "aws-smithy-async", - "aws-smithy-http", - "aws-smithy-json", - "aws-smithy-runtime", - "aws-smithy-runtime-api", - "aws-smithy-types", - "aws-types", - "bytes", - "fastrand", - "hex", - "http 0.2.11", - "hyper 0.14.28", - "ring", - "time", - "tokio", - "tracing", - "zeroize", -] - -[[package]] -name = "aws-credential-types" -version = "1.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a7cb3510b95492bd9014b60e2e3bee3e48bc516e220316f8e6b60df18b47331" -dependencies = [ - "aws-smithy-async", - "aws-smithy-runtime-api", - "aws-smithy-types", - "zeroize", -] - -[[package]] -name = "aws-http" -version = "0.60.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a95d41abe4e941399fdb4bc2f54713eac3c839d98151875948bb24e66ab658f2" -dependencies = [ - "aws-smithy-runtime-api", - "aws-smithy-types", - "aws-types", - "bytes", - "http 0.2.11", - "http-body 0.4.6", - "pin-project-lite", - "tracing", -] - -[[package]] -name = "aws-runtime" -version = "1.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "233cca219c6705d525ace011d6f9bc51aaf32fce5b4c41661d2d7ff22d9b4d49" -dependencies = [ - "aws-credential-types", - "aws-http", - "aws-sigv4", - "aws-smithy-async", - "aws-smithy-eventstream", - "aws-smithy-http", - "aws-smithy-runtime-api", - "aws-smithy-types", - "aws-types", - "fastrand", - "http 0.2.11", - "percent-encoding", - "tracing", - "uuid", -] - -[[package]] -name = "aws-sdk-s3" -version = "1.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "634fbe5b6591ee2e281cd2ba8641e9bd752dbf5bf338924d6ad4bd5a3304fe31" -dependencies = [ - "aws-credential-types", - "aws-http", - "aws-runtime", - "aws-sigv4", - "aws-smithy-async", - "aws-smithy-checksums", - "aws-smithy-eventstream", - "aws-smithy-http", - "aws-smithy-json", - "aws-smithy-runtime", - "aws-smithy-runtime-api", - "aws-smithy-types", - "aws-smithy-xml", - "aws-types", - "bytes", - "http 0.2.11", - "http-body 0.4.6", - "once_cell", - "percent-encoding", - "regex-lite", - "tracing", - "url", -] - -[[package]] -name = "aws-sdk-sso" -version = "1.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee41005e0f3a19ae749c7953d9e1f1ef8d2183f76f64966e346fa41c1ba0ed44" -dependencies = [ - "aws-credential-types", - "aws-http", - "aws-runtime", - "aws-smithy-async", - "aws-smithy-http", - "aws-smithy-json", - "aws-smithy-runtime", - "aws-smithy-runtime-api", - "aws-smithy-types", - "aws-types", - "bytes", - "http 0.2.11", - "once_cell", - "regex-lite", - "tracing", -] - -[[package]] -name = "aws-sdk-ssooidc" -version = "1.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa08168f8a27505e7b90f922c32a489feb1f2133878981a15138bebc849ac09c" -dependencies = [ - "aws-credential-types", - "aws-http", - "aws-runtime", - "aws-smithy-async", - "aws-smithy-http", - "aws-smithy-json", - "aws-smithy-runtime", - "aws-smithy-runtime-api", - "aws-smithy-types", - "aws-types", - "bytes", - "http 0.2.11", - "once_cell", - "regex-lite", - "tracing", -] - -[[package]] -name = "aws-sdk-sts" -version = "1.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29102eff04d50ef70f11a48823db33e33c6cc5f027bfb6ff4864efbd5f1f66f3" -dependencies = [ - "aws-credential-types", - "aws-http", - "aws-runtime", - "aws-smithy-async", - "aws-smithy-http", - "aws-smithy-json", - "aws-smithy-query", - "aws-smithy-runtime", - "aws-smithy-runtime-api", - "aws-smithy-types", - "aws-smithy-xml", - "aws-types", - "http 0.2.11", - "once_cell", - "regex-lite", - "tracing", -] - -[[package]] -name = "aws-sigv4" -version = "1.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b92384b39aedb258aa734fe0e7b2ffcd13f33e68227251a72cd2635e0acc8f1a" -dependencies = [ - "aws-credential-types", - "aws-smithy-eventstream", - "aws-smithy-http", - "aws-smithy-runtime-api", - "aws-smithy-types", - "bytes", - "crypto-bigint 0.5.5", - "form_urlencoded", - "hex", - "hmac", - "http 0.2.11", - "once_cell", - "p256", - "percent-encoding", - "ring", - "sha2", - "subtle", - "time", - "tracing", - "zeroize", -] - -[[package]] -name = "aws-smithy-async" -version = "1.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2eac0bb78e9e2765699999a02d7bfb4e6ad8f13e0962ebb9f5202b1d8cd76006" -dependencies = [ - "futures-util", - "pin-project-lite", - "tokio", -] - -[[package]] -name = "aws-smithy-checksums" -version = "0.60.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "535a2d5f1e459bc7709580a77152c8d493982db083236c2b1d1c51dc6217e8a3" -dependencies = [ - "aws-smithy-http", - "aws-smithy-types", - "bytes", - "crc32c", - "crc32fast", - "hex", - "http 0.2.11", - "http-body 0.4.6", - "md-5", - "pin-project-lite", - "sha1", - "sha2", - "tracing", -] - -[[package]] -name = "aws-smithy-eventstream" -version = "0.60.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "682371561562d08ab437766903c6bc28f4f95d7ab2ecfb389bda7849dd98aefe" -dependencies = [ - "aws-smithy-types", - "bytes", - "crc32fast", -] - -[[package]] -name = "aws-smithy-http" -version = "0.60.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "365ca49744b2bda2f1e2dc03b856da3fa5a28ca5b0a41e41d7ff5305a8fae190" -dependencies = [ - "aws-smithy-eventstream", - "aws-smithy-runtime-api", - "aws-smithy-types", - "bytes", - "bytes-utils", - "futures-core", - "http 0.2.11", - "http-body 0.4.6", - "once_cell", - "percent-encoding", - "pin-project-lite", - "pin-utils", - "tracing", -] - -[[package]] -name = "aws-smithy-json" -version = "0.60.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "733ccdb727ac63370836aa3b3c483d75ad2ef7bc6507db3efe1d01e8d2e50367" -dependencies = [ - "aws-smithy-types", -] - -[[package]] -name = "aws-smithy-query" -version = "0.60.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aff02ae2ee7968bbce2983ffb5ce529d24f4848532300f398347bde8c2196974" -dependencies = [ - "aws-smithy-types", - "urlencoding", -] - -[[package]] -name = "aws-smithy-runtime" -version = "1.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ab9cb6fee50680af8ceaa293ae79eba32095ca117161cb323f9ee30dd87d139" -dependencies = [ - "aws-smithy-async", - "aws-smithy-http", - "aws-smithy-runtime-api", - "aws-smithy-types", - "bytes", - "fastrand", - "h2 0.3.24", - "http 0.2.11", - "http-body 0.4.6", - "hyper 0.14.28", - "hyper-rustls", - "once_cell", - "pin-project-lite", - "pin-utils", - "rustls", - "tokio", - "tracing", -] - -[[package]] -name = "aws-smithy-runtime-api" -version = "1.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02ca2da7619517310bfead6d18abcdde90f1439224d887d608503cfacff46dff" -dependencies = [ - "aws-smithy-async", - "aws-smithy-types", - "bytes", - "http 0.2.11", - "pin-project-lite", - "tokio", - "tracing", - "zeroize", -] - -[[package]] -name = "aws-smithy-types" -version = "1.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d4bb944488536cd2fef43212d829bc7e9a8bfc4afa079d21170441e7be8d2d0" -dependencies = [ - "base64-simd", - "bytes", - "bytes-utils", - "futures-core", - "http 0.2.11", - "http-body 0.4.6", - "itoa", - "num-integer", - "pin-project-lite", - "pin-utils", - "ryu", - "serde", - "time", - "tokio", - "tokio-util", -] - -[[package]] -name = "aws-smithy-xml" -version = "0.60.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef796feaf894d7fd03869235237aeffe73ed1b29a3927cceeee2eecadf876eba" -dependencies = [ - "xmlparser", -] - -[[package]] -name = "aws-types" -version = "1.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8549aa62c5b7db5c57ab915200ee214b4f5d8f19b29a4a8fa0b3ad3bca1380e3" -dependencies = [ - "aws-credential-types", - "aws-smithy-async", - "aws-smithy-runtime-api", - "aws-smithy-types", - "http 0.2.11", - "rustc_version", - "tracing", -] - -[[package]] -name = "axum" -version = "0.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1236b4b292f6c4d6dc34604bb5120d85c3fe1d1aa596bd5cc52ca054d13e7b9e" -dependencies = [ - "async-trait", - "axum-core", - "bytes", - "futures-util", - "http 1.0.0", - "http-body 1.0.0", - "http-body-util", - "hyper 1.1.0", - "hyper-util", - "itoa", - "matchit", - "memchr", - "mime", - "percent-encoding", - "pin-project-lite", - "rustversion", - "serde", - "serde_json", - "serde_path_to_error", - "serde_urlencoded", - "sync_wrapper", - "tokio", - "tower", - "tower-layer", - "tower-service", - "tracing", -] - -[[package]] -name = "axum-core" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a15c63fd72d41492dc4f497196f5da1fb04fb7529e631d73630d1b491e47a2e3" -dependencies = [ - "async-trait", - "bytes", - "futures-util", - "http 1.0.0", - "http-body 1.0.0", - "http-body-util", - "mime", - "pin-project-lite", - "rustversion", - "sync_wrapper", - "tower-layer", - "tower-service", - "tracing", -] - -[[package]] -name = "backtrace" -version = "0.3.69" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837" -dependencies = [ - "addr2line", - "cc", - "cfg-if", - "libc", - "miniz_oxide", - "object", - "rustc-demangle", -] - -[[package]] -name = "base16ct" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "349a06037c7bf932dd7e7d1f653678b2038b9ad46a74102f1fc7bd7872678cce" - -[[package]] -name = "base64" -version = "0.21.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" - -[[package]] -name = "base64-simd" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "339abbe78e73178762e23bea9dfd08e697eb3f3301cd4be981c0f78ba5859195" -dependencies = [ - "outref", - "vsimd", -] - -[[package]] -name = "base64ct" -version = "1.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" - -[[package]] -name = "bitflags" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" - -[[package]] -name = "block-buffer" -version = "0.10.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" -dependencies = [ - "generic-array", -] - -[[package]] -name = "bumpalo" -version = "3.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec" - -[[package]] -name = "bytes" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" - -[[package]] -name = "bytes-utils" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7dafe3a8757b027e2be6e4e5601ed563c55989fcf1546e933c66c8eb3a058d35" -dependencies = [ - "bytes", - "either", -] - -[[package]] -name = "cc" -version = "1.0.83" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" -dependencies = [ - "libc", -] - -[[package]] -name = "cfg-if" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" - -[[package]] -name = "chrono" -version = "0.4.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f2c685bad3eb3d45a01354cedb7d5faa66194d1d58ba6e267a8de788f79db38" -dependencies = [ - "android-tzdata", - "iana-time-zone", - "js-sys", - "num-traits", - "serde", - "wasm-bindgen", - "windows-targets 0.48.5", -] - -[[package]] -name = "common" -version = "0.1.0" -dependencies = [ - "chrono", - "hmac-sha256", - "serde", - "subtle", -] - -[[package]] -name = "const-oid" -version = "0.9.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" - -[[package]] -name = "core-foundation" -version = "0.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" -dependencies = [ - "core-foundation-sys", - "libc", -] - -[[package]] -name = "core-foundation-sys" -version = "0.8.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" - -[[package]] -name = "cpufeatures" -version = "0.2.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504" -dependencies = [ - "libc", -] - -[[package]] -name = "crc32c" -version = "0.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8f48d60e5b4d2c53d5c2b1d8a58c849a70ae5e5509b08a48d047e3b65714a74" -dependencies = [ - "rustc_version", -] - -[[package]] -name = "crc32fast" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "crypto-bigint" -version = "0.4.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef2b4b23cddf68b89b8f8069890e8c270d54e2d5fe1b143820234805e4cb17ef" -dependencies = [ - "generic-array", - "rand_core", - "subtle", - "zeroize", -] - -[[package]] -name = "crypto-bigint" -version = "0.5.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" -dependencies = [ - "rand_core", - "subtle", -] - -[[package]] -name = "crypto-common" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" -dependencies = [ - "generic-array", - "typenum", -] - -[[package]] -name = "der" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1a467a65c5e759bce6e65eaf91cc29f466cdc57cb65777bd646872a8a1fd4de" -dependencies = [ - "const-oid", - "zeroize", -] - -[[package]] -name = "deranged" -version = "0.3.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" -dependencies = [ - "powerfmt", -] - -[[package]] -name = "digest" -version = "0.10.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" -dependencies = [ - "block-buffer", - "crypto-common", - "subtle", -] - -[[package]] -name = "ecdsa" -version = "0.14.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "413301934810f597c1d19ca71c8710e99a3f1ba28a0d2ebc01551a2daeea3c5c" -dependencies = [ - "der", - "elliptic-curve", - "rfc6979", - "signature", -] - -[[package]] -name = "either" -version = "1.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" - -[[package]] -name = "elliptic-curve" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7bb888ab5300a19b8e5bceef25ac745ad065f3c9f7efc6de1b91958110891d3" -dependencies = [ - "base16ct", - "crypto-bigint 0.4.9", - "der", - "digest", - "ff", - "generic-array", - "group", - "pkcs8", - "rand_core", - "sec1", - "subtle", - "zeroize", -] - -[[package]] -name = "equivalent" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" - -[[package]] -name = "fastrand" -version = "2.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5" - -[[package]] -name = "ff" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d013fc25338cc558c5c2cfbad646908fb23591e2404481826742b651c9af7160" -dependencies = [ - "rand_core", - "subtle", -] - -[[package]] -name = "fnv" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" - -[[package]] -name = "form_urlencoded" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" -dependencies = [ - "percent-encoding", -] - -[[package]] -name = "futures-channel" -version = "0.3.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" -dependencies = [ - "futures-core", -] - -[[package]] -name = "futures-core" -version = "0.3.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" - -[[package]] -name = "futures-sink" -version = "0.3.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5" - -[[package]] -name = "futures-task" -version = "0.3.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" - -[[package]] -name = "futures-util" -version = "0.3.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" -dependencies = [ - "futures-core", - "futures-task", - "pin-project-lite", - "pin-utils", -] - -[[package]] -name = "generic-array" -version = "0.14.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" -dependencies = [ - "typenum", - "version_check", -] - -[[package]] -name = "getrandom" -version = "0.2.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "190092ea657667030ac6a35e305e62fc4dd69fd98ac98631e5d3a2b1575a12b5" -dependencies = [ - "cfg-if", - "libc", - "wasi", -] - -[[package]] -name = "gimli" -version = "0.28.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" - -[[package]] -name = "git-lfs-authenticate" -version = "0.1.0" -dependencies = [ - "chrono", - "common", -] - -[[package]] -name = "group" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5dfbfb3a6cfbd390d5c9564ab283a0349b9b9fcd46a706c1eb10e0db70bfbac7" -dependencies = [ - "ff", - "rand_core", - "subtle", -] - -[[package]] -name = "h2" -version = "0.3.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb2c4422095b67ee78da96fbb51a4cc413b3b25883c7717ff7ca1ab31022c9c9" -dependencies = [ - "bytes", - "fnv", - "futures-core", - "futures-sink", - "futures-util", - "http 0.2.11", - "indexmap", - "slab", - "tokio", - "tokio-util", - "tracing", -] - -[[package]] -name = "h2" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31d030e59af851932b72ceebadf4a2b5986dba4c3b99dd2493f8273a0f151943" -dependencies = [ - "bytes", - "fnv", - "futures-core", - "futures-sink", - "futures-util", - "http 1.0.0", - "indexmap", - "slab", - "tokio", - "tokio-util", - "tracing", -] - -[[package]] -name = "hashbrown" -version = "0.14.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" - -[[package]] -name = "hermit-abi" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d77f7ec81a6d05a3abb01ab6eb7590f6083d08449fe5a1c8b1e620283546ccb7" - -[[package]] -name = "hex" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" - -[[package]] -name = "hmac" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" -dependencies = [ - "digest", -] - -[[package]] -name = "hmac-sha256" -version = "1.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3688e69b38018fec1557254f64c8dc2cc8ec502890182f395dbb0aa997aa5735" - -[[package]] -name = "http" -version = "0.2.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8947b1a6fad4393052c7ba1f4cd97bed3e953a95c79c92ad9b051a04611d9fbb" -dependencies = [ - "bytes", - "fnv", - "itoa", -] - -[[package]] -name = "http" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b32afd38673a8016f7c9ae69e5af41a58f81b1d31689040f2f1959594ce194ea" -dependencies = [ - "bytes", - "fnv", - "itoa", -] - -[[package]] -name = "http-body" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" -dependencies = [ - "bytes", - "http 0.2.11", - "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", - "http 1.0.0", -] - -[[package]] -name = "http-body-util" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41cb79eb393015dadd30fc252023adb0b2400a0caee0fa2a077e6e21a551e840" -dependencies = [ - "bytes", - "futures-util", - "http 1.0.0", - "http-body 1.0.0", - "pin-project-lite", -] - -[[package]] -name = "httparse" -version = "1.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" - -[[package]] -name = "httpdate" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" - -[[package]] -name = "hyper" -version = "0.14.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf96e135eb83a2a8ddf766e426a841d8ddd7449d5f00d34ea02b41d2f19eef80" -dependencies = [ - "bytes", - "futures-channel", - "futures-core", - "futures-util", - "h2 0.3.24", - "http 0.2.11", - "http-body 0.4.6", - "httparse", - "httpdate", - "itoa", - "pin-project-lite", - "socket2", - "tokio", - "tower-service", - "tracing", - "want", -] - -[[package]] -name = "hyper" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb5aa53871fc917b1a9ed87b683a5d86db645e23acb32c2e0785a353e522fb75" -dependencies = [ - "bytes", - "futures-channel", - "futures-util", - "h2 0.4.2", - "http 1.0.0", - "http-body 1.0.0", - "httparse", - "httpdate", - "itoa", - "pin-project-lite", - "tokio", -] - -[[package]] -name = "hyper-rustls" -version = "0.24.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec3efd23720e2049821a693cbc7e65ea87c72f1c58ff2f9522ff332b1491e590" -dependencies = [ - "futures-util", - "http 0.2.11", - "hyper 0.14.28", - "log", - "rustls", - "rustls-native-certs", - "tokio", - "tokio-rustls", -] - -[[package]] -name = "hyper-util" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bdea9aac0dbe5a9240d68cfd9501e2db94222c6dc06843e06640b9e07f0fdc67" -dependencies = [ - "bytes", - "futures-channel", - "futures-util", - "http 1.0.0", - "http-body 1.0.0", - "hyper 1.1.0", - "pin-project-lite", - "socket2", - "tokio", - "tracing", -] - -[[package]] -name = "iana-time-zone" -version = "0.1.59" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6a67363e2aa4443928ce15e57ebae94fd8949958fd1223c4cfc0cd473ad7539" -dependencies = [ - "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]] -name = "idna" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" -dependencies = [ - "unicode-bidi", - "unicode-normalization", -] - -[[package]] -name = "indexmap" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f" -dependencies = [ - "equivalent", - "hashbrown", -] - -[[package]] -name = "itoa" -version = "1.0.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c" - -[[package]] -name = "js-sys" -version = "0.3.67" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a1d36f1235bc969acba30b7f5990b864423a6068a10f7c90ae8f0112e3a59d1" -dependencies = [ - "wasm-bindgen", -] - -[[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.152" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13e3bf6590cbc649f4d1a3eefc9d5d6eb746f5200ffb04e5e142700b8faa56e7" - -[[package]] -name = "lock_api" -version = "0.4.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45" -dependencies = [ - "autocfg", - "scopeguard", -] - -[[package]] -name = "log" -version = "0.4.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" - -[[package]] -name = "matchers" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558" -dependencies = [ - "regex-automata 0.1.10", -] - -[[package]] -name = "matchit" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e7465ac9959cc2b1404e8e2367b43684a6d13790fe23056cc8c6c5a6b7bcb94" - -[[package]] -name = "md-5" -version = "0.10.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d89e7ee0cfbedfc4da3340218492196241d89eefb6dab27de5df917a6d2e78cf" -dependencies = [ - "cfg-if", - "digest", -] - -[[package]] -name = "memchr" -version = "2.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149" - -[[package]] -name = "mime" -version = "0.3.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" - -[[package]] -name = "miniz_oxide" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7" -dependencies = [ - "adler", -] - -[[package]] -name = "mio" -version = "0.8.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f3d0b296e374a4e6f3c7b0a1f5a51d748a0d34c85e7dc48fc3fa9a87657fe09" -dependencies = [ - "libc", - "wasi", - "windows-sys 0.48.0", -] - -[[package]] -name = "nu-ansi-term" -version = "0.46.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" -dependencies = [ - "overload", - "winapi", -] - -[[package]] -name = "num-integer" -version = "0.1.45" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" -dependencies = [ - "autocfg", - "num-traits", -] - -[[package]] -name = "num-traits" -version = "0.2.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c" -dependencies = [ - "autocfg", -] - -[[package]] -name = "num_cpus" -version = "1.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" -dependencies = [ - "hermit-abi", - "libc", -] - -[[package]] -name = "object" -version = "0.32.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441" -dependencies = [ - "memchr", -] - -[[package]] -name = "once_cell" -version = "1.19.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" - -[[package]] -name = "openssl-probe" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" - -[[package]] -name = "outref" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4030760ffd992bef45b0ae3f10ce1aba99e33464c90d14dd7c039884963ddc7a" - -[[package]] -name = "overload" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" - -[[package]] -name = "p256" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51f44edd08f51e2ade572f141051021c5af22677e42b7dd28a88155151c33594" -dependencies = [ - "ecdsa", - "elliptic-curve", - "sha2", -] - -[[package]] -name = "parking_lot" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" -dependencies = [ - "lock_api", - "parking_lot_core", -] - -[[package]] -name = "parking_lot_core" -version = "0.9.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c42a9226546d68acdd9c0a280d17ce19bfe27a46bf68784e4066115788d008e" -dependencies = [ - "cfg-if", - "libc", - "redox_syscall", - "smallvec", - "windows-targets 0.48.5", -] - -[[package]] -name = "percent-encoding" -version = "2.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" - -[[package]] -name = "pin-project" -version = "1.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fda4ed1c6c173e3fc7a83629421152e01d7b1f9b7f65fb301e490e8cfc656422" -dependencies = [ - "pin-project-internal", -] - -[[package]] -name = "pin-project-internal" -version = "1.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4359fd9c9171ec6e8c62926d6faaf553a8dc3f64e1507e76da7911b4f6a04405" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "pin-project-lite" -version = "0.2.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" - -[[package]] -name = "pin-utils" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" - -[[package]] -name = "pkcs8" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9eca2c590a5f85da82668fa685c09ce2888b9430e83299debf1f34b65fd4a4ba" -dependencies = [ - "der", - "spki", -] - -[[package]] -name = "powerfmt" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" - -[[package]] -name = "proc-macro2" -version = "1.0.76" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95fc56cda0b5c3325f5fbbd7ff9fda9e02bb00bb3dac51252d2f1bfa1cb8cc8c" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "quote" -version = "1.0.35" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "rand_core" -version = "0.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" -dependencies = [ - "getrandom", -] - -[[package]] -name = "redox_syscall" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" -dependencies = [ - "bitflags", -] - -[[package]] -name = "regex" -version = "1.10.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b62dbe01f0b06f9d8dc7d49e05a0785f153b00b2c227856282f671e0318c9b15" -dependencies = [ - "aho-corasick", - "memchr", - "regex-automata 0.4.4", - "regex-syntax 0.8.2", -] - -[[package]] -name = "regex-automata" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" -dependencies = [ - "regex-syntax 0.6.29", -] - -[[package]] -name = "regex-automata" -version = "0.4.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b7fa1134405e2ec9353fd416b17f8dacd46c473d7d3fd1cf202706a14eb792a" -dependencies = [ - "aho-corasick", - "memchr", - "regex-syntax 0.8.2", -] - -[[package]] -name = "regex-lite" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30b661b2f27137bdbc16f00eda72866a92bb28af1753ffbd56744fb6e2e9cd8e" - -[[package]] -name = "regex-syntax" -version = "0.6.29" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" - -[[package]] -name = "regex-syntax" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" - -[[package]] -name = "rfc6979" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7743f17af12fa0b03b803ba12cd6a8d9483a587e89c69445e3909655c0b9fabb" -dependencies = [ - "crypto-bigint 0.4.9", - "hmac", - "zeroize", -] - -[[package]] -name = "ring" -version = "0.17.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "688c63d65483050968b2a8937f7995f443e27041a0f7700aa59b0822aedebb74" -dependencies = [ - "cc", - "getrandom", - "libc", - "spin", - "untrusted", - "windows-sys 0.48.0", -] - -[[package]] -name = "rustc-demangle" -version = "0.1.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" - -[[package]] -name = "rustc_version" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" -dependencies = [ - "semver", -] - -[[package]] -name = "rustls" -version = "0.21.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9d5a6813c0759e4609cd494e8e725babae6a2ca7b62a5536a13daaec6fcb7ba" -dependencies = [ - "log", - "ring", - "rustls-webpki", - "sct", -] - -[[package]] -name = "rustls-native-certs" -version = "0.6.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9aace74cb666635c918e9c12bc0d348266037aa8eb599b5cba565709a8dff00" -dependencies = [ - "openssl-probe", - "rustls-pemfile", - "schannel", - "security-framework", -] - -[[package]] -name = "rustls-pemfile" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c" -dependencies = [ - "base64", -] - -[[package]] -name = "rustls-webpki" -version = "0.101.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765" -dependencies = [ - "ring", - "untrusted", -] - -[[package]] -name = "rustversion" -version = "1.0.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ffc183a10b4478d04cbbbfc96d0873219d962dd5accaff2ffbd4ceb7df837f4" - -[[package]] -name = "ryu" -version = "1.0.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f98d2aa92eebf49b69786be48e4477826b256916e84a57ff2a4f21923b48eb4c" - -[[package]] -name = "schannel" -version = "0.1.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbc91545643bcf3a0bbb6569265615222618bdf33ce4ffbbd13c4bbd4c093534" -dependencies = [ - "windows-sys 0.52.0", -] - -[[package]] -name = "scopeguard" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" - -[[package]] -name = "sct" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414" -dependencies = [ - "ring", - "untrusted", -] - -[[package]] -name = "sec1" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3be24c1842290c45df0a7bf069e0c268a747ad05a192f2fd7dcfdbc1cba40928" -dependencies = [ - "base16ct", - "der", - "generic-array", - "pkcs8", - "subtle", - "zeroize", -] - -[[package]] -name = "security-framework" -version = "2.9.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05b64fb303737d99b81884b2c63433e9ae28abebe5eb5045dcdd175dc2ecf4de" -dependencies = [ - "bitflags", - "core-foundation", - "core-foundation-sys", - "libc", - "security-framework-sys", -] - -[[package]] -name = "security-framework-sys" -version = "2.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e932934257d3b408ed8f30db49d85ea163bfe74961f017f405b025af298f0c7a" -dependencies = [ - "core-foundation-sys", - "libc", -] - -[[package]] -name = "semver" -version = "1.0.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b97ed7a9823b74f99c7742f5336af7be5ecd3eeafcb1507d1fa93347b1d589b0" - -[[package]] -name = "serde" -version = "1.0.195" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "63261df402c67811e9ac6def069e4786148c4563f4b50fd4bf30aa370d626b02" -dependencies = [ - "serde_derive", -] - -[[package]] -name = "serde_derive" -version = "1.0.195" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46fe8f8603d81ba86327b23a2e9cdf49e1255fb94a4c5f297f6ee0547178ea2c" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "serde_json" -version = "1.0.111" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "176e46fa42316f18edd598015a5166857fc835ec732f5215eac6b7bdbf0a84f4" -dependencies = [ - "itoa", - "ryu", - "serde", -] - -[[package]] -name = "serde_path_to_error" -version = "0.1.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebd154a240de39fdebcf5775d2675c204d7c13cf39a4c697be6493c8e734337c" -dependencies = [ - "itoa", - "serde", -] - -[[package]] -name = "serde_urlencoded" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" -dependencies = [ - "form_urlencoded", - "itoa", - "ryu", - "serde", -] - -[[package]] -name = "server" -version = "0.1.0" -dependencies = [ - "aws-config", - "aws-sdk-s3", - "axum", - "base64", - "chrono", - "common", - "mime", - "serde", - "serde_json", - "tokio", - "tokio-util", - "tower", - "tracing-subscriber", -] - -[[package]] -name = "sha1" -version = "0.10.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" -dependencies = [ - "cfg-if", - "cpufeatures", - "digest", -] - -[[package]] -name = "sha2" -version = "0.10.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" -dependencies = [ - "cfg-if", - "cpufeatures", - "digest", -] - -[[package]] -name = "sharded-slab" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" -dependencies = [ - "lazy_static", -] - -[[package]] -name = "shell" -version = "0.1.0" - -[[package]] -name = "signal-hook-registry" -version = "1.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8229b473baa5980ac72ef434c4415e70c4b5e71b423043adb4ba059f89c99a1" -dependencies = [ - "libc", -] - -[[package]] -name = "signature" -version = "1.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74233d3b3b2f6d4b006dc19dee745e73e2a6bfb6f93607cd3b02bd5b00797d7c" -dependencies = [ - "digest", - "rand_core", -] - -[[package]] -name = "slab" -version = "0.4.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" -dependencies = [ - "autocfg", -] - -[[package]] -name = "smallvec" -version = "1.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4dccd0940a2dcdf68d092b8cbab7dc0ad8fa938bf95787e1b916b0e3d0e8e970" - -[[package]] -name = "socket2" -version = "0.5.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b5fac59a5cb5dd637972e5fca70daf0523c9067fcdc4842f053dae04a18f8e9" -dependencies = [ - "libc", - "windows-sys 0.48.0", -] - -[[package]] -name = "spin" -version = "0.9.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" - -[[package]] -name = "spki" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67cf02bbac7a337dc36e4f5a693db6c21e7863f45070f7064577eb4367a3212b" -dependencies = [ - "base64ct", - "der", -] - -[[package]] -name = "subtle" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" - -[[package]] -name = "syn" -version = "2.0.48" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f3531638e407dfc0814761abb7c00a5b54992b849452a0646b7f65c9f770f3f" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "sync_wrapper" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" - -[[package]] -name = "thread_local" -version = "1.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fdd6f064ccff2d6567adcb3873ca630700f00b5ad3f060c25b5dcfd9a4ce152" -dependencies = [ - "cfg-if", - "once_cell", -] - -[[package]] -name = "time" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f657ba42c3f86e7680e53c8cd3af8abbe56b5491790b46e22e19c0d57463583e" -dependencies = [ - "deranged", - "powerfmt", - "serde", - "time-core", - "time-macros", -] - -[[package]] -name = "time-core" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" - -[[package]] -name = "time-macros" -version = "0.2.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26197e33420244aeb70c3e8c78376ca46571bc4e701e4791c2cd9f57dcb3a43f" -dependencies = [ - "time-core", -] - -[[package]] -name = "tinyvec" -version = "1.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" -dependencies = [ - "tinyvec_macros", -] - -[[package]] -name = "tinyvec_macros" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" - -[[package]] -name = "tokio" -version = "1.35.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c89b4efa943be685f629b149f53829423f8f5531ea21249408e8e2f8671ec104" -dependencies = [ - "backtrace", - "bytes", - "libc", - "mio", - "num_cpus", - "parking_lot", - "pin-project-lite", - "signal-hook-registry", - "socket2", - "tokio-macros", - "windows-sys 0.48.0", -] - -[[package]] -name = "tokio-macros" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "tokio-rustls" -version = "0.24.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081" -dependencies = [ - "rustls", - "tokio", -] - -[[package]] -name = "tokio-util" -version = "0.7.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5419f34732d9eb6ee4c3578b7989078579b7f039cbbb9ca2c4da015749371e15" -dependencies = [ - "bytes", - "futures-core", - "futures-sink", - "pin-project-lite", - "tokio", - "tracing", -] - -[[package]] -name = "tower" -version = "0.4.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c" -dependencies = [ - "futures-core", - "futures-util", - "pin-project", - "pin-project-lite", - "tokio", - "tower-layer", - "tower-service", - "tracing", -] - -[[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.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" - -[[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-attributes", - "tracing-core", -] - -[[package]] -name = "tracing-attributes" -version = "0.1.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "tracing-core" -version = "0.1.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" -dependencies = [ - "once_cell", - "valuable", -] - -[[package]] -name = "tracing-log" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" -dependencies = [ - "log", - "once_cell", - "tracing-core", -] - -[[package]] -name = "tracing-subscriber" -version = "0.3.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b" -dependencies = [ - "matchers", - "nu-ansi-term", - "once_cell", - "regex", - "sharded-slab", - "smallvec", - "thread_local", - "tracing", - "tracing-core", - "tracing-log", -] - -[[package]] -name = "try-lock" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" - -[[package]] -name = "typenum" -version = "1.17.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" - -[[package]] -name = "unicode-bidi" -version = "0.3.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" - -[[package]] -name = "unicode-ident" -version = "1.0.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" - -[[package]] -name = "unicode-normalization" -version = "0.1.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" -dependencies = [ - "tinyvec", -] - -[[package]] -name = "untrusted" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" - -[[package]] -name = "url" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31e6302e3bb753d46e83516cae55ae196fc0c309407cf11ab35cc51a4c2a4633" -dependencies = [ - "form_urlencoded", - "idna", - "percent-encoding", -] - -[[package]] -name = "urlencoding" -version = "2.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da" - -[[package]] -name = "uuid" -version = "1.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e395fcf16a7a3d8127ec99782007af141946b4795001f876d54fb0d55978560" - -[[package]] -name = "valuable" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" - -[[package]] -name = "version_check" -version = "0.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" - -[[package]] -name = "vsimd" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c3082ca00d5a5ef149bb8b555a72ae84c9c59f7250f013ac822ac2e49b19c64" - -[[package]] -name = "want" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" -dependencies = [ - "try-lock", -] - -[[package]] -name = "wasi" -version = "0.11.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" - -[[package]] -name = "wasm-bindgen" -version = "0.2.90" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1223296a201415c7fad14792dbefaace9bd52b62d33453ade1c5b5f07555406" -dependencies = [ - "cfg-if", - "wasm-bindgen-macro", -] - -[[package]] -name = "wasm-bindgen-backend" -version = "0.2.90" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcdc935b63408d58a32f8cc9738a0bffd8f05cc7c002086c6ef20b7312ad9dcd" -dependencies = [ - "bumpalo", - "log", - "once_cell", - "proc-macro2", - "quote", - "syn", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-macro" -version = "0.2.90" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e4c238561b2d428924c49815533a8b9121c664599558a5d9ec51f8a1740a999" -dependencies = [ - "quote", - "wasm-bindgen-macro-support", -] - -[[package]] -name = "wasm-bindgen-macro-support" -version = "0.2.90" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bae1abb6806dc1ad9e560ed242107c0f6c84335f1749dd4e8ddb012ebd5e25a7" -dependencies = [ - "proc-macro2", - "quote", - "syn", - "wasm-bindgen-backend", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-shared" -version = "0.2.90" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d91413b1c31d7539ba5ef2451af3f0b833a005eb27a631cec32bc0635a8602b" - -[[package]] -name = "winapi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" -dependencies = [ - "winapi-i686-pc-windows-gnu", - "winapi-x86_64-pc-windows-gnu", -] - -[[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" - -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" - -[[package]] -name = "windows-core" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" -dependencies = [ - "windows-targets 0.52.0", -] - -[[package]] -name = "windows-sys" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" -dependencies = [ - "windows-targets 0.48.5", -] - -[[package]] -name = "windows-sys" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" -dependencies = [ - "windows-targets 0.52.0", -] - -[[package]] -name = "windows-targets" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" -dependencies = [ - "windows_aarch64_gnullvm 0.48.5", - "windows_aarch64_msvc 0.48.5", - "windows_i686_gnu 0.48.5", - "windows_i686_msvc 0.48.5", - "windows_x86_64_gnu 0.48.5", - "windows_x86_64_gnullvm 0.48.5", - "windows_x86_64_msvc 0.48.5", -] - -[[package]] -name = "windows-targets" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd" -dependencies = [ - "windows_aarch64_gnullvm 0.52.0", - "windows_aarch64_msvc 0.52.0", - "windows_i686_gnu 0.52.0", - "windows_i686_msvc 0.52.0", - "windows_x86_64_gnu 0.52.0", - "windows_x86_64_gnullvm 0.52.0", - "windows_x86_64_msvc 0.52.0", -] - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef" - -[[package]] -name = "windows_i686_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" - -[[package]] -name = "windows_i686_gnu" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313" - -[[package]] -name = "windows_i686_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" - -[[package]] -name = "windows_i686_msvc" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" - -[[package]] -name = "xmlparser" -version = "0.13.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "66fee0b777b0f5ac1c69bb06d361268faafa61cd4682ae064a171c16c433e9e4" - -[[package]] -name = "zeroize" -version = "1.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "525b4ec142c6b68a2d10f01f7bbf6755599ca3f81ea53b8431b7dd348f5fdb2d" diff --git a/rs/Cargo.toml b/rs/Cargo.toml deleted file mode 100644 index 6439e6b..0000000 --- a/rs/Cargo.toml +++ /dev/null @@ -1,8 +0,0 @@ -[workspace] -resolver = "2" -members = [ - "common", - "git-lfs-authenticate", - "server", - "shell", -] diff --git a/rs/common/Cargo.toml b/rs/common/Cargo.toml deleted file mode 100644 index 20d9bdd..0000000 --- a/rs/common/Cargo.toml +++ /dev/null @@ -1,10 +0,0 @@ -[package] -name = "common" -version = "0.1.0" -edition = "2021" - -[dependencies] -chrono = "0.4" -hmac-sha256 = "1.1" -subtle = "2.5" -serde = { version = "1", features = ["derive"] } diff --git a/rs/common/src/lib.rs b/rs/common/src/lib.rs deleted file mode 100644 index 995352d..0000000 --- a/rs/common/src/lib.rs +++ /dev/null @@ -1,368 +0,0 @@ -use chrono::{DateTime, Utc}; -use serde::de; -use serde::{Deserialize, Serialize}; -use std::fmt::Write; -use std::ops; -use std::{fmt, str::FromStr}; -use subtle::ConstantTimeEq; - -#[derive(Debug, Eq, PartialEq, Copy, Clone, Serialize, Deserialize)] -#[repr(u8)] -pub enum Operation { - #[serde(rename = "download")] - Download = 1, - #[serde(rename = "upload")] - Upload = 2, -} - -#[derive(Debug, PartialEq, Eq, Copy, Clone)] -pub struct ParseOperationError; - -impl fmt::Display for ParseOperationError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "operation should be 'download' or 'upload'") - } -} - -impl FromStr for Operation { - type Err = ParseOperationError; - - fn from_str(s: &str) -> Result { - match s { - "upload" => Ok(Self::Upload), - "download" => Ok(Self::Download), - _ => Err(ParseOperationError), - } - } -} - -#[repr(u8)] -enum AuthType { - BatchApi = 1, - Download = 2, -} - -/// None means out of range. -fn decode_nibble(c: u8) -> Option { - if c.is_ascii_digit() { - Some(c - b'0') - } else if (b'a'..=b'f').contains(&c) { - Some(c - b'a' + 10) - } else if (b'A'..=b'F').contains(&c) { - Some(c - b'A' + 10) - } else { - None - } -} - -#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)] -pub struct HexByte(pub u8); - -impl<'de> Deserialize<'de> for HexByte { - fn deserialize(deserializer: D) -> Result - where - D: serde::Deserializer<'de>, - { - let str = <&str>::deserialize(deserializer)?; - let &[b1, b2] = str.as_bytes() else { - return Err(de::Error::invalid_length( - str.len(), - &"two hexadecimal characters", - )); - }; - let (Some(b1), Some(b2)) = (decode_nibble(b1), decode_nibble(b2)) else { - return Err(de::Error::invalid_value( - de::Unexpected::Str(str), - &"two hexadecimal characters", - )); - }; - Ok(HexByte((b1 << 4) | b2)) - } -} - -impl fmt::Display for HexByte { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - let &HexByte(b) = self; - HexFmt(&[b]).fmt(f) - } -} - -#[derive(Debug, PartialEq, Eq, Copy, Clone)] -pub enum ParseHexError { - UnevenNibbles, - InvalidCharacter, - TooShort, - TooLong, -} - -impl fmt::Display for ParseHexError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - Self::UnevenNibbles => { - write!(f, "uneven amount of nibbles (chars in range [a-zA-Z0-9])") - } - Self::InvalidCharacter => write!(f, "non-hex character encountered"), - Self::TooShort => write!(f, "unexpected end of hex sequence"), - Self::TooLong => write!(f, "longer hex sequence than expected"), - } - } -} - -#[derive(Debug)] -pub enum ReadHexError { - Io(std::io::Error), - Format(ParseHexError), -} - -impl fmt::Display for ReadHexError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match self { - Self::Io(e) => e.fmt(f), - Self::Format(e) => e.fmt(f), - } - } -} - -fn parse_hex_exact(value: &str, buf: &mut [u8]) -> Result<(), ParseHexError> { - if value.bytes().len() % 2 == 1 { - return Err(ParseHexError::UnevenNibbles); - } - if value.bytes().len() < 2 * buf.len() { - return Err(ParseHexError::TooShort); - } - if value.bytes().len() > 2 * buf.len() { - return Err(ParseHexError::TooLong); - } - for (i, c) in value.bytes().enumerate() { - if let Some(b) = decode_nibble(c) { - if i % 2 == 0 { - buf[i / 2] = b << 4; - } else { - buf[i / 2] |= b; - } - } else { - return Err(ParseHexError::InvalidCharacter); - } - } - Ok(()) -} - -pub struct SafeByteArray { - inner: [u8; N], -} - -impl SafeByteArray { - pub fn new() -> Self { - Self { inner: [0; N] } - } -} - -impl Default for SafeByteArray { - fn default() -> Self { - Self::new() - } -} - -impl AsRef<[u8]> for SafeByteArray { - fn as_ref(&self) -> &[u8] { - &self.inner - } -} - -impl AsMut<[u8]> for SafeByteArray { - fn as_mut(&mut self) -> &mut [u8] { - &mut self.inner - } -} - -impl Drop for SafeByteArray { - fn drop(&mut self) { - self.inner.fill(0) - } -} - -impl FromStr for SafeByteArray { - type Err = ParseHexError; - - fn from_str(value: &str) -> Result { - let mut sba = Self { inner: [0u8; N] }; - parse_hex_exact(value, &mut sba.inner)?; - Ok(sba) - } -} - -pub type Oid = Digest<32>; - -#[derive(Debug, Copy, Clone)] -pub enum SpecificClaims { - BatchApi(Operation), - Download(Oid), -} - -#[derive(Debug, Copy, Clone)] -pub struct Claims<'a> { - pub specific_claims: SpecificClaims, - pub repo_path: &'a str, - pub expires_at: DateTime, -} - -/// Returns None if the claims are invalid. Repo path length may be no more than 100 bytes. -pub fn generate_tag(claims: Claims, key: impl AsRef<[u8]>) -> Option> { - if claims.repo_path.len() > 100 { - return None; - } - - let mut hmac = hmac_sha256::HMAC::new(key); - match claims.specific_claims { - SpecificClaims::BatchApi(operation) => { - hmac.update([AuthType::BatchApi as u8]); - hmac.update([operation as u8]); - } - SpecificClaims::Download(oid) => { - hmac.update([AuthType::Download as u8]); - hmac.update(oid.as_bytes()); - } - } - hmac.update([claims.repo_path.len() as u8]); - hmac.update(claims.repo_path.as_bytes()); - hmac.update(claims.expires_at.timestamp().to_be_bytes()); - Some(hmac.finalize().into()) -} - -pub struct HexFmt>(pub B); - -impl> fmt::Display for HexFmt { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - let HexFmt(buf) = self; - for b in buf.as_ref() { - let (high, low) = (b >> 4, b & 0xF); - let highc = if high < 10 { - high + b'0' - } else { - high - 10 + b'a' - }; - let lowc = if low < 10 { - low + b'0' - } else { - low - 10 + b'a' - }; - f.write_char(highc as char)?; - f.write_char(lowc as char)?; - } - Ok(()) - } -} - -pub struct EscJsonFmt<'a>(pub &'a str); - -impl<'a> fmt::Display for EscJsonFmt<'a> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - let EscJsonFmt(buf) = self; - for c in buf.chars() { - match c { - '"' => f.write_str("\\\"")?, // quote - '\\' => f.write_str("\\\\")?, // backslash - '\x08' => f.write_str("\\b")?, // backspace - '\x0C' => f.write_str("\\f")?, // form feed - '\n' => f.write_str("\\n")?, // line feed - '\r' => f.write_str("\\r")?, // carriage return - '\t' => f.write_str("\\t")?, // horizontal tab - _ => f.write_char(c)?, - }; - } - Ok(()) - } -} - -#[derive(Debug, Copy, Clone)] -pub struct Digest { - inner: [u8; N], -} - -impl ops::Index for Digest { - type Output = u8; - - fn index(&self, index: usize) -> &Self::Output { - &self.inner[index] - } -} - -impl Digest { - pub fn as_bytes(&self) -> &[u8; N] { - &self.inner - } -} - -impl fmt::Display for Digest { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - HexFmt(&self.inner).fmt(f) - } -} - -impl Digest { - pub fn new(data: [u8; N]) -> Self { - Self { inner: data } - } -} - -impl From<[u8; N]> for Digest { - fn from(value: [u8; N]) -> Self { - Self::new(value) - } -} - -impl From> for [u8; N] { - fn from(val: Digest) -> Self { - val.inner - } -} - -impl FromStr for Digest { - type Err = ParseHexError; - - fn from_str(value: &str) -> Result { - let mut buf = [0u8; N]; - parse_hex_exact(value, &mut buf)?; - Ok(buf.into()) - } -} - -impl ConstantTimeEq for Digest { - fn ct_eq(&self, other: &Self) -> subtle::Choice { - self.inner.ct_eq(&other.inner) - } -} - -impl PartialEq for Digest { - fn eq(&self, other: &Self) -> bool { - self.ct_eq(other).into() - } -} - -impl Eq for Digest {} - -impl<'de, const N: usize> Deserialize<'de> for Digest { - fn deserialize(deserializer: D) -> Result - where - D: serde::Deserializer<'de>, - { - let hex = <&str>::deserialize(deserializer)?; - Digest::from_str(hex).map_err(de::Error::custom) - } -} - -impl Serialize for Digest { - fn serialize(&self, serializer: S) -> Result - where - S: serde::Serializer, - { - serializer.serialize_str(&format!("{self}")) - } -} - -pub type Key = SafeByteArray<64>; - -pub fn load_key(path: &str) -> Result { - let key_str = std::fs::read_to_string(path).map_err(ReadHexError::Io)?; - key_str.trim().parse().map_err(ReadHexError::Format) -} diff --git a/rs/git-lfs-authenticate/Cargo.toml b/rs/git-lfs-authenticate/Cargo.toml deleted file mode 100644 index 217250f..0000000 --- a/rs/git-lfs-authenticate/Cargo.toml +++ /dev/null @@ -1,8 +0,0 @@ -[package] -name = "git-lfs-authenticate" -version = "0.1.0" -edition = "2021" - -[dependencies] -chrono = "0.4" -common = { path = "../common" } diff --git a/rs/git-lfs-authenticate/src/main.rs b/rs/git-lfs-authenticate/src/main.rs deleted file mode 100644 index 36d7818..0000000 --- a/rs/git-lfs-authenticate/src/main.rs +++ /dev/null @@ -1,236 +0,0 @@ -use std::{fmt, process::ExitCode, time::Duration}; - -use chrono::Utc; -use common::{Operation, ParseOperationError}; - -fn help() { - eprintln!("Usage: git-lfs-authenticate upload/download"); -} - -#[derive(Debug, Eq, PartialEq, Copy, Clone)] -enum RepoNameError { - TooLong, - UnresolvedPath, - AbsolutePath, - MissingGitSuffix, -} - -impl fmt::Display for RepoNameError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match self { - Self::TooLong => write!(f, "too long (more than 100 characters)"), - Self::UnresolvedPath => { - write!(f, "contains path one or more path elements '.' and '..'") - } - Self::AbsolutePath => { - write!(f, "starts with '/', which is not allowed") - } - Self::MissingGitSuffix => write!(f, "misses '.git' suffix"), - } - } -} - -// Using `Result<(), E>` here instead of `Option` because `None` typically signifies some error -// state with no further details provided. If we were to return an `Option` type, the user would -// have to first transform it into a `Result` type in order to use the `?` operator, meaning that -// they would have to the following operation to get the type into the right shape: -// `validate_repo_path(path).map_or(Ok(()), Err)`. That would not be very ergonomic. -fn validate_repo_path(path: &str) -> Result<(), RepoNameError> { - if path.len() > 100 { - return Err(RepoNameError::TooLong); - } - if path.contains("//") - || path.contains("/./") - || path.contains("/../") - || path.starts_with("./") - || path.starts_with("../") - { - return Err(RepoNameError::UnresolvedPath); - } - if path.starts_with('/') { - return Err(RepoNameError::AbsolutePath); - } - if !path.ends_with(".git") { - return Err(RepoNameError::MissingGitSuffix); - } - Ok(()) -} - -#[derive(Debug, Eq, PartialEq, Copy, Clone)] -enum ParseCmdlineError { - UnknownOperation(ParseOperationError), - InvalidRepoName(RepoNameError), - UnexpectedArgCount(ArgCountError), -} - -impl From for ParseCmdlineError { - fn from(value: RepoNameError) -> Self { - Self::InvalidRepoName(value) - } -} - -impl From for ParseCmdlineError { - fn from(value: ParseOperationError) -> Self { - Self::UnknownOperation(value) - } -} - -impl From for ParseCmdlineError { - fn from(value: ArgCountError) -> Self { - Self::UnexpectedArgCount(value) - } -} - -impl fmt::Display for ParseCmdlineError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match self { - Self::UnknownOperation(e) => write!(f, "unknown operation: {e}"), - Self::InvalidRepoName(e) => write!(f, "invalid repository name: {e}"), - Self::UnexpectedArgCount(e) => e.fmt(f), - } - } -} - -#[derive(Debug, Eq, PartialEq, Copy, Clone)] -struct ArgCountError { - provided: usize, - expected: usize, -} - -impl fmt::Display for ArgCountError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!( - f, - "got {} argument(s), expected {}", - self.provided, self.expected - ) - } -} - -fn get_cmdline_args() -> Result<[String; N], ArgCountError> { - let args = std::env::args(); - if args.len() - 1 != N { - return Err(ArgCountError { - provided: args.len() - 1, - expected: N, - }); - } - - // Does not allocate. - const EMPTY_STRING: String = String::new(); - let mut values = [EMPTY_STRING; N]; - - // Skip the first element; we do not care about the program name. - for (i, arg) in args.skip(1).enumerate() { - values[i] = arg - } - Ok(values) -} - -fn parse_cmdline() -> Result<(String, Operation), ParseCmdlineError> { - let [repo_path, op_str] = get_cmdline_args::<2>()?; - let op: Operation = op_str.parse()?; - validate_repo_path(&repo_path)?; - Ok((repo_path.to_string(), op)) -} - -fn repo_exists(name: &str) -> bool { - match std::fs::metadata(name) { - Ok(metadata) => metadata.is_dir(), - _ => false, - } -} - -struct Config { - href_base: String, - key_path: String, -} - -#[derive(Debug, Eq, PartialEq, Copy, Clone)] -enum LoadConfigError { - BaseUrlNotProvided, - BaseUrlSlashSuffixMissing, - KeyPathNotProvided, -} - -impl fmt::Display for LoadConfigError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - Self::BaseUrlNotProvided => write!(f, "base URL not provided"), - Self::BaseUrlSlashSuffixMissing => write!(f, "base URL does not end with slash"), - Self::KeyPathNotProvided => write!(f, "key path not provided"), - } - } -} - -fn load_config() -> Result { - let Ok(href_base) = std::env::var("GITOLFS3_HREF_BASE") else { - return Err(LoadConfigError::BaseUrlNotProvided); - }; - if !href_base.ends_with('/') { - return Err(LoadConfigError::BaseUrlSlashSuffixMissing); - } - let Ok(key_path) = std::env::var("GITOLFS3_KEY_PATH") else { - return Err(LoadConfigError::KeyPathNotProvided); - }; - Ok(Config { - href_base, - key_path, - }) -} - -fn main() -> ExitCode { - let config = match load_config() { - Ok(config) => config, - Err(e) => { - eprintln!("Failed to load config: {e}"); - return ExitCode::FAILURE; - } - }; - let key = match common::load_key(&config.key_path) { - Ok(key) => key, - Err(e) => { - eprintln!("Failed to load key: {e}"); - return ExitCode::FAILURE; - } - }; - - let (repo_name, operation) = match parse_cmdline() { - Ok(args) => args, - Err(e) => { - eprintln!("Error: {e}\n"); - help(); - // Exit code 2 signifies bad usage of CLI. - return ExitCode::from(2); - } - }; - - if !repo_exists(&repo_name) { - eprintln!("Error: repository does not exist"); - return ExitCode::FAILURE; - } - - let expires_at = Utc::now() + Duration::from_secs(5 * 60); - let Some(tag) = common::generate_tag( - common::Claims { - specific_claims: common::SpecificClaims::BatchApi(operation), - repo_path: &repo_name, - expires_at, - }, - key, - ) else { - eprintln!("Failed to generate validation tag"); - return ExitCode::FAILURE; - }; - - println!( - "{{\"header\":{{\"Authorization\":\"Gitolfs3-Hmac-Sha256 {tag} {}\"}},\ - \"expires_at\":\"{}\",\"href\":\"{}{}/info/lfs\"}}", - expires_at.timestamp(), - common::EscJsonFmt(&expires_at.to_rfc3339_opts(chrono::SecondsFormat::Secs, true)), - common::EscJsonFmt(&config.href_base), - common::EscJsonFmt(&repo_name), - ); - - ExitCode::SUCCESS -} diff --git a/rs/server/Cargo.toml b/rs/server/Cargo.toml deleted file mode 100644 index edb76d8..0000000 --- a/rs/server/Cargo.toml +++ /dev/null @@ -1,19 +0,0 @@ -[package] -name = "server" -version = "0.1.0" -edition = "2021" - -[dependencies] -aws-config = { version = "1.1.2" } -aws-sdk-s3 = "1.12.0" -axum = "0.7" -base64 = "0.21" -chrono = { version = "0.4", features = ["serde"] } -common = { path = "../common" } -mime = "0.3" -serde = { version = "1", features = ["derive"] } -serde_json = "1" -tokio = { version = "1.35", features = ["full"] } -tokio-util = "0.7" -tower = "0.4" -tracing-subscriber = { version = "0.3", features = ["env-filter"] } diff --git a/rs/server/src/main.rs b/rs/server/src/main.rs deleted file mode 100644 index 8baa0d6..0000000 --- a/rs/server/src/main.rs +++ /dev/null @@ -1,1028 +0,0 @@ -use std::collections::HashMap; -use std::collections::HashSet; -use std::process::ExitCode; -use std::sync::Arc; - -use aws_sdk_s3::error::SdkError; -use aws_sdk_s3::operation::head_object::HeadObjectOutput; -use axum::extract::rejection; -use axum::extract::FromRequest; -use axum::extract::Path; -use axum::extract::State; -use axum::http::header; -use axum::http::HeaderMap; -use axum::http::HeaderValue; -use axum::response::Response; -use axum::Json; -use axum::ServiceExt; -use base64::prelude::*; -use chrono::DateTime; -use chrono::Utc; -use common::HexByte; -use serde::de; -use serde::de::DeserializeOwned; -use serde::Deserialize; -use serde::Serialize; -use tower::Layer; - -use axum::{ - async_trait, - extract::{FromRequestParts, OriginalUri, Request}, - http::{request::Parts, StatusCode, Uri}, - response::IntoResponse, - routing::{get, post}, - Extension, Router, -}; - -#[derive(Clone)] -struct RepositoryName(String); - -struct RepositoryNameRejection; - -impl IntoResponse for RepositoryNameRejection { - fn into_response(self) -> Response { - (StatusCode::INTERNAL_SERVER_ERROR, "Missing repository name").into_response() - } -} - -#[async_trait] -impl FromRequestParts for RepositoryName { - type Rejection = RepositoryNameRejection; - - async fn from_request_parts(parts: &mut Parts, state: &S) -> Result { - let Ok(Extension(repo_name)) = Extension::::from_request_parts(parts, state).await - else { - return Err(RepositoryNameRejection); - }; - Ok(repo_name) - } -} - -async fn rewrite_url( - mut req: axum::http::Request, -) -> Result, StatusCode> { - let uri = req.uri(); - let original_uri = OriginalUri(uri.clone()); - - let Some(path_and_query) = uri.path_and_query() else { - // L @ no path & query - return Err(StatusCode::BAD_REQUEST); - }; - let Some((repo, path)) = path_and_query.path().split_once("/info/lfs/objects") else { - return Err(StatusCode::NOT_FOUND); - }; - let repo = repo - .trim_start_matches('/') - .trim_end_matches('/') - .to_string(); - if !path.starts_with('/') || !repo.ends_with(".git") { - return Err(StatusCode::NOT_FOUND); - } - - let mut parts = uri.clone().into_parts(); - parts.path_and_query = match path_and_query.query() { - None => path.try_into().ok(), - Some(q) => format!("{path}?{q}").try_into().ok(), - }; - let Ok(new_uri) = Uri::from_parts(parts) else { - return Err(StatusCode::INTERNAL_SERVER_ERROR); - }; - - *req.uri_mut() = new_uri; - req.extensions_mut().insert(original_uri); - req.extensions_mut().insert(RepositoryName(repo)); - - Ok(req) -} - -struct AppState { - s3_client: aws_sdk_s3::Client, - s3_bucket: String, - authz_conf: AuthorizationConfig, - // Should not end with a slash. - base_url: String, -} - -struct Env { - s3_access_key_id: String, - s3_secret_access_key: String, - s3_bucket: String, - s3_region: String, - s3_endpoint: String, - base_url: String, - key_path: String, - listen_host: String, - listen_port: String, - trusted_forwarded_hosts: String, -} - -fn require_env(name: &str) -> Result { - std::env::var(name) - .map_err(|_| format!("environment variable {name} should be defined and valid")) -} - -impl Env { - fn load() -> Result { - Ok(Env { - s3_secret_access_key: require_env("GITOLFS3_S3_SECRET_ACCESS_KEY_FILE")?, - s3_access_key_id: require_env("GITOLFS3_S3_ACCESS_KEY_ID_FILE")?, - s3_region: require_env("GITOLFS3_S3_REGION")?, - s3_endpoint: require_env("GITOLFS3_S3_ENDPOINT")?, - s3_bucket: require_env("GITOLFS3_S3_BUCKET")?, - base_url: require_env("GITOLFS3_BASE_URL")?, - key_path: require_env("GITOLFS3_KEY_PATH")?, - listen_host: require_env("GITOLFS3_LISTEN_HOST")?, - listen_port: require_env("GITOLFS3_LISTEN_PORT")?, - trusted_forwarded_hosts: std::env::var("GITOLFS3_TRUSTED_FORWARDED_HOSTS") - .unwrap_or_default(), - }) - } -} - -fn get_s3_client(env: &Env) -> Result { - let access_key_id = std::fs::read_to_string(&env.s3_access_key_id)?; - let secret_access_key = std::fs::read_to_string(&env.s3_secret_access_key)?; - - let credentials = aws_sdk_s3::config::Credentials::new( - access_key_id, - secret_access_key, - None, - None, - "gitolfs3-env", - ); - let config = aws_config::SdkConfig::builder() - .behavior_version(aws_config::BehaviorVersion::latest()) - .region(aws_config::Region::new(env.s3_region.clone())) - .endpoint_url(&env.s3_endpoint) - .credentials_provider(aws_sdk_s3::config::SharedCredentialsProvider::new( - credentials, - )) - .build(); - Ok(aws_sdk_s3::Client::new(&config)) -} - -#[tokio::main] -async fn main() -> ExitCode { - tracing_subscriber::fmt::init(); - - let env = match Env::load() { - Ok(env) => env, - Err(e) => { - println!("Failed to load configuration: {e}"); - return ExitCode::from(2); - } - }; - - let s3_client = match get_s3_client(&env) { - Ok(s3_client) => s3_client, - Err(e) => { - println!("Failed to create S3 client: {e}"); - return ExitCode::FAILURE; - } - }; - let key = match common::load_key(&env.key_path) { - Ok(key) => key, - Err(e) => { - println!("Failed to load Gitolfs3 key: {e}"); - return ExitCode::FAILURE; - } - }; - - let trusted_forwarded_hosts: HashSet = env - .trusted_forwarded_hosts - .split(',') - .map(|s| s.to_owned()) - .filter(|s| !s.is_empty()) - .collect(); - let base_url = env.base_url.trim_end_matches('/').to_string(); - - let authz_conf = AuthorizationConfig { - key, - trusted_forwarded_hosts, - }; - - let shared_state = Arc::new(AppState { - s3_client, - s3_bucket: env.s3_bucket, - authz_conf, - base_url, - }); - let app = Router::new() - .route("/batch", post(batch)) - .route("/:oid0/:oid1/:oid", get(obj_download)) - .with_state(shared_state); - - let middleware = axum::middleware::map_request(rewrite_url); - let app_with_middleware = middleware.layer(app); - - let Ok(listen_port): Result = env.listen_port.parse() else { - println!("Configured LISTEN_PORT should be an unsigned integer no higher than 65535"); - return ExitCode::from(2); - }; - let addr: (String, u16) = (env.listen_host, listen_port); - let listener = match tokio::net::TcpListener::bind(addr).await { - Ok(listener) => listener, - Err(e) => { - println!("Failed to listen: {e}"); - return ExitCode::FAILURE; - } - }; - - match axum::serve(listener, app_with_middleware.into_make_service()).await { - Ok(_) => ExitCode::SUCCESS, - Err(e) => { - println!("Error serving: {e}"); - ExitCode::FAILURE - } - } -} - -#[derive(Debug, Serialize, Deserialize, PartialEq, Eq, Clone, Copy)] -enum TransferAdapter { - #[serde(rename = "basic")] - Basic, - #[serde(other)] - Unknown, -} - -#[derive(Debug, Serialize, Deserialize, PartialEq, Eq, Clone, Copy)] -enum HashAlgo { - #[serde(rename = "sha256")] - Sha256, - #[serde(other)] - Unknown, -} - -impl Default for HashAlgo { - fn default() -> Self { - Self::Sha256 - } -} - -#[derive(Debug, Deserialize, PartialEq, Eq, Clone)] -struct BatchRequestObject { - oid: common::Oid, - size: i64, -} - -#[derive(Debug, Serialize, Deserialize, Clone)] -struct BatchRef { - name: String, -} - -fn default_transfers() -> Vec { - vec![TransferAdapter::Basic] -} - -#[derive(Debug, Deserialize, PartialEq, Eq, Clone)] -struct BatchRequest { - operation: common::Operation, - #[serde(default = "default_transfers")] - transfers: Vec, - objects: Vec, - #[serde(default)] - hash_algo: HashAlgo, -} - -#[derive(Debug, Clone)] -struct GitLfsJson(Json); - -const LFS_MIME: &str = "application/vnd.git-lfs+json"; - -enum GitLfsJsonRejection { - Json(rejection::JsonRejection), - MissingGitLfsJsonContentType, -} - -impl IntoResponse for GitLfsJsonRejection { - fn into_response(self) -> Response { - match self { - Self::Json(rej) => rej.into_response(), - Self::MissingGitLfsJsonContentType => make_error_resp( - StatusCode::UNSUPPORTED_MEDIA_TYPE, - &format!("Expected request with `Content-Type: {LFS_MIME}`"), - ) - .into_response(), - } - } -} - -fn is_git_lfs_json_mimetype(mimetype: &str) -> bool { - let Ok(mime) = mimetype.parse::() else { - return false; - }; - if mime.type_() != mime::APPLICATION - || mime.subtype() != "vnd.git-lfs" - || mime.suffix() != Some(mime::JSON) - { - return false; - } - match mime.get_param(mime::CHARSET) { - Some(mime::UTF_8) | None => true, - Some(_) => false, - } -} - -fn has_git_lfs_json_content_type(req: &Request) -> bool { - let Some(content_type) = req.headers().get(header::CONTENT_TYPE) else { - return false; - }; - let Ok(content_type) = content_type.to_str() else { - return false; - }; - is_git_lfs_json_mimetype(content_type) -} - -#[async_trait] -impl FromRequest for GitLfsJson -where - T: DeserializeOwned, - S: Send + Sync, -{ - type Rejection = GitLfsJsonRejection; - - async fn from_request(req: Request, state: &S) -> Result { - if !has_git_lfs_json_content_type(&req) { - return Err(GitLfsJsonRejection::MissingGitLfsJsonContentType); - } - Json::::from_request(req, state) - .await - .map(GitLfsJson) - .map_err(GitLfsJsonRejection::Json) - } -} - -impl IntoResponse for GitLfsJson { - fn into_response(self) -> Response { - let GitLfsJson(json) = self; - let mut resp = json.into_response(); - resp.headers_mut().insert( - header::CONTENT_TYPE, - HeaderValue::from_static("application/vnd.git-lfs+json; charset=utf-8"), - ); - resp - } -} - -#[derive(Debug, Serialize)] -struct GitLfsErrorData<'a> { - message: &'a str, -} - -type GitLfsErrorResponse<'a> = (StatusCode, GitLfsJson>); - -const fn make_error_resp(code: StatusCode, message: &str) -> GitLfsErrorResponse { - (code, GitLfsJson(Json(GitLfsErrorData { message }))) -} - -#[derive(Debug, Serialize, Clone)] -struct BatchResponseObjectAction { - href: String, - #[serde(skip_serializing_if = "HashMap::is_empty")] - header: HashMap, - expires_at: DateTime, -} - -#[derive(Default, Debug, Serialize, Clone)] -struct BatchResponseObjectActions { - #[serde(skip_serializing_if = "Option::is_none")] - upload: Option, - #[serde(skip_serializing_if = "Option::is_none")] - download: Option, - #[serde(skip_serializing_if = "Option::is_none")] - verify: Option, -} - -#[derive(Debug, Clone, Serialize)] -struct BatchResponseObjectError { - code: u16, - message: String, -} - -#[derive(Debug, Serialize, Clone)] -struct BatchResponseObject { - oid: common::Oid, - size: i64, - #[serde(skip_serializing_if = "Option::is_none")] - authenticated: Option, - actions: BatchResponseObjectActions, - #[serde(skip_serializing_if = "Option::is_none")] - error: Option, -} - -impl BatchResponseObject { - fn error(obj: &BatchRequestObject, code: StatusCode, message: String) -> BatchResponseObject { - BatchResponseObject { - oid: obj.oid, - size: obj.size, - authenticated: None, - actions: Default::default(), - error: Some(BatchResponseObjectError { - code: code.as_u16(), - message, - }), - } - } -} - -#[derive(Debug, Serialize, Clone)] -struct BatchResponse { - transfer: TransferAdapter, - objects: Vec, - hash_algo: HashAlgo, -} - -fn validate_checksum(oid: common::Oid, obj: &HeadObjectOutput) -> bool { - if let Some(checksum) = obj.checksum_sha256() { - if let Ok(checksum) = BASE64_STANDARD.decode(checksum) { - if let Ok(checksum32b) = TryInto::<[u8; 32]>::try_into(checksum) { - return common::Oid::from(checksum32b) == oid; - } - } - } - true -} - -fn validate_size(expected: i64, obj: &HeadObjectOutput) -> bool { - if let Some(length) = obj.content_length() { - return length == expected; - } - true -} - -async fn handle_upload_object( - state: &AppState, - repo: &str, - obj: &BatchRequestObject, -) -> Option { - let (oid0, oid1) = (HexByte(obj.oid[0]), HexByte(obj.oid[1])); - let full_path = format!("{repo}/lfs/objects/{}/{}/{}", oid0, oid1, obj.oid); - - match state - .s3_client - .head_object() - .bucket(&state.s3_bucket) - .key(full_path.clone()) - .checksum_mode(aws_sdk_s3::types::ChecksumMode::Enabled) - .send() - .await - { - Ok(result) => { - if validate_size(obj.size, &result) && validate_checksum(obj.oid, &result) { - return None; - } - } - Err(SdkError::ServiceError(e)) if e.err().is_not_found() => {} - Err(e) => { - println!("Failed to HeadObject (repo {repo}, OID {}): {e}", obj.oid); - return Some(BatchResponseObject::error( - obj, - StatusCode::INTERNAL_SERVER_ERROR, - "Failed to query object information".to_string(), - )); - } - }; - - let expires_in = std::time::Duration::from_secs(5 * 60); - let expires_at = Utc::now() + expires_in; - - let Ok(config) = aws_sdk_s3::presigning::PresigningConfig::expires_in(expires_in) else { - return Some(BatchResponseObject::error( - obj, - StatusCode::INTERNAL_SERVER_ERROR, - "Failed to generate upload URL".to_string(), - )); - }; - let Ok(presigned) = state - .s3_client - .put_object() - .bucket(&state.s3_bucket) - .key(full_path) - .checksum_sha256(obj.oid.to_string()) - .content_length(obj.size) - .presigned(config) - .await - else { - return Some(BatchResponseObject::error( - obj, - StatusCode::INTERNAL_SERVER_ERROR, - "Failed to generate upload URL".to_string(), - )); - }; - Some(BatchResponseObject { - oid: obj.oid, - size: obj.size, - authenticated: Some(true), - actions: BatchResponseObjectActions { - upload: Some(BatchResponseObjectAction { - header: presigned - .headers() - .map(|(k, v)| (k.to_owned(), v.to_owned())) - .collect(), - expires_at, - href: presigned.uri().to_string(), - }), - ..Default::default() - }, - error: None, - }) -} - -async fn handle_download_object( - state: &AppState, - repo: &str, - obj: &BatchRequestObject, - trusted: bool, -) -> BatchResponseObject { - let (oid0, oid1) = (HexByte(obj.oid[0]), HexByte(obj.oid[1])); - let full_path = format!("{repo}/lfs/objects/{}/{}/{}", oid0, oid1, obj.oid); - - let result = match state - .s3_client - .head_object() - .bucket(&state.s3_bucket) - .key(&full_path) - .checksum_mode(aws_sdk_s3::types::ChecksumMode::Enabled) - .send() - .await - { - Ok(result) => result, - Err(e) => { - println!("Failed to HeadObject (repo {repo}, OID {}): {e}", obj.oid); - return BatchResponseObject::error( - obj, - StatusCode::INTERNAL_SERVER_ERROR, - "Failed to query object information".to_string(), - ); - } - }; - - // Scaleway actually doesn't provide SHA256 suport, but maybe in the future :) - if !validate_checksum(obj.oid, &result) { - return BatchResponseObject::error( - obj, - StatusCode::UNPROCESSABLE_ENTITY, - "Object corrupted".to_string(), - ); - } - if !validate_size(obj.size, &result) { - return BatchResponseObject::error( - obj, - StatusCode::UNPROCESSABLE_ENTITY, - "Incorrect size specified (or object corrupted)".to_string(), - ); - } - - let expires_in = std::time::Duration::from_secs(5 * 60); - let expires_at = Utc::now() + expires_in; - - if trusted { - let Ok(config) = aws_sdk_s3::presigning::PresigningConfig::expires_in(expires_in) else { - return BatchResponseObject::error( - obj, - StatusCode::INTERNAL_SERVER_ERROR, - "Failed to generate upload URL".to_string(), - ); - }; - let Ok(presigned) = state - .s3_client - .get_object() - .bucket(&state.s3_bucket) - .key(full_path) - .presigned(config) - .await - else { - return BatchResponseObject::error( - obj, - StatusCode::INTERNAL_SERVER_ERROR, - "Failed to generate upload URL".to_string(), - ); - }; - return BatchResponseObject { - oid: obj.oid, - size: obj.size, - authenticated: Some(true), - actions: BatchResponseObjectActions { - download: Some(BatchResponseObjectAction { - header: presigned - .headers() - .map(|(k, v)| (k.to_owned(), v.to_owned())) - .collect(), - expires_at, - href: presigned.uri().to_string(), - }), - ..Default::default() - }, - error: None, - }; - } - - let Some(tag) = common::generate_tag( - common::Claims { - specific_claims: common::SpecificClaims::Download(obj.oid), - repo_path: repo, - expires_at, - }, - &state.authz_conf.key, - ) else { - return BatchResponseObject::error( - obj, - StatusCode::INTERNAL_SERVER_ERROR, - "Internal server error".to_string(), - ); - }; - - let upload_path = format!( - "{repo}/info/lfs/objects/{}/{}/{}", - HexByte(obj.oid[0]), - HexByte(obj.oid[1]), - obj.oid, - ); - - BatchResponseObject { - oid: obj.oid, - size: obj.size, - authenticated: Some(true), - actions: BatchResponseObjectActions { - download: Some(BatchResponseObjectAction { - header: { - let mut map = HashMap::new(); - map.insert( - "Authorization".to_string(), - format!("Gitolfs3-Hmac-Sha256 {tag} {}", expires_at.timestamp()), - ); - map - }, - expires_at, - href: format!("{}/{upload_path}", state.base_url), - }), - ..Default::default() - }, - error: None, - } -} - -struct AuthorizationConfig { - trusted_forwarded_hosts: HashSet, - key: common::Key, -} - -struct Trusted(bool); - -fn forwarded_for_trusted_host( - headers: &HeaderMap, - trusted: &HashSet, -) -> Result> { - if let Some(forwarded_for) = headers.get("X-Forwarded-For") { - if let Ok(forwarded_for) = forwarded_for.to_str() { - if trusted.contains(forwarded_for) { - return Ok(true); - } - } else { - return Err(make_error_resp( - StatusCode::NOT_FOUND, - "Invalid X-Forwarded-For header", - )); - } - } - Ok(false) -} -const REPO_NOT_FOUND: GitLfsErrorResponse = - make_error_resp(StatusCode::NOT_FOUND, "Repository not found"); - -fn authorize_batch( - conf: &AuthorizationConfig, - repo_path: &str, - public: bool, - operation: common::Operation, - headers: &HeaderMap, -) -> Result> { - // - No authentication required for downloading exported repos - // - When authenticated: - // - Download / upload over presigned URLs - // - When accessing over Tailscale: - // - No authentication required for downloading from any repo - - let claims = VerifyClaimsInput { - specific_claims: common::SpecificClaims::BatchApi(operation), - repo_path, - }; - if verify_claims(conf, &claims, headers)? { - return Ok(Trusted(true)); - } - - let trusted = forwarded_for_trusted_host(headers, &conf.trusted_forwarded_hosts)?; - if operation != common::Operation::Download { - if trusted { - return Err(make_error_resp( - StatusCode::FORBIDDEN, - "Authentication required to upload", - )); - } - return Err(REPO_NOT_FOUND); - } - if trusted { - return Ok(Trusted(true)); - } - - if public { - Ok(Trusted(false)) - } else { - Err(REPO_NOT_FOUND) - } -} - -fn repo_exists(name: &str) -> bool { - let Ok(metadata) = std::fs::metadata(name) else { - return false; - }; - metadata.is_dir() -} - -fn is_repo_public(name: &str) -> Option { - if !repo_exists(name) { - return None; - } - std::fs::metadata(format!("{name}/git-daemon-export-ok")) - .ok()? - .is_file() - .into() -} - -async fn batch( - State(state): State>, - headers: HeaderMap, - RepositoryName(repo): RepositoryName, - GitLfsJson(Json(payload)): GitLfsJson, -) -> Response { - let Some(public) = is_repo_public(&repo) else { - return REPO_NOT_FOUND.into_response(); - }; - let Trusted(trusted) = match authorize_batch( - &state.authz_conf, - &repo, - public, - payload.operation, - &headers, - ) { - Ok(authn) => authn, - Err(e) => return e.into_response(), - }; - - if !headers - .get_all("Accept") - .iter() - .filter_map(|v| v.to_str().ok()) - .any(is_git_lfs_json_mimetype) - { - let message = format!("Expected `{LFS_MIME}` in list of acceptable response media types"); - return make_error_resp(StatusCode::NOT_ACCEPTABLE, &message).into_response(); - } - - if payload.hash_algo != HashAlgo::Sha256 { - let message = "Unsupported hashing algorithm specified"; - return make_error_resp(StatusCode::CONFLICT, message).into_response(); - } - if !payload.transfers.is_empty() && !payload.transfers.contains(&TransferAdapter::Basic) { - let message = "Unsupported transfer adapter specified (supported: basic)"; - return make_error_resp(StatusCode::CONFLICT, message).into_response(); - } - - let mut resp = BatchResponse { - transfer: TransferAdapter::Basic, - objects: vec![], - hash_algo: HashAlgo::Sha256, - }; - for obj in payload.objects { - match payload.operation { - common::Operation::Download => resp - .objects - .push(handle_download_object(&state, &repo, &obj, trusted).await), - common::Operation::Upload => { - if let Some(obj_resp) = handle_upload_object(&state, &repo, &obj).await { - resp.objects.push(obj_resp); - } - } - }; - } - GitLfsJson(Json(resp)).into_response() -} - -#[derive(Deserialize, Copy, Clone)] -#[serde(remote = "Self")] -struct FileParams { - oid0: HexByte, - oid1: HexByte, - oid: common::Oid, -} - -impl<'de> Deserialize<'de> for FileParams { - fn deserialize(deserializer: D) -> Result - where - D: serde::Deserializer<'de>, - { - let unchecked @ FileParams { - oid0: HexByte(oid0), - oid1: HexByte(oid1), - oid, - } = FileParams::deserialize(deserializer)?; - if oid0 != oid.as_bytes()[0] { - return Err(de::Error::custom( - "first OID path part does not match first byte of full OID", - )); - } - if oid1 != oid.as_bytes()[1] { - return Err(de::Error::custom( - "second OID path part does not match first byte of full OID", - )); - } - Ok(unchecked) - } -} - -pub struct VerifyClaimsInput<'a> { - pub specific_claims: common::SpecificClaims, - pub repo_path: &'a str, -} - -fn verify_claims( - conf: &AuthorizationConfig, - claims: &VerifyClaimsInput, - headers: &HeaderMap, -) -> Result> { - const INVALID_AUTHZ_HEADER: GitLfsErrorResponse = - make_error_resp(StatusCode::BAD_REQUEST, "Invalid authorization header"); - - if let Some(authz) = headers.get(header::AUTHORIZATION) { - if let Ok(authz) = authz.to_str() { - if let Some(val) = authz.strip_prefix("Gitolfs3-Hmac-Sha256 ") { - let (tag, expires_at) = val.split_once(' ').ok_or(INVALID_AUTHZ_HEADER)?; - let tag: common::Digest<32> = tag.parse().map_err(|_| INVALID_AUTHZ_HEADER)?; - let expires_at: i64 = expires_at.parse().map_err(|_| INVALID_AUTHZ_HEADER)?; - let expires_at = - DateTime::::from_timestamp(expires_at, 0).ok_or(INVALID_AUTHZ_HEADER)?; - let Some(expected_tag) = common::generate_tag( - common::Claims { - specific_claims: claims.specific_claims, - repo_path: claims.repo_path, - expires_at, - }, - &conf.key, - ) else { - return Err(make_error_resp( - StatusCode::INTERNAL_SERVER_ERROR, - "Internal server error", - )); - }; - if tag == expected_tag { - return Ok(true); - } - } - } - return Err(INVALID_AUTHZ_HEADER); - } - Ok(false) -} - -fn authorize_get( - conf: &AuthorizationConfig, - repo_path: &str, - oid: common::Oid, - headers: &HeaderMap, -) -> Result<(), GitLfsErrorResponse<'static>> { - let claims = VerifyClaimsInput { - specific_claims: common::SpecificClaims::Download(oid), - repo_path, - }; - if !verify_claims(conf, &claims, headers)? { - return Err(make_error_resp( - StatusCode::UNAUTHORIZED, - "Repository not found", - )); - } - Ok(()) -} - -async fn obj_download( - State(state): State>, - headers: HeaderMap, - RepositoryName(repo): RepositoryName, - Path(FileParams { oid0, oid1, oid }): Path, -) -> Response { - if let Err(e) = authorize_get(&state.authz_conf, &repo, oid, &headers) { - return e.into_response(); - } - - let full_path = format!("{repo}/lfs/objects/{}/{}/{}", oid0, oid1, oid); - let result = match state - .s3_client - .get_object() - .bucket(&state.s3_bucket) - .key(full_path) - .checksum_mode(aws_sdk_s3::types::ChecksumMode::Enabled) - .send() - .await - { - Ok(result) => result, - Err(e) => { - println!("Failed to GetObject (repo {repo}, OID {oid}): {e}"); - return ( - StatusCode::INTERNAL_SERVER_ERROR, - "Failed to query object information", - ) - .into_response(); - } - }; - - let mut headers = header::HeaderMap::new(); - if let Some(content_type) = result.content_type { - let Ok(header_value) = content_type.try_into() else { - return ( - StatusCode::INTERNAL_SERVER_ERROR, - "Object has invalid content type", - ) - .into_response(); - }; - headers.insert(header::CONTENT_TYPE, header_value); - } - if let Some(content_length) = result.content_length { - headers.insert(header::CONTENT_LENGTH, content_length.into()); - } - - let async_read = result.body.into_async_read(); - let stream = tokio_util::io::ReaderStream::new(async_read); - let body = axum::body::Body::from_stream(stream); - - (headers, body).into_response() -} - -#[test] -fn test_mimetype() { - assert!(is_git_lfs_json_mimetype("application/vnd.git-lfs+json")); - assert!(!is_git_lfs_json_mimetype("application/vnd.git-lfs")); - assert!(!is_git_lfs_json_mimetype("application/json")); - assert!(is_git_lfs_json_mimetype( - "application/vnd.git-lfs+json; charset=utf-8" - )); - assert!(is_git_lfs_json_mimetype( - "application/vnd.git-lfs+json; charset=UTF-8" - )); - assert!(!is_git_lfs_json_mimetype( - "application/vnd.git-lfs+json; charset=ISO-8859-1" - )); -} - -#[test] -fn test_deserialize() { - let json = r#"{"operation":"upload","objects":[{"oid":"8f4123f9a7181f488c5e111d82cefd992e461ae5df01fd2254399e6e670b2d3c","size":170904}], - "transfers":["lfs-standalone-file","basic","ssh"],"ref":{"name":"refs/heads/main"},"hash_algo":"sha256"}"#; - let expected = BatchRequest { - operation: common::Operation::Upload, - objects: vec![BatchRequestObject { - oid: "8f4123f9a7181f488c5e111d82cefd992e461ae5df01fd2254399e6e670b2d3c" - .parse() - .unwrap(), - size: 170904, - }], - transfers: vec![ - TransferAdapter::Unknown, - TransferAdapter::Basic, - TransferAdapter::Unknown, - ], - hash_algo: HashAlgo::Sha256, - }; - assert_eq!( - serde_json::from_str::(json).unwrap(), - expected - ); -} - -#[test] -fn test_validate_claims() { - let key = "00232f7a019bd34e3921ee6c5f04caf48a4489d1be5d1999038950a7054e0bfea369ce2becc0f13fd3c69f8af2384a25b7ac2d52eb52c33722f3c00c50d4c9c2"; - let key: common::Key = key.parse().unwrap(); - - let claims = common::Claims { - expires_at: Utc::now() + std::time::Duration::from_secs(5 * 60), - repo_path: "lfs-test.git", - specific_claims: common::SpecificClaims::BatchApi(common::Operation::Download), - }; - let tag = common::generate_tag(claims, &key).unwrap(); - let header_value = format!( - "Gitolfs3-Hmac-Sha256 {tag} {}", - claims.expires_at.timestamp() - ); - - let conf = AuthorizationConfig { - key, - trusted_forwarded_hosts: HashSet::new(), - }; - let verification_claims = VerifyClaimsInput { - repo_path: claims.repo_path, - specific_claims: claims.specific_claims, - }; - let mut headers = HeaderMap::new(); - headers.insert(header::AUTHORIZATION, header_value.try_into().unwrap()); - - assert!(verify_claims(&conf, &verification_claims, &headers).unwrap()); -} diff --git a/rs/shell/Cargo.toml b/rs/shell/Cargo.toml deleted file mode 100644 index 0dcb6d6..0000000 --- a/rs/shell/Cargo.toml +++ /dev/null @@ -1,6 +0,0 @@ -[package] -name = "shell" -version = "0.1.0" -edition = "2021" - -[dependencies] diff --git a/rs/shell/src/main.rs b/rs/shell/src/main.rs deleted file mode 100644 index ef0ef48..0000000 --- a/rs/shell/src/main.rs +++ /dev/null @@ -1,143 +0,0 @@ -use std::{os::unix::process::CommandExt, process::ExitCode}; - -fn parse_sq(s: &str) -> Option<(String, &str)> { - #[derive(PartialEq, Eq)] - enum SqState { - Quoted, - Unquoted { may_escape: bool }, - UnquotedEscaped, - } - - let mut result = String::new(); - let mut state = SqState::Unquoted { may_escape: false }; - let mut remaining = ""; - for (i, c) in s.char_indices() { - match state { - SqState::Unquoted { may_escape: false } => { - if c != '\'' { - return None; - } - state = SqState::Quoted - } - SqState::Quoted => { - if c == '\'' { - state = SqState::Unquoted { may_escape: true }; - continue; - } - result.push(c); - } - SqState::Unquoted { may_escape: true } => { - if is_posix_space(c) { - remaining = &s[i..]; - break; - } - if c != '\\' { - return None; - } - state = SqState::UnquotedEscaped; - } - SqState::UnquotedEscaped => { - if c != '\\' && c != '!' { - return None; - } - result.push(c); - state = SqState::Unquoted { may_escape: false }; - } - } - } - - if state != (SqState::Unquoted { may_escape: true }) { - return None; - } - Some((result, remaining)) -} - -fn parse_cmd(mut cmd: &str) -> Option> { - let mut args = Vec::::new(); - - cmd = cmd.trim_matches(is_posix_space); - while cmd != "" { - if cmd.starts_with('\'') { - let (arg, remaining) = parse_sq(cmd)?; - args.push(arg); - cmd = remaining.trim_start_matches(is_posix_space); - } else if let Some((arg, remaining)) = cmd.split_once(is_posix_space) { - args.push(arg.to_owned()); - cmd = remaining.trim_start_matches(is_posix_space); - } else { - args.push(cmd.to_owned()); - cmd = ""; - } - } - - Some(args) -} - -fn is_posix_space(c: char) -> bool { - // Form feed: 0x0c - // Vertical tab: 0x0b - c == ' ' || c == '\x0c' || c == '\n' || c == '\r' || c == '\t' || c == '\x0b' -} - -fn main() -> ExitCode { - let bad_usage = ExitCode::from(2); - - let mut args = std::env::args().skip(1); - if args.next() != Some("-c".to_string()) { - eprintln!("Expected usage: shell -c "); - return bad_usage; - } - let Some(cmd) = args.next() else { - eprintln!("Missing argument for argument '-c'"); - return bad_usage; - }; - if args.next() != None { - eprintln!("Too many arguments passed"); - return bad_usage; - } - - let Some(mut cmd) = parse_cmd(&cmd) else { - eprintln!("Bad command"); - return bad_usage; - }; - - let Some(mut program) = cmd.drain(0..1).next() else { - eprintln!("Bad command"); - return bad_usage; - }; - if program == "git" { - let Some(subcommand) = cmd.drain(0..1).next() else { - eprintln!("Bad command"); - return bad_usage; - }; - program.push('-'); - program.push_str(&subcommand); - } - - let mut args = Vec::new(); - - let git_cmds = ["git-receive-pack", "git-upload-archive", "git-upload-pack"]; - if git_cmds.contains(&program.as_str()) { - if cmd.len() != 1 { - eprintln!("Bad command"); - return bad_usage; - } - let repository = cmd[0].trim_start_matches('/'); - args.push(repository); - } else if program == "git-lfs-authenticate" { - if cmd.len() != 2 { - eprintln!("Bad command"); - return bad_usage; - } - let repository = cmd[0].trim_start_matches('/'); - args.push(repository); - args.push(&cmd[1]); - } else { - eprintln!("Unknown command"); - return bad_usage; - } - - let e = std::process::Command::new(program).args(args).exec(); - eprintln!("Error: {e}"); - ExitCode::FAILURE -} -- cgit v1.2.3