refactor: move to cargo workplace

This commit is contained in:
Lowder
2025-11-27 00:39:54 +05:00
parent 1ba0810418
commit 55ca118061
34 changed files with 4450 additions and 449 deletions
+1 -1
View File
@@ -1 +1 @@
target/
.git/
+1 -1
View File
@@ -1,2 +1,2 @@
/target
/databases
.idea/
Generated
+151 -108
View File
@@ -169,29 +169,6 @@ dependencies = [
"generic-array",
]
[[package]]
name = "blocklist-check"
version = "0.1.3"
dependencies = [
"chrono",
"csv",
"env_logger",
"flate2",
"hickory-resolver",
"ipnet",
"ipnet-trie",
"log",
"maxminddb",
"reqwest",
"rocket",
"rocket-cache-response",
"rocket_dyn_templates",
"serde",
"tar",
"trie-rs",
"url",
]
[[package]]
name = "bstr"
version = "1.12.1"
@@ -222,9 +199,9 @@ checksum = "b35204fbdc0b3f4446b89fc1ac2cf84a8a68971995d0bf2e925ec7cd960f9cb3"
[[package]]
name = "cc"
version = "1.2.46"
version = "1.2.47"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b97463e1064cb1b1c1384ad0a0b9c8abd0988e2a91f52606c80ef14aadb63e36"
checksum = "cd405d82c84ff7f35739f175f67d8b9fb7687a0e84ccdc78bd3568839827cf07"
dependencies = [
"find-msvc-tools",
"shlex",
@@ -284,6 +261,19 @@ version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75"
[[package]]
name = "console"
version = "0.16.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b430743a6eb14e9764d4260d4c0d8123087d504eeb9c48f2b2a5e810dd369df4"
dependencies = [
"encode_unicode",
"libc",
"once_cell",
"unicode-width",
"windows-sys 0.61.2",
]
[[package]]
name = "cookie"
version = "0.18.1"
@@ -371,9 +361,9 @@ checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28"
[[package]]
name = "crypto-common"
version = "0.1.6"
version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3"
checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a"
dependencies = [
"generic-array",
"typenum",
@@ -481,6 +471,12 @@ version = "1.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719"
[[package]]
name = "encode_unicode"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "34aa73646ffb006b8f5147f3dc182bd4bcb190227ce861fc4a4844bf8e3cb2c0"
[[package]]
name = "encoding_rs"
version = "0.8.35"
@@ -824,7 +820,7 @@ dependencies = [
"fnv",
"futures-core",
"futures-sink",
"http 1.3.1",
"http 1.4.0",
"indexmap",
"slab",
"tokio",
@@ -834,9 +830,9 @@ dependencies = [
[[package]]
name = "hashbrown"
version = "0.16.0"
version = "0.16.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5419bdc4f6a9207fbeba6d11b604d481addf78ecd10c11ad51e76c2f6482748d"
checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100"
[[package]]
name = "heck"
@@ -865,7 +861,7 @@ dependencies = [
"futures-io",
"futures-util",
"h2 0.4.12",
"http 1.3.1",
"http 1.4.0",
"idna",
"ipnet",
"once_cell",
@@ -918,12 +914,11 @@ dependencies = [
[[package]]
name = "http"
version = "1.3.1"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f4a85d31aea989eead29a3aaf9e1115a180df8282431156e533de47660892565"
checksum = "e3ba2a386d7f85a81f119ad7498ebe444d2e22c2af0b86b069416ace48b3311a"
dependencies = [
"bytes",
"fnv",
"itoa",
]
@@ -945,7 +940,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184"
dependencies = [
"bytes",
"http 1.3.1",
"http 1.4.0",
]
[[package]]
@@ -956,7 +951,7 @@ checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a"
dependencies = [
"bytes",
"futures-core",
"http 1.3.1",
"http 1.4.0",
"http-body 1.0.1",
"pin-project-lite",
]
@@ -1017,7 +1012,7 @@ dependencies = [
"futures-channel",
"futures-core",
"h2 0.4.12",
"http 1.3.1",
"http 1.4.0",
"http-body 1.0.1",
"httparse",
"itoa",
@@ -1034,7 +1029,7 @@ version = "0.27.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e3c93eb611681b207e1fe55d5a71ecf91572ec8a6705cdb6857f7d8d5242cf58"
dependencies = [
"http 1.3.1",
"http 1.4.0",
"hyper 1.8.1",
"hyper-util",
"rustls",
@@ -1042,7 +1037,7 @@ dependencies = [
"tokio",
"tokio-rustls",
"tower-service",
"webpki-roots 1.0.2",
"webpki-roots 1.0.4",
]
[[package]]
@@ -1072,7 +1067,7 @@ dependencies = [
"futures-channel",
"futures-core",
"futures-util",
"http 1.3.1",
"http 1.4.0",
"http-body 1.0.1",
"hyper 1.8.1",
"ipnet",
@@ -1231,9 +1226,9 @@ dependencies = [
[[package]]
name = "indexmap"
version = "2.12.0"
version = "2.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6717a8d2a5a929a1a2eb43a12812498ed141a0bcfb7e8f7844fbdbe4303bba9f"
checksum = "0ad4bb2b565bca0645f4d68c5c9af97fba094e9791da685bf83cb5f3ce74acf2"
dependencies = [
"equivalent",
"hashbrown",
@@ -1241,6 +1236,19 @@ dependencies = [
"serde_core",
]
[[package]]
name = "indicatif"
version = "0.18.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9375e112e4b463ec1b1c6c011953545c65a30164fbab5b581df32b3abf0dcb88"
dependencies = [
"console",
"portable-atomic",
"unicode-width",
"unit-prefix",
"web-time",
]
[[package]]
name = "inlinable_string"
version = "0.1.15"
@@ -1360,9 +1368,9 @@ dependencies = [
[[package]]
name = "js-sys"
version = "0.3.81"
version = "0.3.82"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec48937a97411dcb524a265206ccd4c90bb711fca92b2792c407f268825b9305"
checksum = "b011eec8cc36da2aab2d5cff675ec18454fad408585853910a202391cf9f8e65"
dependencies = [
"once_cell",
"wasm-bindgen",
@@ -1402,9 +1410,9 @@ checksum = "2874a2af47a2325c2001a6e6fad9b16a53b802102b528163885171cf92b15976"
[[package]]
name = "libm"
version = "0.2.13"
version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c9627da5196e5d8ed0b0495e61e518847578da83483c37288316d9b2e03a7f72"
checksum = "f9fbbcab51052fe104eb5e5d351cf728d30a5be1fe14d9be8a3b097481fb97de"
[[package]]
name = "libredox"
@@ -1568,7 +1576,7 @@ dependencies = [
"bytes",
"encoding_rs",
"futures-util",
"http 1.3.1",
"http 1.4.0",
"httparse",
"memchr",
"mime",
@@ -1780,20 +1788,19 @@ checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220"
[[package]]
name = "pest"
version = "2.7.15"
version = "2.8.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8b7cafe60d6cf8e62e1b9b2ea516a089c008945bb5a275416789e7db0bc199dc"
checksum = "cbcfd20a6d4eeba40179f05735784ad32bdaef05ce8e8af05f180d45bb3e7e22"
dependencies = [
"memchr",
"thiserror",
"ucd-trie",
]
[[package]]
name = "pest_derive"
version = "2.7.15"
version = "2.8.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "816518421cfc6887a0d62bf441b6ffb4536fcc926395a69e1a85852d4363f57e"
checksum = "51f72981ade67b1ca6adc26ec221be9f463f2b5839c7508998daa17c23d94d7f"
dependencies = [
"pest",
"pest_generator",
@@ -1801,9 +1808,9 @@ dependencies = [
[[package]]
name = "pest_generator"
version = "2.7.15"
version = "2.8.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7d1396fd3a870fc7838768d171b4616d5c91f6cc25e377b673d714567d99377b"
checksum = "dee9efd8cdb50d719a80088b76f81aec7c41ed6d522ee750178f83883d271625"
dependencies = [
"pest",
"pest_meta",
@@ -1814,11 +1821,10 @@ dependencies = [
[[package]]
name = "pest_meta"
version = "2.7.15"
version = "2.8.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e1e58089ea25d717bfd31fb534e4f3afcc2cc569c70de3e239778991ea3b7dea"
checksum = "bf1d70880e76bdc13ba52eafa6239ce793d85c8e43896507e43dd8984ff05b82"
dependencies = [
"once_cell",
"pest",
"sha2",
]
@@ -1950,6 +1956,28 @@ dependencies = [
"yansi",
]
[[package]]
name = "querying"
version = "0.1.0"
dependencies = [
"async-trait",
"chrono",
"csv",
"futures-util",
"hickory-resolver",
"indicatif",
"ipnet",
"ipnet-trie",
"log",
"maxminddb",
"reqwest",
"serde",
"thiserror",
"tokio",
"trie-rs",
"url",
]
[[package]]
name = "quinn"
version = "0.11.9"
@@ -1963,7 +1991,7 @@ dependencies = [
"quinn-udp",
"rustc-hash",
"rustls",
"socket2 0.5.10",
"socket2 0.6.1",
"thiserror",
"tokio",
"tracing",
@@ -2000,9 +2028,9 @@ dependencies = [
"cfg_aliases",
"libc",
"once_cell",
"socket2 0.5.10",
"socket2 0.6.1",
"tracing",
"windows-sys 0.52.0",
"windows-sys 0.60.2",
]
[[package]]
@@ -2170,7 +2198,7 @@ dependencies = [
"futures-core",
"futures-util",
"h2 0.4.12",
"http 1.3.1",
"http 1.4.0",
"http-body 1.0.1",
"http-body-util",
"hyper 1.8.1",
@@ -2202,7 +2230,7 @@ dependencies = [
"wasm-bindgen-futures",
"wasm-streams",
"web-sys",
"webpki-roots 1.0.2",
"webpki-roots 1.0.4",
]
[[package]]
@@ -2555,9 +2583,9 @@ checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
[[package]]
name = "signal-hook-registry"
version = "1.4.6"
version = "1.4.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b2a4719bff48cee6b39d12c020eeb490953ad2443b7055bd0b21fca26bd8c28b"
checksum = "7664a098b8e616bdfcc2dc0e9ac44eb231eedf41db4e9fe95d8d32ec728dedad"
dependencies = [
"libc",
]
@@ -2654,9 +2682,9 @@ checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292"
[[package]]
name = "syn"
version = "2.0.110"
version = "2.0.111"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a99801b5bd34ede4cf3fc688c5919368fea4e4814a4664359503e6015b280aea"
checksum = "390cc9a294ab71bdb1aa2e99d13be9c753cd2d7bd6560c77118597410c4d2e87"
dependencies = [
"proc-macro2",
"quote",
@@ -2685,20 +2713,20 @@ dependencies = [
[[package]]
name = "system-configuration"
version = "0.5.1"
version = "0.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7"
checksum = "3c879d448e9d986b661742763247d3693ed13609438cf3d006f51f5368a5ba6b"
dependencies = [
"bitflags 1.3.2",
"bitflags 2.10.0",
"core-foundation",
"system-configuration-sys",
]
[[package]]
name = "system-configuration-sys"
version = "0.5.0"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a75fb188eb626b924683e3b95e3a48e63551fcfb51949de2f06a9d91dbee93c9"
checksum = "8e1d1b10ced5ca923a1fcb8d03e96b8d3268065d724548c0211415ff6ac6bac4"
dependencies = [
"core-foundation-sys",
"libc",
@@ -2850,6 +2878,7 @@ dependencies = [
"bytes",
"libc",
"mio 1.1.0",
"parking_lot",
"pin-project-lite",
"signal-hook-registry",
"socket2 0.6.1",
@@ -2970,14 +2999,14 @@ dependencies = [
[[package]]
name = "tower-http"
version = "0.6.6"
version = "0.6.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "adc82fd73de2a9722ac5da747f12383d2bfdb93591ee6c58486e0097890f05f2"
checksum = "9cf146f99d442e8e68e585f5d798ccd3cad9a7835b917e09728880a862706456"
dependencies = [
"bitflags 2.10.0",
"bytes",
"futures-util",
"http 1.3.1",
"http 1.4.0",
"http-body 1.0.1",
"iri-string",
"pin-project-lite",
@@ -3117,12 +3146,24 @@ version = "1.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493"
[[package]]
name = "unicode-width"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b4ac048d71ede7ee76d585517add45da530660ef4390e49b098733c6e897f254"
[[package]]
name = "unicode-xid"
version = "0.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853"
[[package]]
name = "unit-prefix"
version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "81e544489bf3d8ef66c953931f56617f423cd4b5494be343d9b9d3dda037b9a3"
[[package]]
name = "untrusted"
version = "0.9.0"
@@ -3218,9 +3259,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen"
version = "0.2.104"
version = "0.2.105"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c1da10c01ae9f1ae40cbfac0bac3b1e724b320abfcf52229f80b547c0d250e2d"
checksum = "da95793dfc411fbbd93f5be7715b0578ec61fe87cb1a42b12eb625caa5c5ea60"
dependencies = [
"cfg-if",
"once_cell",
@@ -3229,25 +3270,11 @@ dependencies = [
"wasm-bindgen-shared",
]
[[package]]
name = "wasm-bindgen-backend"
version = "0.2.104"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "671c9a5a66f49d8a47345ab942e2cb93c7d1d0339065d4f8139c486121b43b19"
dependencies = [
"bumpalo",
"log",
"proc-macro2",
"quote",
"syn",
"wasm-bindgen-shared",
]
[[package]]
name = "wasm-bindgen-futures"
version = "0.4.54"
version = "0.4.55"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7e038d41e478cc73bae0ff9b36c60cff1c98b8f38f8d7e8061e79ee63608ac5c"
checksum = "551f88106c6d5e7ccc7cd9a16f312dd3b5d36ea8b4954304657d5dfba115d4a0"
dependencies = [
"cfg-if",
"js-sys",
@@ -3258,9 +3285,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen-macro"
version = "0.2.104"
version = "0.2.105"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7ca60477e4c59f5f2986c50191cd972e3a50d8a95603bc9434501cf156a9a119"
checksum = "04264334509e04a7bf8690f2384ef5265f05143a4bff3889ab7a3269adab59c2"
dependencies = [
"quote",
"wasm-bindgen-macro-support",
@@ -3268,22 +3295,22 @@ dependencies = [
[[package]]
name = "wasm-bindgen-macro-support"
version = "0.2.104"
version = "0.2.105"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9f07d2f20d4da7b26400c9f4a0511e6e0345b040694e8a75bd41d578fa4421d7"
checksum = "420bc339d9f322e562942d52e115d57e950d12d88983a14c79b86859ee6c7ebc"
dependencies = [
"bumpalo",
"proc-macro2",
"quote",
"syn",
"wasm-bindgen-backend",
"wasm-bindgen-shared",
]
[[package]]
name = "wasm-bindgen-shared"
version = "0.2.104"
version = "0.2.105"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bad67dc8b2a1a6e5448428adec4c3e84c43e561d8c9ee8a9e5aabeb193ec41d1"
checksum = "76f218a38c84bcb33c25ec7059b07847d465ce0e0a76b995e134a45adcb6af76"
dependencies = [
"unicode-ident",
]
@@ -3303,9 +3330,9 @@ dependencies = [
[[package]]
name = "web-sys"
version = "0.3.81"
version = "0.3.82"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9367c417a924a74cae129e6a2ae3b47fabb1f8995595ab474029da749a8be120"
checksum = "3a1f95c0d03a47f4ae1f7a64643a6bb97465d9b740f0fa8f90ea33915c99a9a1"
dependencies = [
"js-sys",
"wasm-bindgen",
@@ -3327,18 +3354,34 @@ version = "0.26.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "521bc38abb08001b01866da9f51eb7c5d647a19260e00054a8c7fd5f9e57f7a9"
dependencies = [
"webpki-roots 1.0.2",
"webpki-roots 1.0.4",
]
[[package]]
name = "webpki-roots"
version = "1.0.2"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7e8983c3ab33d6fb807cfcdad2491c4ea8cbc8ed839181c7dfd9c67c83e261b2"
checksum = "b2878ef029c47c6e8cf779119f20fcf52bde7ad42a731b2a304bc221df17571e"
dependencies = [
"rustls-pki-types",
]
[[package]]
name = "website"
version = "0.1.3"
dependencies = [
"env_logger",
"flate2",
"log",
"querying",
"reqwest",
"rocket",
"rocket-cache-response",
"rocket_dyn_templates",
"serde",
"tar",
]
[[package]]
name = "widestring"
version = "1.2.1"
@@ -3730,18 +3773,18 @@ dependencies = [
[[package]]
name = "zerocopy"
version = "0.8.27"
version = "0.8.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0894878a5fa3edfd6da3f88c4805f4c8558e2b996227a3d864f47fe11e38282c"
checksum = "4ea879c944afe8a2b25fef16bb4ba234f47c694565e97383b36f3a878219065c"
dependencies = [
"zerocopy-derive",
]
[[package]]
name = "zerocopy-derive"
version = "0.8.27"
version = "0.8.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "88d2b8d9c68ad2b9e4340d7832716a4d21a22a1154777ad56ea55c51a9cf3831"
checksum = "cf955aa904d6040f70dc8e9384444cb1030aed272ba3cb09bbc4ab9e7c1f34f5"
dependencies = [
"proc-macro2",
"quote",
+8 -25
View File
@@ -1,27 +1,10 @@
[package]
name = "blocklist-check"
version = "0.1.3"
edition = "2024"
[workspace]
members = [ "querying",
"website",
]
resolver = "3"
[dependencies]
hickory-resolver = { version = "0.26.0-alpha.1", features = ["tokio", "webpki-roots", "https-ring"] }
rocket = "0.5.1"
rocket_dyn_templates = { version = "0.2.0", features = ["tera"] }
serde = { version = "1", features = ["derive"] }
log = "0.4.28"
maxminddb = "0.26"
ipnet-trie = "0.3.0"
ipnet = "2.11.0"
csv = "1.4.0"
trie-rs = "0.4.2"
env_logger = "0.11.8"
[workspace.dependencies]
tokio = { version = "1.48.0", features = ["full"] }
reqwest = { version = "0.12.24", features = ["stream", "rustls-tls-webpki-roots"] }
chrono = { version = "0.4.42", features = ["serde"] }
rocket-cache-response = "0.6.4"
url = "2.5.7"
[build-dependencies]
reqwest = { version = "0.12", features = ["blocking", "json"] }
serde = { version = "1", features = ["derive"] }
tar = "0.4"
flate2 = "1.0"
log = "0.4.28"
+1 -1
View File
@@ -14,7 +14,7 @@
- **Rust** — язык программирования, на котором написан весь бекенд.
- **Rocket.rs** — веб-фреймворк для построения HTTP API и серверной логики.
- **DoH резолвер Cloudflare** — для разрешения DNS-запросов используется DNS-over-HTTPS через Cloudflare, что позволяет обойти локальные ограничения и получать актуальные данные.
- **DoH резолвер Quad9** — для разрешения DNS-запросов используется DNS-over-HTTPS, что позволяет обойти локальные ограничения и получать актуальные данные.
- **Tera** — шаблонизатор для генерации HTML страниц, используется для фронтенда.
- **lucide** — библиотека иконок, применяемая для визуального оформления интерфейса.
+2
View File
@@ -0,0 +1,2 @@
[default]
template_dir = "website/templates/"
+22
View File
@@ -0,0 +1,22 @@
[package]
name = "querying"
version = "0.1.0"
edition = "2024"
[dependencies]
ipnet-trie = "0.3.0"
ipnet = "2.11.0"
serde = { version = "1", features = ["derive"] }
async-trait = "0.1.89"
trie-rs = "0.4.2"
tokio = { workspace = true }
reqwest = { workspace = true }
csv = "1.4.0"
maxminddb = "0.26.0"
log = { workspace = true }
hickory-resolver = { version = "0.26.0-alpha.1", features = ["tokio", "webpki-roots", "https-ring"] }
thiserror = "2.0.17"
url = "2.5.7"
indicatif = "0.18.3"
chrono = { version = "0.4.42", features = ["serde"] }
futures-util = "0.3.31"
+7 -6
View File
@@ -1,9 +1,10 @@
use std::{io};
use std::io::Error;
use std::net::IpAddr;
use async_trait::async_trait;
use maxminddb::{geoip2, MaxMindDbError};
use maxminddb::geoip2::{city, country, City, Country};
use rocket::serde::Serialize;
use serde::Serialize;
use crate::updater::{fetch_db, Updatable};
pub struct GeoIp {
@@ -84,14 +85,14 @@ impl GeoIp {
impl Updatable for GeoIp {
type Base = (Vec<u8>, Vec<u8>, Vec<u8>);
async fn download() -> Result<Self::Base, io::Error> {
Ok((fetch_db(Self::get_url("GEO_ASN", "https://github.com/P3TERX/GeoLite.mmdb/raw/download/GeoLite2-ASN.mmdb")).await?,
fetch_db(Self::get_url("GEO_COUNTRY", "https://github.com/P3TERX/GeoLite.mmdb/raw/download/GeoLite2-Country.mmdb")).await?,
fetch_db(Self::get_url("GEO_CITY", "https://github.com/P3TERX/GeoLite.mmdb/raw/download/GeoLite2-City.mmdb")).await?))
async fn download() -> Result<Self::Base, Error> {
Ok((fetch_db(Self::get_url("GEO_ASN", "https://git.io/GeoLite2-ASN.mmdb")).await?,
fetch_db(Self::get_url("GEO_COUNTRY", "https://git.io/GeoLite2-Country.mmdb")).await?,
fetch_db(Self::get_url("GEO_CITY", "https://git.io/GeoLite2-City.mmdb")).await?))
}
async fn install(&mut self, (asn, country, city): Self::Base) -> Result<(), Error> {
self.update(asn, country, city)
.map_err(|e| io::Error::new(io::ErrorKind::Other, e))
.map_err(|e| Error::new(io::ErrorKind::Other, e))
}
}
+173
View File
@@ -0,0 +1,173 @@
use std::collections::{HashMap, HashSet};
use std::net::IpAddr;
use std::sync::Arc;
use chrono::{DateTime, Utc};
use ipnet::IpNet;
use log::error;
use thiserror::Error;
use tokio::sync::{watch, RwLock};
use crate::geoip::{GeoIp, IpInfo};
use crate::lists::{CdnList, NetworkRecord, RuBlacklist};
use crate::resolver::{ResolveError, Resolver};
use crate::target::Target;
use crate::updater::Updatable;
pub mod geoip;
pub mod lists;
pub mod resolver;
pub mod updater;
pub mod target;
pub struct Checker {
rx: watch::Receiver<Option<DateTime<Utc>>>,
tx: watch::Sender<Option<DateTime<Utc>>>,
cdn_list: Arc<RwLock<CdnList>>,
ru_blacklist: Arc<RwLock<RuBlacklist>>,
geo_ip: Arc<RwLock<GeoIp>>,
resolver: Resolver,
}
pub struct Check {
pub verdict: CheckVerdict,
pub geo: IpInfo,
pub ips: Vec<IpAddr>,
}
pub enum CheckVerdict {
Clear,
Blocked {
rkn_domain: Option<String>,
rkn_subnets: HashSet<IpNet>,
cdn_provider_subnets: HashMap<String, HashSet<NetworkRecord>>,
},
}
#[derive(Debug, Error)]
pub enum CheckError {
#[error("resolve error")]
ResolveError(#[from] ResolveError),
#[error("geoip error")]
GeoIpError,
#[error("domain not found")]
NotFound,
}
impl Checker {
pub async fn new() -> Checker {
let (tx, rx) = watch::channel(None);
Checker {
rx,
tx,
cdn_list: Arc::new(RwLock::new(CdnList::new())),
ru_blacklist: Arc::new(RwLock::new(RuBlacklist::new())),
geo_ip: Arc::new(RwLock::new(GeoIp::new())),
resolver: Resolver::new().await,
}
}
pub async fn check(&self, target: Target) -> Result<Check, CheckError> {
let ips = match target.resolve(&self.resolver).await {
Ok(ips) => ips,
Err(ResolveError::NxDomain) => {
return Err(CheckError::NotFound);
}
Err(e) => {
error!("{}", e);
return Err(CheckError::ResolveError(e));
},
};
let geo_ip = self.geo_ip.read().await;
let geo = match ips.get(0).map(|ip| geo_ip.lookup(ip.clone())) {
None => IpInfo::default(),
Some(Ok(ip)) => ip,
Some(Err(e)) => {
error!("{}", e);
return Err(CheckError::GeoIpError);
},
};
let mut cdn_provider_subnets: HashMap<String, HashSet<NetworkRecord>> = HashMap::new();
let cdn_list = self.cdn_list.read().await;
ips.iter()
.filter_map(|ip| cdn_list.contains(ip))
.map(|ip| (match &ip.region {
None => ip.provider.clone(),
Some(region) => format!("{} ({})", ip.provider, region),
}, ip.clone()))
.for_each(|(k, v)| {
cdn_provider_subnets.entry(k).or_default().insert(v);
});
let ru_blacklist = self.ru_blacklist.read().await;
let domain = match &target {
Target::Domain(domain) => ru_blacklist.contains_domain(domain),
_ => None
};
let rkn_subnets: HashSet<IpNet> = ips.iter()
.filter_map(|ip| ru_blacklist.contains_ip(ip))
.collect();
Ok(Check {
verdict: match (domain, cdn_provider_subnets.is_empty(), rkn_subnets.is_empty()) {
(None, true, true) => CheckVerdict::Clear,
(domain, _, _) => CheckVerdict::Blocked {
rkn_domain: domain,
rkn_subnets,
cdn_provider_subnets,
}
},
geo,
ips
})
}
pub fn last_update(&self) -> Option<DateTime<Utc>> {
self.rx.borrow().clone()
}
pub async fn update_all(&self) {
match GeoIp::download().await {
Ok(base) => {
if let Err(e) = self.geo_ip.write().await.install(base).await {
error!("Failed to update GeoIP: {}", e);
}
}
Err(e) => {
error!("Failed to download GeoIP: {}", e);
}
}
match RuBlacklist::download().await {
Ok(base) => {
if let Err(e) = self.ru_blacklist.write().await.install(base).await {
error!("Failed to update RKN: {}", e);
}
}
Err(e) => {
error!("Failed to download RKN: {}", e);
}
}
match CdnList::download().await {
Ok(base) => {
if let Err(e) = self.cdn_list.write().await.install(base).await {
error!("Failed to update CDN: {}", e);
}
}
Err(e) => {
error!("Failed to download CDN: {}", e);
}
}
self.tx.send(Some(Utc::now())).unwrap();
}
pub async fn total_domains(&self) -> usize {
self.ru_blacklist.read().await.domain_count
}
pub async fn total_v4s(&self) -> usize {
(self.cdn_list.read().await.v4_count() + self.ru_blacklist.read().await.v4_count()) as usize
}
}
+2
View File
@@ -3,8 +3,10 @@ use std::io;
use std::io::{BufRead, Error, Read};
use std::net::IpAddr;
use std::str::FromStr;
use async_trait::async_trait;
use ipnet::IpNet;
use ipnet_trie::IpnetTrie;
use log::info;
use serde::{de, Deserialize, Deserializer, Serializer};
use trie_rs::map::{Trie, TrieBuilder};
use crate::updater::{fetch_db, Updatable};
+17 -3
View File
@@ -1,12 +1,21 @@
use std::io::{Error, ErrorKind};
use std::net::IpAddr;
use hickory_resolver::config::{LookupIpStrategy, ResolverConfig, ResolverOpts};
use hickory_resolver::name_server::{TokioConnectionProvider};
use hickory_resolver::proto::ProtoError;
use thiserror::Error;
pub struct Resolver {
resolver: hickory_resolver::Resolver<TokioConnectionProvider>,
}
#[derive(Error, Debug)]
pub enum ResolveError {
#[error("domain not found")]
NxDomain,
#[error("resolver error")]
Other(#[from] Error),
}
impl Resolver {
pub async fn new() -> Resolver {
let config = ResolverConfig::quad9_https();
@@ -18,8 +27,13 @@ impl Resolver {
Resolver { resolver }
}
pub async fn lookup_ips(&self, domain: &str) -> Result<Vec<IpAddr>, ProtoError> {
Ok(self.resolver.lookup_ip(domain).await?
pub async fn lookup_ips(&self, domain: &str) -> Result<Vec<IpAddr>, ResolveError> {
Ok(self.resolver.lookup_ip(domain).await
.map_err(|e| if e.kind.is_no_records_found() {
ResolveError::NxDomain
} else {
ResolveError::Other(Error::new(ErrorKind::Other, e))
})?
.into_iter().collect())
}
}
+3 -3
View File
@@ -1,8 +1,8 @@
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
use hickory_resolver::proto::ProtoError;
use url::Url;
use crate::resolver::Resolver;
use crate::resolver::{ResolveError, Resolver};
#[derive(Debug, Clone)]
pub enum Target {
Domain(String),
Ipv4(Ipv4Addr),
@@ -37,7 +37,7 @@ impl Target {
}
}
pub async fn resolve(&self, resolver: &Resolver) -> Result<Vec<IpAddr>, ProtoError> {
pub async fn resolve(&self, resolver: &Resolver) -> Result<Vec<IpAddr>, ResolveError> {
Ok(match self {
Target::Domain(domain) => resolver.lookup_ips(domain).await?,
Target::Ipv4(ipv4) => vec![IpAddr::V4(ipv4.clone())],
+47
View File
@@ -0,0 +1,47 @@
use std::fmt::Display;
use std::io;
use std::io::Error;
use async_trait::async_trait;
use indicatif::{ProgressBar, ProgressStyle};
use futures_util::StreamExt;
use log::info;
use reqwest::IntoUrl;
pub async fn fetch_db<T: IntoUrl + Display>(url: T) -> Result<Vec<u8>, Error> {
info!("Fetching {}", url);
let response = reqwest::get(url).await
.map_err(|e| Error::new(io::ErrorKind::Other, e))?
.error_for_status()
.map_err(|e| Error::new(io::ErrorKind::Other, e))?;
let total_size = response.content_length().unwrap_or(0);
let pb = ProgressBar::new(total_size);
pb.set_style(ProgressStyle::default_bar()
.template("{spinner:.green} [{elapsed_precise}] [{bar:40.cyan/blue}] {bytes}/{total_bytes} ({eta})")
.map_err(|e| Error::new(io::ErrorKind::Other, e))?
.progress_chars("#>-"));
let mut bytes = Vec::new();
bytes.reserve(total_size as usize);
let mut stream = response.bytes_stream();
while let Some(chunk_result) = stream.next().await {
let chunk = chunk_result.map_err(|e| Error::new(io::ErrorKind::Other, e))?;
bytes.extend(&chunk);
pb.inc(chunk.len() as u64);
}
pb.finish_with_message("Download complete!");
Ok(bytes)
}
#[async_trait]
pub trait Updatable {
type Base;
async fn download() -> Result<Self::Base, Error>;
async fn install(&mut self, base: Self::Base) -> Result<(), Error>;
fn get_url(key: &'static str, default: &'static str) -> String {
std::env::var(key).ok().unwrap_or(default.to_string())
}
}
-215
View File
@@ -1,215 +0,0 @@
mod target;
mod resolver;
mod geoip;
mod lists;
mod updater;
#[macro_use] extern crate rocket;
extern crate maxminddb;
use std::collections::{HashMap, HashSet};
use std::path::PathBuf;
use std::sync::Arc;
use std::time::Duration;
use chrono::{DateTime, Utc};
use rocket::fs::FileServer;
use rocket::http::Status;
use rocket::{tokio, Request, State};
use rocket::response::content::RawJavaScript;
use rocket_dyn_templates::{context, Metadata, Template};
use serde::Serialize;
use log::error;
use rocket::tokio::sync::{watch, RwLock};
use rocket::tokio::time;
use rocket_cache_response::CacheResponse;
use crate::geoip::{GeoIp, IpInfo};
use crate::lists::{CdnList, NetworkRecord, RuBlacklist};
use crate::resolver::Resolver;
use crate::target::Target;
use crate::updater::update_all;
#[derive(Serialize)]
struct GlobalContext {
version: &'static str,
}
impl GlobalContext {
fn new() -> Self {
GlobalContext { version: env!("CARGO_PKG_VERSION") }
}
}
#[get("/")]
fn index(info: &State<watch::Receiver<UpdateInfo>>) -> Template {
Template::render("index", context! {
global: GlobalContext::new(),
info: &*info.borrow(),
})
}
#[get("/kb/<page>")]
fn page(metadata: Metadata, page: &str) -> Option<Template> {
let page = format!("pages/{}", page);
if !metadata.contains_template(&page) {
return None;
}
Some(Template::render(page, context! {
global: GlobalContext::new(),
}))
}
#[get("/healthcheck")]
fn healthcheck(info: &State<watch::Receiver<UpdateInfo>>) -> (Status, String) {
if info.borrow().last_update.is_some() {
(Status::Ok, "OK".to_string())
} else {
(Status::InternalServerError, "LOADING DATABASES".to_string())
}
}
#[get("/check?<target>")]
async fn check(target: &str, resolver: &State<Resolver>,
geo_ip: &State<Arc<RwLock<GeoIp>>>,
cdn: &State<Arc<RwLock<CdnList>>>,
ru_blacklist: &State<Arc<RwLock<RuBlacklist>>>) -> Result<Template, Status> {
let target = Target::from(target);
let ips = match target.resolve(resolver).await {
Ok(ips) => ips,
Err(e) if e.kind().is_no_records_found() => {
return Ok(Template::render("empty", context! {
global: GlobalContext::new(),
target: target.to_query(),
target_type: target.readable_type(),
}));
}
Err(e) => {
error!("{}", e);
return Err(Status::BadRequest);
},
};
let geo_ip = geo_ip.read().await;
let geo = match ips.get(0).map(|ip| geo_ip.lookup(ip.clone())) {
None => IpInfo::default(),
Some(Ok(ip)) => ip,
Some(Err(e)) => {
error!("{}", e);
return Err(Status::BadRequest);
},
};
let mut providers: HashMap<String, HashSet<NetworkRecord>> = HashMap::new();
let cdn = cdn.read().await;
ips.iter()
.filter_map(|ip| cdn.contains(ip))
.map(|ip| (match &ip.region {
None => ip.provider.clone(),
Some(region) => format!("{} ({})", ip.provider, region),
}, ip.clone()))
.for_each(|(k, v)| {
providers.entry(k).or_default().insert(v);
});
let ru_blacklist = ru_blacklist.read().await;
let domain = match &target {
Target::Domain(domain) => ru_blacklist.contains_domain(domain),
_ => None
};
let blocked_subnets: HashSet<String> = ips.iter()
.filter_map(|ip| ru_blacklist.contains_ip(ip))
.map(|ip| ip.to_string()).collect();
Ok(Template::render("result", context! {
global: GlobalContext::new(),
found: providers.len() > 0 || domain.is_some() || blocked_subnets.len() > 0,
cdn_found: providers.len() > 0,
domain_found: domain.is_some(),
subnet_found: blocked_subnets.len() > 0,
providers,
domain,
blocked_subnets,
target: target.to_query(),
target_type: target.readable_type(),
ips,
geo,
}))
}
#[catch(default)]
fn default(status: Status, _req: &Request) -> Template {
Template::render("error", context! {
global: GlobalContext::new(),
status: status.code,
reason: status.reason_lossy(),
})
}
#[rocket::get("/vendor/lucide.js")]
fn lucide() -> CacheResponse<RawJavaScript<&'static [u8]>> {
CacheResponse::Public {
responder: RawJavaScript(include_bytes!(concat!(env!("OUT_DIR"), "/lucide.js"))),
max_age: 604800,
must_revalidate: false,
}
}
#[derive(Serialize, Default)]
pub struct UpdateInfo {
last_update: Option<DateTime<Utc>>,
domain_count: String,
v4_count: String,
}
fn format_number(number: u64) -> String {
number.to_string()
.as_bytes()
.rchunks(3)
.rev()
.map(std::str::from_utf8)
.collect::<Result<Vec<&str>, _>>()
.unwrap()
.join(" ")
}
#[launch]
async fn rocket() -> _ {
env_logger::builder().filter_level(log::LevelFilter::Info).init();
let mut interval = time::interval(Duration::from_secs(std::env::var("DATABASE_INTERVAL_SECONDS")
.unwrap_or("21600".to_string()).parse().unwrap()));
let (tx, rx) = watch::channel(UpdateInfo::default());
let cdn_list = Arc::new(RwLock::new(CdnList::new()));
let rkn_list = Arc::new(RwLock::new(RuBlacklist::new()));
let geo_ip = Arc::new(RwLock::new(GeoIp::new()));
let geo_ip_clone = geo_ip.clone();
let rkn_list_clone = rkn_list.clone();
let cdn_list_clone = cdn_list.clone();
tokio::spawn(async move {
info!("Refreshing DB every {:?}", interval.period());
loop {
interval.tick().await;
update_all(geo_ip_clone.clone(), rkn_list_clone.clone(), cdn_list_clone.clone()).await;
let domain_count = rkn_list_clone.read().await.domain_count;
let v4_count = rkn_list_clone.read().await.v4_count() + cdn_list_clone.read().await.v4_count();
tx.send(UpdateInfo {
last_update: Some(Utc::now()),
domain_count: format_number(domain_count as u64),
v4_count: format_number(v4_count as u64),
}).unwrap();
}
});
rocket::build()
.manage(Resolver::new().await)
.manage(cdn_list)
.manage(rkn_list)
.manage(geo_ip)
.manage(rx)
.mount("/", routes![index, lucide, check, healthcheck, page])
.register("/", catchers![default])
.mount("/", FileServer::from(PathBuf::from("static")))
.attach(Template::fairing())
}
-63
View File
@@ -1,63 +0,0 @@
use std::io;
use std::io::Error;
use std::sync::Arc;
use reqwest::IntoUrl;
use rocket::tokio::sync::RwLock;
use crate::geoip::GeoIp;
use crate::lists::{CdnList, RuBlacklist};
pub async fn fetch_db<T: IntoUrl>(url: T) -> Result<Vec<u8>, Error> {
let response = reqwest::get(url).await
.map_err(|e| Error::new(io::ErrorKind::Other, e))?
.error_for_status()
.map_err(|e| Error::new(io::ErrorKind::Other, e))?;
let bytes = response.bytes().await
.map_err(|e| Error::new(io::ErrorKind::Other, e))?;
Ok(bytes.to_vec())
}
#[async_trait]
pub trait Updatable {
type Base;
async fn download() -> Result<Self::Base, Error>;
async fn install(&mut self, base: Self::Base) -> Result<(), Error>;
fn get_url(key: &'static str, default: &'static str) -> String {
std::env::var(key).ok().unwrap_or(default.to_string())
}
}
pub async fn update_all(geo_ip: Arc<RwLock<GeoIp>>, rkn: Arc<RwLock<RuBlacklist>>, cdn: Arc<RwLock<CdnList>>) {
info!("Updating all DBs");
match GeoIp::download().await {
Ok(base) => {
if let Err(e) = geo_ip.write().await.install(base).await {
error!("Failed to update GeoIP: {}", e);
}
}
Err(e) => {
error!("Failed to download GeoIP: {}", e);
}
}
match RuBlacklist::download().await {
Ok(base) => {
if let Err(e) = rkn.write().await.install(base).await {
error!("Failed to update RKN: {}", e);
}
}
Err(e) => {
error!("Failed to download RKN: {}", e);
}
}
match CdnList::download().await {
Ok(base) => {
if let Err(e) = cdn.write().await.install(base).await {
error!("Failed to update CDN: {}", e);
}
}
Err(e) => {
error!("Failed to download CDN: {}", e);
}
}
info!("Updated databases");
}
+4 -7
View File
@@ -1,8 +1,5 @@
FROM docker.io/rust:1-slim-bookworm AS build
## cargo package name: customize here or provide via --build-arg
ARG pkg=blocklist-check
WORKDIR /build
COPY . .
@@ -13,8 +10,8 @@ RUN --mount=type=cache,target=/build/target \
--mount=type=cache,target=/usr/local/cargo/registry \
--mount=type=cache,target=/usr/local/cargo/git \
set -eux; \
cargo build --release; \
objcopy --compress-debug-sections target/release/$pkg ./main
cargo build --release --package website; \
objcopy --compress-debug-sections target/release/website ./main
################################################################################
@@ -27,8 +24,8 @@ RUN apt update && apt install -y libssl3 ca-certificates curl
## copy the main binary
COPY --from=build /build/main ./
COPY --from=build /build/static ./static
COPY --from=build /build/templates ./templates
COPY --from=build /build/website/static ./static
COPY --from=build /build/website/templates ./templates
## ensure the container listens globally on port 8080
ENV ROCKET_ADDRESS=0.0.0.0
+3809
View File
File diff suppressed because it is too large Load Diff
+19
View File
@@ -0,0 +1,19 @@
[package]
name = "website"
version = "0.1.3"
edition = "2024"
[dependencies]
rocket = "0.5.1"
rocket_dyn_templates = { version = "0.2.0", features = ["tera"] }
serde = { version = "1", features = ["derive"] }
querying = { path = "../querying" }
env_logger = "0.11.8"
rocket-cache-response = "0.6.4"
log = { workspace = true }
[build-dependencies]
reqwest = { version = "0.12", features = ["blocking", "json"] }
serde = { version = "1", features = ["derive"] }
tar = "0.4"
flate2 = "1.0"
View File
+164
View File
@@ -0,0 +1,164 @@
#[macro_use] extern crate rocket;
use std::path::PathBuf;
use std::sync::Arc;
use std::time::Duration;
use rocket::fs::FileServer;
use rocket::http::Status;
use rocket::{tokio, Request, State};
use rocket::response::content::RawJavaScript;
use rocket_dyn_templates::{context, Metadata, Template};
use serde::Serialize;
use log::error;
use rocket::tokio::sync::RwLock;
use rocket::tokio::time;
use rocket_cache_response::CacheResponse;
use querying::{Check, CheckError, CheckVerdict, Checker};
use querying::resolver::Resolver;
use querying::target::Target;
#[derive(Serialize)]
struct GlobalContext {
version: &'static str,
}
impl GlobalContext {
fn new() -> Self {
GlobalContext { version: env!("CARGO_PKG_VERSION") }
}
}
#[get("/")]
async fn index(checker: &State<Arc<RwLock<Checker>>>) -> Template {
let checker_ref = checker.read().await;
Template::render("index", context! {
global: GlobalContext::new(),
domain_count: format_number(checker_ref.total_domains().await),
v4_count: format_number(checker_ref.total_v4s().await),
last_update: checker_ref.last_update(),
})
}
#[get("/kb/<page>")]
fn page(metadata: Metadata, page: &str) -> Option<Template> {
let page = format!("pages/{}", page);
if !metadata.contains_template(&page) {
return None;
}
Some(Template::render(page, context! {
global: GlobalContext::new(),
}))
}
#[get("/healthcheck")]
async fn healthcheck(checker: &State<Arc<RwLock<Checker>>>) -> (Status, String) {
if checker.read().await.last_update().is_some() {
(Status::Ok, "OK".to_string())
} else {
(Status::InternalServerError, "LOADING DATABASES".to_string())
}
}
#[get("/check?<target>")]
async fn check(target: &str, checker: &State<Arc<RwLock<Checker>>>) -> Result<Template, Status> {
let target = Target::from(target);
match checker.read().await.check(target.clone()).await {
Err(CheckError::NotFound) =>
Ok(Template::render("empty", context! {
global: GlobalContext::new(),
target: target.to_query(),
target_type: target.readable_type(),
})),
Ok(Check { verdict: CheckVerdict::Clear, geo, ips }) =>
Ok(Template::render("result", context! {
global: GlobalContext::new(),
found: false,
target: target.to_query(),
target_type: target.readable_type(),
ips,
geo,
})),
Ok(Check {
verdict: CheckVerdict::Blocked {
rkn_domain,
rkn_subnets,
cdn_provider_subnets
}, geo, ips }) =>
Ok(Template::render("result", context! {
global: GlobalContext::new(),
found: true,
domain: rkn_domain,
providers: cdn_provider_subnets,
blocked_subnets: rkn_subnets.iter()
.map(|n| n.to_string())
.collect::<Vec<_>>(),
target: target.to_query(),
target_type: target.readable_type(),
ips,
geo,
})),
Err(e) => {
error!("check failed {:?}", e);
Err(Status::InternalServerError)
}
}
}
#[catch(default)]
fn default(status: Status, _req: &Request) -> Template {
Template::render("error", context! {
global: GlobalContext::new(),
status: status.code,
reason: status.reason_lossy(),
})
}
#[rocket::get("/vendor/lucide.js")]
fn lucide() -> CacheResponse<RawJavaScript<&'static [u8]>> {
CacheResponse::Public {
responder: RawJavaScript(include_bytes!(concat!(env!("OUT_DIR"), "/lucide.js"))),
max_age: 604800,
must_revalidate: false,
}
}
fn format_number(number: usize) -> String {
number.to_string()
.as_bytes()
.rchunks(3)
.rev()
.map(std::str::from_utf8)
.collect::<Result<Vec<&str>, _>>()
.unwrap()
.join(" ")
}
#[launch]
async fn rocket() -> _ {
env_logger::builder().filter_level(log::LevelFilter::Info).init();
let mut interval = time::interval(Duration::from_secs(std::env::var("DATABASE_INTERVAL_SECONDS")
.unwrap_or("21600".to_string()).parse().unwrap()));
let checker = Arc::new(RwLock::new(Checker::new().await));
let checker_clone = checker.clone();
tokio::spawn(async move {
info!("Refreshing DB every {:?}", interval.period());
loop {
interval.tick().await;
log::info!("Updating all DBs");
checker_clone.read().await.update_all().await;
log::info!("Updated databases");
}
});
rocket::build()
.manage(Resolver::new().await)
.manage(checker)
.mount("/", routes![index, lucide, check, healthcheck, page])
.register("/", catchers![default])
.mount("/", FileServer::from(PathBuf::from("static")))
.attach(Template::fairing())
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 734 B

Before

Width:  |  Height:  |  Size: 501 B

After

Width:  |  Height:  |  Size: 501 B

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 15 KiB

@@ -6,6 +6,7 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="/main.css"/>
<link rel="icon" type="image/png" href="/favicon.png">
<link rel="icon" type="image/svg+xml" href="/favicon.svg">
{% block metadata %}
@@ -31,21 +31,21 @@
<i data-lucide="globe" width="16" height="16"></i>
<span>Количество доменов</span>
</div>
<span>{{ info.domain_count }}</span>
<span>{{ domain_count }}</span>
</div>
<div class="stat-card">
<div class="stat-card-header">
<i data-lucide="server" width="16" height="16"></i>
<span>Количество IPv4-адресов</span>
</div>
<span>{{ info.v4_count }}</span>
<span>{{ v4_count }}</span>
</div>
<div class="stat-card">
<div class="stat-card-header">
<i data-lucide="activity" width="16" height="16"></i>
<span>Последнее обновление</span>
</div>
<span><script>document.write(new Date("{{ info.last_update }}").toLocaleString())</script></span>
<span><script>document.write(new Date("{{ last_update }}").toLocaleString())</script></span>
</div>
</div>
{% endblock content %}
@@ -58,39 +58,41 @@
<h3 class="reason-header">Нахождение в списках</h3>
<div class="detail-row">
<span class="row-label">CDN</span>
{% if cdn_found %}
{% if providers %}
<p class="row-value alert">НАЙДЕН</p>
{% else %}
<span class="row-value">Не найден</span>
{% endif %}
</div>
{% for provider, networks in providers %}
<div class="detail-row">
<span class="row-label">{{ provider }}</span>
<div>
{% for network in networks %}
<p class="row-value">{{ network.cidr }}</p>
{% endfor %}
{% if providers %}
{% for provider, networks in providers %}
<div class="detail-row">
<span class="row-label">{{ provider }}</span>
<div>
{% for network in networks %}
<p class="row-value">{{ network.cidr }}</p>
{% endfor %}
</div>
</div>
</div>
{% endfor %}
{% endfor %}
{% endif %}
<div class="detail-row">
<span class="row-label">Реестр РКН</span>
{% if domain_found or subnet_found %}
{% if domain or blocked_subnets %}
<span class="row-value alert">ОГРАНИЧЕН</span>
{% else %}
<span class="row-value">Не найден</span>
{% endif %}
</div>
{% if domain_found %}
{% if domain %}
<div class="detail-row">
<span class="row-label">Заблокированный домен</span>
<span class="row-value">{{ domain }}</span>
</div>
{% endif %}
{% if subnet_found %}
{% if blocked_subnets %}
<div class="detail-row">
<span class="row-label">Заблокированные подсети</span>
<div>