diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 30cd9d5..6a49bd5 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -39,3 +39,24 @@ jobs: run: cargo clippy --all-targets --all-features --tests --benches -- -D warnings - name: Execute rust tests run: cargo nextest run --all-features + build-image: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Set up QEMU + uses: docker/setup-qemu-action@v2 + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v2 + - name: Login to Docker Hub + uses: docker/login-action@v2 + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + - name: Build and Push image + uses: docker/build-push-action@v4 + with: + context: . + push: true + platforms: linux/amd64 + tags: ${{ vars.LATEST_IMAGE }} diff --git a/Cargo.lock b/Cargo.lock index ae252e4..7b07bb1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -43,12 +43,6 @@ version = "0.2.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" -[[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" @@ -110,9 +104,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.99" +version = "1.0.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0674a1ddeecb70197781e945de4b3b8ffb61fa939a5597bcf48503737663100" +checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61" [[package]] name = "arbitrary" @@ -300,17 +294,16 @@ checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" [[package]] name = "chrono" -version = "0.4.41" +version = "0.4.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c469d952047f47f91b68d1cba3f10d63c11d73e4636f24f08daf0278abf01c4d" +checksum = "145052bdd345b87320e369255277e3fb5152762ad123a901ef5c262dd38fe8d2" dependencies = [ - "android-tzdata", "iana-time-zone", "js-sys", "num-traits", "serde", "wasm-bindgen", - "windows-link", + "windows-link 0.2.0", ] [[package]] @@ -347,9 +340,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.47" +version = "4.5.48" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7eac00902d9d136acd712710d71823fb8ac8004ca445a89e73a41d45aa712931" +checksum = "e2134bb3ea021b78629caa971416385309e0131b351b25e01dc16fb54e1b5fae" dependencies = [ "clap_builder", "clap_derive", @@ -357,9 +350,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.47" +version = "4.5.48" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ad9bbf750e73b5884fb8a211a9424a1906c1e156724260fdae972f31d70e1d6" +checksum = "c2ba64afa3c0a6df7fa517765e31314e983f51dda798ffba27b988194fb65dc9" dependencies = [ "anstream", "anstyle", @@ -596,12 +589,13 @@ dependencies = [ [[package]] name = "ctrlc" -version = "3.4.7" +version = "3.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46f93780a459b7d656ef7f071fe699c4d3d2cb201c4b24d085b6ddc505276e73" +checksum = "881c5d0a13b2f1498e2306e82cbada78390e152d4b1378fb28a84f4dcd0dc4f3" dependencies = [ + "dispatch", "nix", - "windows-sys 0.59.0", + "windows-sys 0.61.1", ] [[package]] @@ -671,9 +665,9 @@ dependencies = [ [[package]] name = "deranged" -version = "0.4.0" +version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c9e6a11ca8224451684bc0d7d5a7adbf8f2fd6887261a1cfc3c0432f9d4068e" +checksum = "a41953f86f8a05768a6cda24def994fd2f424b04ec5c719cf89989779f199071" dependencies = [ "powerfmt", ] @@ -727,6 +721,12 @@ dependencies = [ "subtle", ] +[[package]] +name = "dispatch" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd0c93bb4b0c6d9b77f4435b0ae98c24d17f1c45b2ff844c6151a07256ca923b" + [[package]] name = "displaydoc" version = "0.2.5" @@ -807,11 +807,12 @@ checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" [[package]] name = "erased-serde" -version = "0.4.6" +version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e004d887f51fcb9fef17317a2f3525c887d8aa3f4f50fed920816a688284a5b7" +checksum = "259d404d09818dec19332e31d94558aeb442fea04c817006456c24b5460bbd4b" dependencies = [ "serde", + "serde_core", "typeid", ] @@ -1108,9 +1109,9 @@ dependencies = [ [[package]] name = "getopts" -version = "0.2.23" +version = "0.2.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cba6ae63eb948698e300f645f87c70f76630d505f23b8907cf1e193ee85048c1" +checksum = "cfe4fbac503b8d1f88e6676011885f34b7174f46e59956bba534ba83abded4df" dependencies = [ "unicode-width", ] @@ -1596,13 +1597,14 @@ dependencies = [ [[package]] name = "hyper" -version = "1.6.0" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc2b571658e38e0c01b1fdca3bbbe93c00d3d71693ff2770043f8c29bc7d6f80" +checksum = "eb3aa54a13a0dfe7fbe3a59e0c76093041720fdc77b110cc0fc260fafb4dc51e" dependencies = [ + "atomic-waker", "bytes", "futures-channel", - "futures-util", + "futures-core", "h2", "http", "http-body", @@ -1610,6 +1612,7 @@ dependencies = [ "httpdate", "itoa", "pin-project-lite", + "pin-utils", "smallvec", "tokio", "want", @@ -1664,9 +1667,9 @@ dependencies = [ [[package]] name = "hyper-util" -version = "0.1.16" +version = "0.1.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d9b05277c7e8da2c93a568989bb6207bef0112e8d17df7a6eda4a3cf143bc5e" +checksum = "3c6995591a8f1380fcb4ba966a252a4b29188d51d2b89e3a252f5305be65aea8" dependencies = [ "base64", "bytes", @@ -1690,9 +1693,9 @@ dependencies = [ [[package]] name = "iana-time-zone" -version = "0.1.63" +version = "0.1.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0c919e5debc312ad217002b8048a17b7d83f80703865bbfcfebb0458b0b27d8" +checksum = "33e57f83510bb73707521ebaffa789ec8caf86f9657cad665b092b581d40e9fb" dependencies = [ "android_system_properties", "core-foundation-sys", @@ -1853,9 +1856,9 @@ dependencies = [ [[package]] name = "inherent" -version = "1.0.12" +version = "1.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c38228f24186d9cc68c729accb4d413be9eaed6ad07ff79e0270d9e56f3de13" +checksum = "c727f80bfa4a6c6e2508d2f05b6f4bfce242030bd88ed15ae5331c5b5d30fba7" dependencies = [ "proc-macro2", "quote", @@ -1959,9 +1962,9 @@ dependencies = [ [[package]] name = "jobserver" -version = "0.1.33" +version = "0.1.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38f262f097c174adebe41eb73d66ae9c06b2844fb0da69969647bbddd9b0538a" +checksum = "9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33" dependencies = [ "getrandom 0.3.3", "libc", @@ -2054,9 +2057,9 @@ checksum = "f9fbbcab51052fe104eb5e5d351cf728d30a5be1fe14d9be8a3b097481fb97de" [[package]] name = "libredox" -version = "0.1.9" +version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "391290121bad3d37fbddad76d8f5d1c1c314cfc646d143d7e07a3086ddff0ce3" +checksum = "416f7e718bdb06000964960ffa43b4335ad4012ae8b99060261aa4a8088d5ccb" dependencies = [ "bitflags", "libc", @@ -2220,9 +2223,9 @@ checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0" [[package]] name = "memmap2" -version = "0.9.7" +version = "0.9.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "483758ad303d734cec05e5c12b41d7e93e6a6390c5e9dae6bdeb7c1259012d28" +checksum = "843a98750cd611cc2965a8213b53b43e715f13c37a9e096c6408e69990961db7" dependencies = [ "libc", ] @@ -2645,9 +2648,9 @@ checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" [[package]] name = "pest" -version = "2.8.1" +version = "2.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1db05f56d34358a8b1066f67cbb203ee3e7ed2ba674a6263a1d5ec6db2204323" +checksum = "21e0a3a33733faeaf8651dfee72dd0f388f0c8e5ad496a3478fa5a922f49cfa8" dependencies = [ "memchr", "thiserror", @@ -2656,9 +2659,9 @@ dependencies = [ [[package]] name = "pest_derive" -version = "2.8.1" +version = "2.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb056d9e8ea77922845ec74a1c4e8fb17e7c218cc4fc11a15c5d25e189aa40bc" +checksum = "bc58706f770acb1dbd0973e6530a3cff4746fb721207feb3a8a6064cd0b6c663" dependencies = [ "pest", "pest_generator", @@ -2666,9 +2669,9 @@ dependencies = [ [[package]] name = "pest_generator" -version = "2.8.1" +version = "2.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87e404e638f781eb3202dc82db6760c8ae8a1eeef7fb3fa8264b2ef280504966" +checksum = "6d4f36811dfe07f7b8573462465d5cb8965fffc2e71ae377a33aecf14c2c9a2f" dependencies = [ "pest", "pest_meta", @@ -2679,9 +2682,9 @@ dependencies = [ [[package]] name = "pest_meta" -version = "2.8.1" +version = "2.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edd1101f170f5903fde0914f899bb503d9ff5271d7ba76bbb70bea63690cc0d5" +checksum = "42919b05089acbd0a5dcd5405fb304d17d1053847b81163d09c4ad18ce8e8420" dependencies = [ "pest", "sha2", @@ -2900,11 +2903,11 @@ checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" [[package]] name = "proc-macro-crate" -version = "3.3.0" +version = "3.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edce586971a4dfaa28950c6f18ed55e0406c1ab88bbce2c6f6293a7aaba73d35" +checksum = "219cb19e96be00ab2e37d6e299658a0cfa83e52429179969b0f0121b4ac46983" dependencies = [ - "toml_edit 0.22.27", + "toml_edit", ] [[package]] @@ -3032,9 +3035,9 @@ dependencies = [ [[package]] name = "regex" -version = "1.11.2" +version = "1.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23d7fd106d8c02486a8d64e778353d1cffe08ce79ac2e82f540c86d0facf6912" +checksum = "8b5288124840bee7b386bc413c487869b360b2b4ec421ea56425128692f2a82c" dependencies = [ "aho-corasick", "memchr", @@ -3044,9 +3047,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.9" +version = "0.4.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" +checksum = "833eb9ce86d40ef33cb1306d8accf7bc8ec2bfea4355cbdebb3df68b40925cad" dependencies = [ "aho-corasick", "memchr", @@ -3055,9 +3058,9 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.8.5" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" +checksum = "caf4aa5b0f434c91fe5c7f1ecb6a5ece2130b02ad2a590589dda5146df959001" [[package]] name = "reqwest" @@ -3239,9 +3242,9 @@ dependencies = [ [[package]] name = "rustls" -version = "0.23.31" +version = "0.23.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0ebcbd2f03de0fc1122ad9bb24b127a5a6cd51d72604a3f3c50ac459762b6cc" +checksum = "cd3c25631629d034ce7cd9940adc9d45762d46de2b0f57193c4443b92c6d4d40" dependencies = [ "log", "once_cell", @@ -3261,7 +3264,7 @@ dependencies = [ "openssl-probe", "rustls-pki-types", "schannel", - "security-framework 3.3.0", + "security-framework 3.5.0", ] [[package]] @@ -3275,9 +3278,9 @@ dependencies = [ [[package]] name = "rustls-webpki" -version = "0.103.4" +version = "0.103.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a17884ae0c1b773f1ccd2bd4a8c72f16da897310a98b0e84bf349ad5ead92fc" +checksum = "8572f3c2cb9934231157b45499fc41e1f58c589fdfb81a844ba873265e80f8eb" dependencies = [ "ring", "rustls-pki-types", @@ -3442,9 +3445,9 @@ dependencies = [ [[package]] name = "security-framework" -version = "3.3.0" +version = "3.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80fb1d92c5028aa318b4b8bd7302a5bfcf48be96a37fc6fc790f806b0004ee0c" +checksum = "cc198e42d9b7510827939c9a15f5062a0c913f3371d765977e586d2fe6c16f4a" dependencies = [ "bitflags", "core-foundation 0.10.1", @@ -3455,9 +3458,9 @@ dependencies = [ [[package]] name = "security-framework-sys" -version = "2.14.0" +version = "2.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49db231d56a190491cb4aeda9527f1ad45345af50b0851622a7adb8c03b01c32" +checksum = "cc1f0cbffaac4852523ce30d8bd3c5cdc873501d96ff467ca09b6767bb8cd5c0" dependencies = [ "core-foundation-sys", "libc", @@ -3484,9 +3487,9 @@ dependencies = [ [[package]] name = "semver" -version = "1.0.26" +version = "1.0.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56e6fa9c48d24d85fb3de5ad847117517440f6beceb7798af16b4a87d616b8d0" +checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2" [[package]] name = "serde" @@ -3542,12 +3545,13 @@ dependencies = [ [[package]] name = "serde_path_to_error" -version = "0.1.17" +version = "0.1.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59fab13f937fa393d08645bf3a84bdfe86e296747b506ada67bb15f10f218b2a" +checksum = "10a9ff822e371bb5403e391ecd83e182e0e77ba7f6fe0160b795797109d1b457" dependencies = [ "itoa", "serde", + "serde_core", ] [[package]] @@ -3707,18 +3711,18 @@ dependencies = [ [[package]] name = "snafu" -version = "0.8.7" +version = "0.8.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0062a372b26c4a6e9155d099a3416d732514fd47ae2f235b3695b820afcee74a" +checksum = "6e84b3f4eacbf3a1ce05eac6763b4d629d60cbc94d632e4092c54ade71f1e1a2" dependencies = [ "snafu-derive", ] [[package]] name = "snafu-derive" -version = "0.8.7" +version = "0.8.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e5fd9e3263fc19d73abd5107dbd4d43e37949212d2b15d4d334ee5db53022b8" +checksum = "c1c97747dbf44bb1ca44a561ece23508e99cb592e862f22222dcf42f51d1e451" dependencies = [ "heck 0.5.0", "proc-macro2", @@ -4218,9 +4222,9 @@ dependencies = [ [[package]] name = "time" -version = "0.3.41" +version = "0.3.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a7619e19bc266e0f9c5e6686659d394bc57973859340060a69221e57dbc0c40" +checksum = "91e7d9e3bb61134e77bde20dd4825b97c010155709965fedf0f49bb138e52a9d" dependencies = [ "deranged", "itoa", @@ -4235,15 +4239,15 @@ dependencies = [ [[package]] name = "time-core" -version = "0.1.4" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9e9a38711f559d9e3ce1cdb06dd7c5b8ea546bc90052da6d06bb76da74bb07c" +checksum = "40868e7c1d2f0b8d73e4a8c7f0ff63af4f6d19be117e90bd73eb1d62cf831c6b" [[package]] name = "time-macros" -version = "0.2.22" +version = "0.2.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3526739392ec93fd8b359c8e98514cb3e8e021beb4e5f597b00a0221f8ed8a49" +checksum = "30cfb0125f12d9c277f35663a0a33f8c30190f4e4574868a330595412d34ebf3" dependencies = [ "num-conv", "time-core", @@ -4261,9 +4265,9 @@ dependencies = [ [[package]] name = "tinyvec" -version = "1.9.0" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09b3661f17e86524eccd4371ab0429194e0d7c008abb45f7a7495b1719463c71" +checksum = "bfa5fdc3bce6191a1dbc8c02d5c8bffcf557bafa17c124c5264a458f1b0613fa" dependencies = [ "tinyvec_macros", ] @@ -4331,9 +4335,9 @@ dependencies = [ [[package]] name = "tokio-rustls" -version = "0.26.2" +version = "0.26.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e727b36a1a0e8b74c376ac2211e40c2c8af09fb4013c60d910495810f008e9b" +checksum = "05f63835928ca123f1bef57abbcd23bb2ba0ac9ae1235f1e65bda0d06e7786bd" dependencies = [ "rustls", "tokio", @@ -4363,12 +4367,6 @@ dependencies = [ "tokio", ] -[[package]] -name = "toml_datetime" -version = "0.6.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22cddaf88f4fbc13c51aebbf5f8eceb5c7c5a9da2ac40a13519eb5b0a0e8f11c" - [[package]] name = "toml_datetime" version = "0.7.2" @@ -4378,17 +4376,6 @@ dependencies = [ "serde_core", ] -[[package]] -name = "toml_edit" -version = "0.22.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a" -dependencies = [ - "indexmap", - "toml_datetime 0.6.11", - "winnow", -] - [[package]] name = "toml_edit" version = "0.23.6" @@ -4398,7 +4385,7 @@ dependencies = [ "indexmap", "serde_core", "serde_spanned", - "toml_datetime 0.7.2", + "toml_datetime", "toml_parser", "toml_writer", "winnow", @@ -4807,7 +4794,7 @@ dependencies = [ "thiserror", "tokio", "tokio-cron-scheduler", - "toml_edit 0.23.6", + "toml_edit", "uuid", "zip", ] @@ -4968,37 +4955,37 @@ dependencies = [ [[package]] name = "wildmatch" -version = "2.4.0" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68ce1ab1f8c62655ebe1350f589c61e505cf94d385bc6a12899442d9081e71fd" +checksum = "39b7d07a236abaef6607536ccfaf19b396dbe3f5110ddb73d39f4562902ed382" [[package]] name = "winapi-util" -version = "0.1.9" +version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" +checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" dependencies = [ - "windows-sys 0.59.0", + "windows-sys 0.60.2", ] [[package]] name = "windows-core" -version = "0.61.2" +version = "0.62.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0fdd3ddb90610c7638aa2b3a3ab2904fb9e5cdbecc643ddb3647212781c4ae3" +checksum = "6844ee5416b285084d3d3fffd743b925a6c9385455f64f6d4fa3031c4c2749a9" dependencies = [ "windows-implement", "windows-interface", - "windows-link", - "windows-result", - "windows-strings", + "windows-link 0.2.0", + "windows-result 0.4.0", + "windows-strings 0.5.0", ] [[package]] name = "windows-implement" -version = "0.60.0" +version = "0.60.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a47fddd13af08290e67f4acabf4b459f647552718f683a7b415d290ac744a836" +checksum = "edb307e42a74fb6de9bf3a02d9712678b22399c87e6fa869d6dfcd8c1b7754e0" dependencies = [ "proc-macro2", "quote", @@ -5007,9 +4994,9 @@ dependencies = [ [[package]] name = "windows-interface" -version = "0.59.1" +version = "0.59.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd9211b69f8dcdfa817bfd14bf1c97c9188afa36f4750130fcdf3f400eca9fa8" +checksum = "c0abd1ddbc6964ac14db11c7213d6532ef34bd9aa042c2e5935f59d7908b46a5" dependencies = [ "proc-macro2", "quote", @@ -5022,15 +5009,21 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a" +[[package]] +name = "windows-link" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45e46c0661abb7180e7b9c281db115305d49ca1709ab8242adf09666d2173c65" + [[package]] name = "windows-registry" version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5b8a9ed28765efc97bbc954883f4e6796c33a06546ebafacbabee9696967499e" dependencies = [ - "windows-link", - "windows-result", - "windows-strings", + "windows-link 0.1.3", + "windows-result 0.3.4", + "windows-strings 0.4.2", ] [[package]] @@ -5039,7 +5032,16 @@ version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "56f42bd332cc6c8eac5af113fc0c1fd6a8fd2aa08a0119358686e5160d0586c6" dependencies = [ - "windows-link", + "windows-link 0.1.3", +] + +[[package]] +name = "windows-result" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7084dcc306f89883455a206237404d3eaf961e5bd7e0f312f7c91f57eb44167f" +dependencies = [ + "windows-link 0.2.0", ] [[package]] @@ -5048,7 +5050,16 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "56e6c93f3a0c3b36176cb1327a4958a0353d5d166c2a35cb268ace15e91d3b57" dependencies = [ - "windows-link", + "windows-link 0.1.3", +] + +[[package]] +name = "windows-strings" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7218c655a553b0bed4426cf54b20d7ba363ef543b52d515b3e48d7fd55318dda" +dependencies = [ + "windows-link 0.2.0", ] [[package]] @@ -5087,6 +5098,15 @@ dependencies = [ "windows-targets 0.53.3", ] +[[package]] +name = "windows-sys" +version = "0.61.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f109e41dd4a3c848907eb83d5a42ea98b3769495597450cf6d153507b166f0f" +dependencies = [ + "windows-link 0.2.0", +] + [[package]] name = "windows-targets" version = "0.48.5" @@ -5124,7 +5144,7 @@ version = "0.53.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d5fe6031c4041849d7c496a8ded650796e7b6ecc19df1a431c1a363342e5dc91" dependencies = [ - "windows-link", + "windows-link 0.1.3", "windows_aarch64_gnullvm 0.53.0", "windows_aarch64_msvc 0.53.0", "windows_i686_gnu 0.53.0", @@ -5323,18 +5343,18 @@ dependencies = [ [[package]] name = "zerocopy" -version = "0.8.26" +version = "0.8.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1039dd0d3c310cf05de012d8a39ff557cb0d23087fd44cad61df08fc31907a2f" +checksum = "0894878a5fa3edfd6da3f88c4805f4c8558e2b996227a3d864f47fe11e38282c" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.8.26" +version = "0.8.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ecf5b4cc5364572d7f4c329661bcc82724222973f2cab6f050a4e5c22f75181" +checksum = "88d2b8d9c68ad2b9e4340d7832716a4d21a22a1154777ad56ea55c51a9cf3831" dependencies = [ "proc-macro2", "quote", diff --git a/README.md b/README.md index 98db59a..71fd28f 100644 --- a/README.md +++ b/README.md @@ -17,12 +17,13 @@ VulnFeed 是一个用于收集和推送高价值漏洞和补丁公告信息的 当抓取安全补丁公告的站点数据: -| 名称 | 地址 | 推送策略 | -| --------------------- | ----------------------------------------------------------- | -------------------------------------------------- | -| 用友安全中心 | | 近三条数据 | -| 泛微ECOLOGY安全补丁包 | | "EC9.0全量补丁", "EC8.0全量补丁", "EC10.0安全补丁" | -| Smartbi安全补丁包 | | 近三条数据 | -| 帆软安全漏洞声明 | | 近三条数据 | +| 名称 | 地址 | 推送策略 | +| --------------------- | ---------------------------------------------------------------------------------------------------- | -------------------------------------------------- | +| 用友安全中心 | | 近三条数据 | +| 泛微ECOLOGY安全补丁包 | | "EC9.0全量补丁", "EC8.0全量补丁", "EC10.0安全补丁" | +| Smartbi安全补丁包 | | 近三条数据 | +| 帆软安全漏洞声明 | | 近三条数据 | +| 致远安全补丁 | | V5的近三条数据 | ![app](./images/app.jpg) diff --git a/assets/src/routes/secnotice/list.jsx b/assets/src/routes/secnotice/list.jsx index 1188dac..cf87510 100644 --- a/assets/src/routes/secnotice/list.jsx +++ b/assets/src/routes/secnotice/list.jsx @@ -220,13 +220,7 @@ const SecNoticeListPage = () => {

- 发布时间: + 发布时间:

) -> AppResult<()> { WeaverNoticePlugin::try_new(sender.clone())?; SmartbiNoticePlugin::try_new(sender.clone())?; FanRuanNoticePlugin::try_new(sender.clone())?; + SeeyonNoticePlugin::try_new(sender.clone())?; Ok(()) } diff --git a/src/output/plugins/sec_notice/seeyon.rs b/src/output/plugins/sec_notice/seeyon.rs new file mode 100644 index 0000000..025d58d --- /dev/null +++ b/src/output/plugins/sec_notice/seeyon.rs @@ -0,0 +1,274 @@ +use async_trait::async_trait; +use error_stack::ResultExt; +use mea::mpsc::UnboundedSender; +use serde::{Deserialize, Serialize}; + +use crate::{ + AppResult, + domain::models::security_notice::{CreateSecurityNotice, RiskLevel}, + errors::Error, + output::plugins::sec_notice::{SecNoticePlugin, register_sec_notice}, + utils::http_client::HttpClient, +}; + +const SEEOYN_NOTICE_URL: &str = "https://service.seeyon.com/server2/rest/security/getCategory"; +const SEEOYN_DETAIL_URL: &str = + "https://service.seeyon.com/server2/rest/security/getCategoryDetail"; + +#[derive(Debug, Clone)] +pub struct SeeyonNoticePlugin { + name: String, + display_name: String, + link: String, + http_client: HttpClient, + sender: UnboundedSender, +} + +#[async_trait] +impl SecNoticePlugin for SeeyonNoticePlugin { + fn get_name(&self) -> String { + self.name.to_string() + } + + fn get_display_name(&self) -> String { + self.display_name.to_string() + } + + fn get_link(&self) -> String { + self.link.to_string() + } + + async fn update(&self, _page_limit: i32) -> AppResult<()> { + let notices = self.parse_security_notices().await?; + for notice in notices { + let title = notice.title.clone(); + + let detail_response = self.get_detail_data(notice.id).await?; + let (patch_number, patch_time) = self.extract_patch_info(&detail_response.content); + let detail_link = format!("{}?id={}", SEEOYN_DETAIL_URL, notice.id); + match (patch_number, patch_time) { + (Some(patch_number), Some(patch_time)) => { + let create_security_notice = CreateSecurityNotice { + key: patch_number, + title, + product_name: "致远OA".to_string(), + risk_level: RiskLevel::High.to_string(), + source: self.link.clone(), + source_name: self.get_name(), + is_zero_day: false, + detail_link, + publish_time: patch_time, + pushed: false, + }; + self.sender.send(create_security_notice).map_err(|e| { + Error::Message(format!("Failed to send security notice to queue: {}", e)) + })?; + } + (_, _) => { + log::error!( + "Failed to extract patch info for notice id: {} title: {}", + notice.id, + notice.title + ); + continue; + } + } + } + Ok(()) + } +} + +impl SeeyonNoticePlugin { + pub fn try_new(sender: UnboundedSender) -> AppResult { + let http_client = HttpClient::try_new()?; + let seeyon = SeeyonNoticePlugin { + name: "SeeyonPlugin".to_string(), + display_name: "致远OA安全公告".to_string(), + link: "https://service.seeyon.com".to_string(), + http_client, + sender, + }; + register_sec_notice(seeyon.name.clone(), Box::new(seeyon.clone())); + Ok(seeyon) + } + + async fn get_category_data(&self) -> AppResult { + let response = self + .http_client + .get_json(SEEOYN_NOTICE_URL) + .await + .change_context_lazy(|| { + Error::Message("Failed to fetch Seeyon category data".to_string()) + })?; + let category_data: SeeyonCategoryResponse = + response.json().await.change_context_lazy(|| { + Error::Message("Failed to parse Seeyon category data".to_string()) + })?; + Ok(category_data) + } + + pub async fn get_detail_data(&self, id: i32) -> AppResult { + let url = format!("{}?id={}", SEEOYN_DETAIL_URL, id); + let response = self + .http_client + .get_json(&url) + .await + .change_context_lazy(|| { + Error::Message(format!("Failed to fetch Seeyon detail data for id: {}", id)) + })?; + let detail_data: SeeyonDetailResponse = + response.json().await.change_context_lazy(|| { + Error::Message(format!("Failed to parse Seeyon detail data for id: {}", id)) + })?; + Ok(detail_data) + } + + async fn parse_security_notices(&self) -> AppResult> { + let category_data = self.get_category_data().await?; + + let v5_id = category_data + .iter() + .find(|item| item.classification == "V5") + .map(|item| item.id) + .ok_or_else(|| Error::Message("V5 classification not found".to_string()))?; + + // Find items with pid equal to V5 id + let mut notices: Vec = Vec::new(); + + // 获取前3个ID最大的项目 + let mut filtered_items: Vec<_> = category_data + .iter() + .filter(|item| item.pid == v5_id) + .collect(); + + filtered_items.sort_by(|a, b| b.id.cmp(&a.id)); + filtered_items.truncate(3); + + // 为每个项目获取详细信息 + for item in filtered_items { + let mut notice = SeeyonSecurityNotice { + id: item.id, + title: item.classification.clone(), + patch_number: None, + publish_time: None, + }; + + // 获取详细信息 + match self.get_detail_data(item.id).await { + Ok(detail) => { + notice.title = detail.title; + + // 从HTML内容中提取补丁编号和发布时间 + let (patch_number, publish_time) = self.extract_patch_info(&detail.content); + notice.patch_number = patch_number; + notice.publish_time = publish_time; + } + Err(e) => { + eprintln!("Failed to get detail data for id {}: {:?}", item.id, e); + } + } + notices.push(notice); + } + + Ok(notices) + } + + pub fn extract_patch_info(&self, content: &str) -> (Option, Option) { + let mut patch_number = None; + let mut publish_time = None; + let document = scraper::Html::parse_document(content); + + // CSS选择器查找包含"补丁编号"文本的td元素,然后获取下一个兄弟元素的文本内容 + let patch_selector = scraper::Selector::parse("td").unwrap(); + let elements: Vec<_> = document.select(&patch_selector).collect(); + + for (i, element) in elements.iter().enumerate() { + if let Some(text) = element.text().next() + && text.contains("补丁编号") + && i + 1 < elements.len() + { + // 获取下一个td元素作为补丁编号 + patch_number = Some( + elements[i + 1] + .text() + .collect::() + .trim() + .to_string(), + ); + break; + } + } + + // CSS选择器查找包含"发布时间"文本的td元素,然后获取下一个兄弟元素的文本内容 + for (i, element) in elements.iter().enumerate() { + if let Some(text) = element.text().next() + && text.contains("发布时间") + && i + 1 < elements.len() + { + // 获取下一个td元素作为发布时间 + publish_time = Some( + elements[i + 1] + .text() + .collect::() + .trim() + .to_string(), + ); + break; + } + } + + (patch_number, publish_time) + } +} + +pub type SeeyonCategoryResponse = Vec; + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct SeeyonCategoryItem { + pub id: i32, + pub pid: i32, + pub classification: String, + pub sort: i32, + pub url: Option, +} + +#[derive(Debug, Clone, PartialEq)] +pub struct SeeyonSecurityNotice { + pub id: i32, + pub title: String, + pub patch_number: Option, + pub publish_time: Option, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct SeeyonDetailResponse { + pub id: i32, + pub title: String, + pub content: String, + #[serde(rename = "createTime")] + pub create_time: Option, + pub author: String, + #[serde(rename = "categoryId")] + pub category_id: i32, + #[serde(rename = "categoryName")] + pub category_name: Option, +} + +#[cfg(test)] +mod tests { + use super::*; + use mea::mpsc::unbounded; + + #[tokio::test] + pub async fn test_extract_patch_info() { + let (sender, _receiver) = unbounded::(); + let plugin = SeeyonNoticePlugin::try_new(sender).unwrap(); + let detail_data = plugin.get_detail_data(180).await.unwrap(); + let content = &detail_data.content; + + let (patch_number, publish_time) = plugin.extract_patch_info(content); + + assert_eq!(patch_number, Some("250300-S006".to_string())); + assert_eq!(publish_time, Some("2025年3月".to_string())); + } +}