diff --git a/Cargo.lock b/Cargo.lock index c25150c9b..835583649 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,12 +2,6 @@ # It is not intended for manual editing. version = 3 -[[package]] -name = "Inflector" -version = "0.11.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe438c63458706e03479442743baae6c88256498e6431708f6dfc520a26515d3" - [[package]] name = "actix" version = "0.13.1" @@ -26,7 +20,7 @@ dependencies = [ "futures-util", "log", "once_cell", - "parking_lot 0.12.1", + "parking_lot", "pin-project-lite", "smallvec", "tokio", @@ -60,7 +54,7 @@ dependencies = [ "actix-rt", "actix-service", "actix-utils", - "ahash 0.8.3", + "ahash", "base64 0.21.3", "bitflags 2.4.0", "brotli", @@ -169,9 +163,9 @@ dependencies = [ [[package]] name = "actix-toolbox" -version = "0.11.0" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2278c18baa8abc4936303bd17fb7724902138f36c14fe98cdaf80de32844c077" +checksum = "671496831a04cc1f9c9160b5bcd43d76415dad27c310b0e9e2f5d7097104d3e0" dependencies = [ "actix", "actix-session", @@ -218,7 +212,7 @@ dependencies = [ "actix-service", "actix-utils", "actix-web-codegen", - "ahash 0.8.3", + "ahash", "bytes", "bytestring", "cfg-if", @@ -239,7 +233,7 @@ dependencies = [ "serde_urlencoded", "smallvec", "socket2 0.5.3", - "time 0.3.28", + "time", "url", ] @@ -334,17 +328,6 @@ dependencies = [ "subtle", ] -[[package]] -name = "ahash" -version = "0.7.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47" -dependencies = [ - "getrandom", - "once_cell", - "version_check", -] - [[package]] name = "ahash" version = "0.8.3" @@ -366,12 +349,6 @@ dependencies = [ "memchr", ] -[[package]] -name = "aliasable" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "250f629c0161ad8107cf89319e990051fae62832fd343083bea452d93e2205fd" - [[package]] name = "alloc-no-stdlib" version = "2.0.4" @@ -493,7 +470,7 @@ dependencies = [ "num-traits", "rusticata-macros", "thiserror", - "time 0.3.28", + "time", ] [[package]] @@ -554,9 +531,9 @@ dependencies = [ [[package]] name = "atoi" -version = "1.0.0" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7c57d12312ff59c811c0643f4d80830505833c9ffaebd193d819392b265be8e" +checksum = "f28d99ec8bfea296261ca1af174f24225171fea9664ba9003cbebee704810528" dependencies = [ "num-traits", ] @@ -662,6 +639,12 @@ dependencies = [ "serde_json", ] +[[package]] +name = "bit-vec" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" + [[package]] name = "bitflags" version = "1.3.2" @@ -673,6 +656,9 @@ name = "bitflags" version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635" +dependencies = [ + "serde", +] [[package]] name = "blake2" @@ -768,16 +754,15 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "chrono" -version = "0.4.29" +version = "0.4.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d87d9d13be47a5b7c3907137f1290b0459a7f80efb26be8c52afb11963bccb02" +checksum = "defd4e7873dbddba6c7c91e199c7fcb946abc4a6a4ac3195400bcfb01b5de877" dependencies = [ "android-tzdata", "iana-time-zone", "js-sys", "num-traits", "serde", - "time 0.1.45", "wasm-bindgen", "windows-targets", ] @@ -857,9 +842,9 @@ dependencies = [ [[package]] name = "const-oid" -version = "0.7.1" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4c78c047431fee22c1a7bb92e00ad095a02a983affe4d8a72e2a2c62c1b94f3" +checksum = "28c122c3980598d243d63d9a704629a2d748d101f278052ff068be5a4423ab6f" [[package]] name = "convert_case" @@ -881,7 +866,7 @@ dependencies = [ "rand", "sha2", "subtle", - "time 0.3.28", + "time", "version_check", ] @@ -963,16 +948,6 @@ dependencies = [ "cfg-if", ] -[[package]] -name = "crypto-bigint" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03c6a1d5fa1de37e071642dfa44ec552ca5b299adb128fab16138e24b548fd21" -dependencies = [ - "generic-array", - "subtle", -] - [[package]] name = "crypto-common" version = "0.1.6" @@ -1051,13 +1026,13 @@ dependencies = [ [[package]] name = "der" -version = "0.5.1" +version = "0.7.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6919815d73839e7ad218de758883aae3a257ba6759ce7a9992501efbb53d705c" +checksum = "fffa369a668c8af7dbf8b5e56c9f744fbd399949ed171606040001947de40b1c" dependencies = [ "const-oid", - "crypto-bigint", "pem-rfc7468", + "zeroize", ] [[package]] @@ -1117,6 +1092,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ "block-buffer", + "const-oid", "crypto-common", "subtle", ] @@ -1163,6 +1139,9 @@ name = "either" version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" +dependencies = [ + "serde", +] [[package]] name = "encoding_rs" @@ -1225,6 +1204,17 @@ dependencies = [ "libc", ] +[[package]] +name = "etcetera" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "136d1b5283a1ab77bd9257427ffd09d8667ced0570b6f938942bc7568ed5b943" +dependencies = [ + "cfg-if", + "home", + "windows-sys", +] + [[package]] name = "event-listener" version = "2.5.3" @@ -1345,13 +1335,13 @@ dependencies = [ [[package]] name = "futures-intrusive" -version = "0.4.2" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a604f7a68fbf8103337523b1fadc8ade7361ee3f112f7c680ad179651616aed5" +checksum = "1d930c203dd0b6ff06e0201a4a2fe9149b43c684fd4420555b26d21b1a02956f" dependencies = [ "futures-core", "lock_api", - "parking_lot 0.11.2", + "parking_lot", ] [[package]] @@ -1419,7 +1409,7 @@ checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" dependencies = [ "cfg-if", "libc", - "wasi 0.11.0+wasi-snapshot-preview1", + "wasi", ] [[package]] @@ -1481,7 +1471,7 @@ version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2c6201b9ff9fd90a5a3bac2e56a830d0caa509576f0e503818ee82c181b3437a" dependencies = [ - "ahash 0.8.3", + "ahash", "allocator-api2", ] @@ -1736,15 +1726,6 @@ dependencies = [ "generic-array", ] -[[package]] -name = "instant" -version = "0.1.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" -dependencies = [ - "cfg-if", -] - [[package]] name = "ipconfig" version = "0.3.2" @@ -1766,6 +1747,15 @@ dependencies = [ "serde", ] +[[package]] +name = "ipnetwork" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf466541e9d546596ee94f9f69590f89473455f88372423e0008fc1a7daf100e" +dependencies = [ + "serde", +] + [[package]] name = "is-terminal" version = "0.4.9" @@ -1824,6 +1814,7 @@ dependencies = [ "dehashed-rs", "futures", "ipnet", + "ipnetwork", "log", "prost", "prost-types", @@ -1909,9 +1900,9 @@ checksum = "f7012b1bbb0719e1097c47611d3898568c546d597c2e74d66f6087edd5233ff4" [[package]] name = "libsqlite3-sys" -version = "0.24.2" +version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "898745e570c7d0453cc1fbc4a701eb6c662ed54e8fec8b7d14be137ebeeb9d14" +checksum = "afc22eff61b133b115c6e8c74e818c628d6d5e7a502afea6f64dee076dd94326" dependencies = [ "cc", "pkg-config", @@ -2009,7 +2000,7 @@ dependencies = [ "libc", "log", "log-mdc", - "parking_lot 0.12.1", + "parking_lot", "serde", "serde-value", "serde_json", @@ -2029,6 +2020,16 @@ dependencies = [ "linked-hash-map", ] +[[package]] +name = "mac_address" +version = "1.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4863ee94f19ed315bf3bc00299338d857d4b5bc856af375cc97d237382ad3856" +dependencies = [ + "nix", + "winapi", +] + [[package]] name = "match_cfg" version = "0.1.0" @@ -2062,6 +2063,15 @@ version = "2.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f232d6ef707e1956a43342693d2a31e72989554d58299d7a88738cc95b0d35c" +[[package]] +name = "memoffset" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce" +dependencies = [ + "autocfg", +] + [[package]] name = "mime" version = "0.3.17" @@ -2101,7 +2111,7 @@ checksum = "927a765cd3fc26206e66b296465fa9d3e5ab003e651c1b3c060e7956d96b19d2" dependencies = [ "libc", "log", - "wasi 0.11.0+wasi-snapshot-preview1", + "wasi", "windows-sys", ] @@ -2129,6 +2139,19 @@ dependencies = [ "tempfile", ] +[[package]] +name = "nix" +version = "0.23.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f3790c00a0150112de0f4cd161e3d7fc4b2d8a5542ffc35f099a2562aecb35c" +dependencies = [ + "bitflags 1.3.2", + "cc", + "cfg-if", + "libc", + "memoffset", +] + [[package]] name = "no-std-net" version = "0.6.0" @@ -2308,40 +2331,6 @@ dependencies = [ "serde", ] -[[package]] -name = "ouroboros" -version = "0.15.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1358bd1558bd2a083fed428ffeda486fbfb323e698cdda7794259d592ca72db" -dependencies = [ - "aliasable", - "ouroboros_macro", -] - -[[package]] -name = "ouroboros_macro" -version = "0.15.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f7d21ccd03305a674437ee1248f3ab5d4b1db095cf1caf49f1713ddf61956b7" -dependencies = [ - "Inflector", - "proc-macro-error", - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "parking_lot" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99" -dependencies = [ - "instant", - "lock_api", - "parking_lot_core 0.8.6", -] - [[package]] name = "parking_lot" version = "0.12.1" @@ -2349,21 +2338,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" dependencies = [ "lock_api", - "parking_lot_core 0.9.8", -] - -[[package]] -name = "parking_lot_core" -version = "0.8.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60a2cfe6f0ad2bfc16aefa463b497d5c7a5ecd44a23efa72aa342d90177356dc" -dependencies = [ - "cfg-if", - "instant", - "libc", - "redox_syscall 0.2.16", - "smallvec", - "winapi", + "parking_lot_core", ] [[package]] @@ -2398,9 +2373,9 @@ checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" [[package]] name = "pem-rfc7468" -version = "0.3.1" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01de5d978f34aa4b2296576379fcc416034702fd94117c56ffd8a1a767cefb30" +checksum = "88b39c9bfcfc231068454382784bb460aae594343fb030d46e9f50a645418412" dependencies = [ "base64ct", ] @@ -2455,24 +2430,23 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] name = "pkcs1" -version = "0.3.3" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a78f66c04ccc83dd4486fd46c33896f4e17b24a7a3a6400dedc48ed0ddd72320" +checksum = "c8ffb9f10fa047879315e6625af03c164b16962a5368d724ed16323b68ace47f" dependencies = [ "der", "pkcs8", - "zeroize", + "spki", ] [[package]] name = "pkcs8" -version = "0.8.0" +version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7cabda3fb821068a9a4fab19a683eac3af12edf0f34b94a8be53c4972b8149d0" +checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" dependencies = [ "der", "spki", - "zeroize", ] [[package]] @@ -2543,9 +2517,9 @@ checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" [[package]] name = "prettyplease" -version = "0.2.14" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8832c0f9be7e3cae60727e6256cfd2cd3c3e2b6cd5dad4190ecb2fd658c9030b" +checksum = "ae005bd773ab59b4725093fd7df83fd7892f7d8eafb48dbd7de6e024e4215f9d" dependencies = [ "proc-macro2", "syn 2.0.31", @@ -2822,19 +2796,22 @@ dependencies = [ [[package]] name = "rorm" -version = "0.5.3" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9a6bbee31206b1e7c4dc86b31b491162d5e3595dd7be0d234ad2f8248f71720" +checksum = "de0eed15701ac6010df37109893e83cfd5b18bd9e208687b011ce79ffefe7ee0" dependencies = [ + "bit-vec", "chrono", "futures", + "ipnetwork", "linkme", - "ouroboros", + "mac_address", "pin-project", "rorm-cli", "rorm-db", "rorm-declaration", "rorm-macro", + "rustc_version", "serde", "serde_json", "uuid", @@ -2842,74 +2819,81 @@ dependencies = [ [[package]] name = "rorm-cli" -version = "0.7.3" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8293f6560be934927037acbd78472e02de52cd2ce1c1131e249296540575bd7" +checksum = "5eeb91478da697a489b340d587ba9076870b19d389a54a984a7809ffbe11ca26" dependencies = [ "anyhow", "clap", "once_cell", "regex", + "rorm-db", "rorm-declaration", "rorm-sql", "rpassword", "serde", "serde_json", - "sqlx", "strum", "toml", ] [[package]] name = "rorm-db" -version = "0.8.1" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3946457d1326a637d22d88f14635b4c0b69061f21161e55a114d4b574ce1eb80" +checksum = "1ccef391d5e25f29aa7d6876347fe7d78713731d93f70fc05583094b4f569b43" dependencies = [ - "aliasable", "futures", "log", - "ouroboros", "pin-project", "rorm-declaration", "rorm-sql", + "rustc_version", "serde", "sqlx", ] [[package]] name = "rorm-declaration" -version = "0.3.0" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c8540970180a180a2d87d529f39874e40cefce8bac13012030b49a941659289" +checksum = "b6ee80ca31f108f0e6eb33cf33d1b6e7e57ef36eb530d2758792f608022a4282" dependencies = [ "ordered-float 3.9.1", + "rustc_version", "serde", "strum", ] [[package]] name = "rorm-macro" -version = "0.6.0" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fca53686a59dd381b867c6403670ed75b2efdaf39d18bd7f8fba89a1ee0ec847" +checksum = "711d39add68b078f2096878af4882855484c304fe31cba7adc95bcc757dfe82d" dependencies = [ "darling", "proc-macro2", "quote", + "rustc_version", "syn 1.0.109", ] [[package]] name = "rorm-sql" -version = "0.6.2" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f246e637bb4566dfd82446625344a69c8c369d013716833a61b897b03cff5e56" +checksum = "9f44ee43c3943eb17dfa82f70f7b22c705cab170859d85859dd9da2aef864a4c" dependencies = [ + "bit-vec", "chrono", - "libsqlite3-sys", + "ipnetwork", + "mac_address", "rorm-declaration", "rustc_version", + "serde", + "serde_json", + "time", + "uuid", ] [[package]] @@ -2925,11 +2909,12 @@ dependencies = [ [[package]] name = "rsa" -version = "0.6.1" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4cf22754c49613d2b3b119f0e5d46e34a2c628a937e3024b8762de4e7d8c710b" +checksum = "6ab43bb47d23c1a631b4b680199a45255dce26fa9ab2fa902581f624ff13e6a8" dependencies = [ "byteorder", + "const-oid", "digest", "num-bigint-dig", "num-integer", @@ -2938,7 +2923,8 @@ dependencies = [ "pkcs1", "pkcs8", "rand_core", - "smallvec", + "signature", + "spki", "subtle", "zeroize", ] @@ -3290,6 +3276,16 @@ dependencies = [ "libc", ] +[[package]] +name = "signature" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e1788eed21689f9cf370582dfc467ef36ed9c707f073528ddafa8d83e3b8500" +dependencies = [ + "digest", + "rand_core", +] + [[package]] name = "slab" version = "0.4.9" @@ -3342,9 +3338,9 @@ dependencies = [ [[package]] name = "spki" -version = "0.5.4" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44d01ac02a6ccf3e07db148d2be087da624fea0221a16152ed01f0496a6b0a27" +checksum = "9d1e996ef02c474957d681f1b05213dfb0abab947b446a62d37770b23500184a" dependencies = [ "base64ct", "der", @@ -3363,103 +3359,218 @@ dependencies = [ [[package]] name = "sqlx" -version = "0.6.3" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8de3b03a925878ed54a954f621e64bf55a3c1bd29652d0d1a17830405350188" +checksum = "8e58421b6bc416714d5115a2ca953718f6c621a51b68e4f4922aea5a4391a721" dependencies = [ "sqlx-core", "sqlx-macros", + "sqlx-mysql", + "sqlx-postgres", + "sqlx-sqlite", ] [[package]] name = "sqlx-core" -version = "0.6.3" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa8241483a83a3f33aa5fff7e7d9def398ff9990b2752b6c6112b83c6d246029" +checksum = "dd4cef4251aabbae751a3710927945901ee1d97ee96d757f6880ebb9a79bfd53" dependencies = [ - "ahash 0.7.6", + "ahash", "atoi", - "base64 0.13.1", - "bitflags 1.3.2", + "bit-vec", "byteorder", "bytes", "chrono", "crc", "crossbeam-queue", - "digest", - "dirs", "dotenvy", "either", "event-listener", - "flume", "futures-channel", "futures-core", - "futures-executor", "futures-intrusive", + "futures-io", "futures-util", - "generic-array", "hashlink", "hex", - "hkdf", - "hmac", - "indexmap 1.9.3", - "itoa", - "libc", - "libsqlite3-sys", + "indexmap 2.0.0", + "ipnetwork", "log", - "md-5", + "mac_address", "memchr", - "num-bigint", "once_cell", "paste", "percent-encoding", - "rand", - "rsa", - "rustls 0.20.9", + "rustls 0.21.7", "rustls-pemfile", "serde", "serde_json", - "sha1", "sha2", "smallvec", "sqlformat", - "sqlx-rt", - "stringprep", "thiserror", + "time", + "tokio", "tokio-stream", + "tracing", "url", - "webpki-roots", - "whoami", + "uuid", + "webpki-roots 0.24.0", ] [[package]] name = "sqlx-macros" -version = "0.6.3" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9966e64ae989e7e575b19d7265cb79d7fc3cbbdf179835cb0d716f294c2049c9" +checksum = "208e3165167afd7f3881b16c1ef3f2af69fa75980897aac8874a0696516d12c2" +dependencies = [ + "proc-macro2", + "quote", + "sqlx-core", + "sqlx-macros-core", + "syn 1.0.109", +] + +[[package]] +name = "sqlx-macros-core" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a4a8336d278c62231d87f24e8a7a74898156e34c1c18942857be2acb29c7dfc" dependencies = [ "dotenvy", "either", "heck", + "hex", "once_cell", "proc-macro2", "quote", + "serde", + "serde_json", "sha2", "sqlx-core", - "sqlx-rt", + "sqlx-mysql", + "sqlx-postgres", + "sqlx-sqlite", "syn 1.0.109", + "tempfile", + "tokio", "url", ] [[package]] -name = "sqlx-rt" -version = "0.6.3" +name = "sqlx-mysql" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "804d3f245f894e61b1e6263c84b23ca675d96753b5abfd5cc8597d86806e8024" +checksum = "8ca69bf415b93b60b80dc8fda3cb4ef52b2336614d8da2de5456cc942a110482" dependencies = [ + "atoi", + "base64 0.21.3", + "bitflags 2.4.0", + "byteorder", + "bytes", + "chrono", + "crc", + "digest", + "dotenvy", + "either", + "futures-channel", + "futures-core", + "futures-io", + "futures-util", + "generic-array", + "hex", + "hkdf", + "hmac", + "itoa", + "log", + "md-5", + "memchr", "once_cell", - "tokio", - "tokio-rustls 0.23.4", + "percent-encoding", + "rand", + "rsa", + "serde", + "sha1", + "sha2", + "smallvec", + "sqlx-core", + "stringprep", + "thiserror", + "time", + "tracing", + "uuid", + "whoami", +] + +[[package]] +name = "sqlx-postgres" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0db2df1b8731c3651e204629dd55e52adbae0462fa1bdcbed56a2302c18181e" +dependencies = [ + "atoi", + "base64 0.21.3", + "bit-vec", + "bitflags 2.4.0", + "byteorder", + "chrono", + "crc", + "dotenvy", + "etcetera", + "futures-channel", + "futures-core", + "futures-io", + "futures-util", + "hex", + "hkdf", + "hmac", + "home", + "ipnetwork", + "itoa", + "log", + "mac_address", + "md-5", + "memchr", + "once_cell", + "rand", + "serde", + "serde_json", + "sha1", + "sha2", + "smallvec", + "sqlx-core", + "stringprep", + "thiserror", + "time", + "tracing", + "uuid", + "whoami", +] + +[[package]] +name = "sqlx-sqlite" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be4c21bf34c7cae5b283efb3ac1bcc7670df7561124dc2f8bdc0b59be40f79a2" +dependencies = [ + "atoi", + "chrono", + "flume", + "futures-channel", + "futures-core", + "futures-executor", + "futures-intrusive", + "futures-util", + "libsqlite3-sys", + "log", + "percent-encoding", + "serde", + "sqlx-core", + "time", + "tracing", + "url", + "uuid", ] [[package]] @@ -3481,24 +3592,24 @@ checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" [[package]] name = "strum" -version = "0.24.1" +version = "0.25.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "063e6045c0e62079840579a7e47a355ae92f60eb74daaf156fb1e84ba164e63f" +checksum = "290d54ea6f91c969195bdbcd7442c8c2a2ba87da8bf60a7ee86a235d4bc1e125" dependencies = [ "strum_macros", ] [[package]] name = "strum_macros" -version = "0.24.3" +version = "0.25.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e385be0d24f186b4ce2f9982191e7101bb737312ad61c1f2f984f34bcf85d59" +checksum = "ad8d03b598d3d0fff69bf533ee3ef19b8eeb342729596df84bcc7e1f96ec4059" dependencies = [ "heck", "proc-macro2", "quote", "rustversion", - "syn 1.0.109", + "syn 2.0.31", ] [[package]] @@ -3514,7 +3625,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "af341b2be485d647b5dc4cfb2da99efac35b5c95748a08fb7233480fedc5ead3" dependencies = [ "hex", - "parking_lot 0.12.1", + "parking_lot", "pnet_packet", "rand", "socket2 0.5.3", @@ -3616,17 +3727,6 @@ dependencies = [ "winapi", ] -[[package]] -name = "time" -version = "0.1.45" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b797afad3f312d1c66a56d11d0316f916356d11bd158fbc6ca6389ff6bf805a" -dependencies = [ - "libc", - "wasi 0.10.0+wasi-snapshot-preview1", - "winapi", -] - [[package]] name = "time" version = "0.3.28" @@ -3681,7 +3781,7 @@ dependencies = [ "libc", "mio", "num_cpus", - "parking_lot 0.12.1", + "parking_lot", "pin-project-lite", "signal-hook-registry", "socket2 0.5.3", @@ -3768,9 +3868,9 @@ dependencies = [ [[package]] name = "toml" -version = "0.7.6" +version = "0.7.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c17e963a819c331dcacd7ab957d80bc2b9a9c1e71c804826d2f283dd65306542" +checksum = "de0a3ab2091e52d7299a39d098e200114a972df0a7724add02a273aa9aada592" dependencies = [ "serde", "serde_spanned", @@ -3789,9 +3889,9 @@ dependencies = [ [[package]] name = "toml_edit" -version = "0.19.14" +version = "0.19.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8123f27e969974a3dfba720fdb560be359f57b44302d280ba72e76a74480e8a" +checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" dependencies = [ "indexmap 2.0.0", "serde", @@ -3937,7 +4037,7 @@ dependencies = [ "tracing", "url", "webpki", - "webpki-roots", + "webpki-roots 0.22.6", ] [[package]] @@ -3951,7 +4051,7 @@ dependencies = [ "ipconfig", "lazy_static", "lru-cache", - "parking_lot 0.12.1", + "parking_lot", "resolv-conf", "rustls 0.20.9", "smallvec", @@ -3960,7 +4060,7 @@ dependencies = [ "tokio-rustls 0.23.4", "tracing", "trust-dns-proto", - "webpki-roots", + "webpki-roots 0.22.6", ] [[package]] @@ -4164,12 +4264,6 @@ dependencies = [ "try-lock", ] -[[package]] -name = "wasi" -version = "0.10.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f" - [[package]] name = "wasi" version = "0.11.0+wasi-snapshot-preview1" @@ -4321,6 +4415,15 @@ dependencies = [ "webpki", ] +[[package]] +name = "webpki-roots" +version = "0.24.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b291546d5d9d1eab74f069c77749f2cb8504a12caa20f0f2de93ddbf6f411888" +dependencies = [ + "rustls-webpki", +] + [[package]] name = "which" version = "4.4.2" @@ -4338,10 +4441,6 @@ name = "whoami" version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "22fc3756b8a9133049b26c7f61ab35416c130e8c09b660f5b3958b446f52cc50" -dependencies = [ - "wasm-bindgen", - "web-sys", -] [[package]] name = "widestring" @@ -4489,7 +4588,7 @@ dependencies = [ "oid-registry", "rusticata-macros", "thiserror", - "time 0.3.28", + "time", ] [[package]] diff --git a/deny.toml b/deny.toml index 5ae9e6427..89d5a58e0 100644 --- a/deny.toml +++ b/deny.toml @@ -19,10 +19,7 @@ allow = [ "LicenseRef-ring", "AGPL-3.0" ] - -deny = [ - -] +deny = [] # Exception for rings license [[licenses.clarify]] diff --git a/kraken/Cargo.toml b/kraken/Cargo.toml index f512cc4f8..41bbf7bf1 100644 --- a/kraken/Cargo.toml +++ b/kraken/Cargo.toml @@ -13,7 +13,7 @@ description = "The core component of kraken-project" # Webframework actix-web = { version = "~4" } # Extensions for actix-web -actix-toolbox = { version = "~0.12", features = ["ws", "logging", "session"] } +actix-toolbox = { version = "~0.13", features = ["ws", "logging", "session-postgres-only"] } # Webauthn library webauthn-rs = { version = "~0.4", features = ["danger-allow-state-serialisation"] } @@ -67,7 +67,8 @@ prost-types = { version = "~0.12" } thiserror = { version = "~1" } # ORM -rorm = { version = "~0.6", default-features = false, features = ["tokio", "rustls", "cli", "uuid", "postgres-only"] } +rorm = { version = "~0.6", default-features = false, features = ["tokio", "rustls", "cli", "uuid", "postgres-only", "chrono"] } +ipnetwork = { version = "~0.20" } # API for dehashed dehashed-rs = { version = "~0.3", features = ["tokio", "utoipa"] } diff --git a/kraken/migrations/0002_placeholder.toml b/kraken/migrations/0002_placeholder.toml new file mode 100644 index 000000000..7cb3b6ba0 --- /dev/null +++ b/kraken/migrations/0002_placeholder.toml @@ -0,0 +1,136 @@ +[Migration] +Hash = "15664649178895690706" +Initial = false +Dependency = 1 +Replaces = [] + +[[Migration.Operations]] +Type = "CreateModel" +Name = "certificatetransparencyvaluename" + +[[Migration.Operations.Fields]] +Name = "uuid" +Type = "varbinary" + +[[Migration.Operations.Fields.Annotations]] +Type = "primary_key" + +[[Migration.Operations.Fields]] +Name = "value_name" +Type = "varchar" + +[[Migration.Operations.Fields.Annotations]] +Type = "max_length" +Value = 255 + +[[Migration.Operations.Fields.Annotations]] +Type = "not_null" + +[[Migration.Operations]] +Type = "CreateModel" +Name = "certificatetransparencyresult" + +[[Migration.Operations.Fields]] +Name = "uuid" +Type = "varbinary" + +[[Migration.Operations.Fields.Annotations]] +Type = "primary_key" + +[[Migration.Operations.Fields]] +Name = "created_at" +Type = "datetime" + +[[Migration.Operations.Fields.Annotations]] +Type = "auto_create_time" + +[[Migration.Operations.Fields.Annotations]] +Type = "not_null" + +[[Migration.Operations.Fields]] +Name = "issuer_name" +Type = "varchar" + +[[Migration.Operations.Fields.Annotations]] +Type = "max_length" +Value = 255 + +[[Migration.Operations.Fields.Annotations]] +Type = "not_null" + +[[Migration.Operations.Fields]] +Name = "common_name" +Type = "varchar" + +[[Migration.Operations.Fields.Annotations]] +Type = "max_length" +Value = 255 + +[[Migration.Operations.Fields.Annotations]] +Type = "not_null" + +[[Migration.Operations.Fields]] +Name = "not_before" +Type = "datetime" +Annotations = [] + +[[Migration.Operations.Fields]] +Name = "not_after" +Type = "datetime" +Annotations = [] + +[[Migration.Operations.Fields]] +Name = "serial_number" +Type = "varchar" + +[[Migration.Operations.Fields.Annotations]] +Type = "max_length" +Value = 255 + +[[Migration.Operations.Fields.Annotations]] +Type = "not_null" + +[[Migration.Operations]] +Type = "CreateField" +Model = "certificatetransparencyvaluename" + +[Migration.Operations.Field] +Name = "ct_result" +Type = "varbinary" + +[[Migration.Operations.Field.Annotations]] +Type = "foreign_key" + +[Migration.Operations.Field.Annotations.Value] +TableName = "certificatetransparencyresult" +ColumnName = "uuid" +OnDelete = "Cascade" +OnUpdate = "Cascade" + +[[Migration.Operations.Field.Annotations]] +Type = "not_null" + +[[Migration.Operations]] +Type = "CreateField" +Model = "certificatetransparencyresult" + +[Migration.Operations.Field] +Name = "attack" +Type = "varbinary" + +[[Migration.Operations.Field.Annotations]] +Type = "foreign_key" + +[Migration.Operations.Field.Annotations.Value] +TableName = "attack" +ColumnName = "uuid" +OnDelete = "Cascade" +OnUpdate = "Cascade" + +[[Migration.Operations.Field.Annotations]] +Type = "not_null" + +[[Migration.Operations]] +Type = "DeleteField" +Model = "workspace" +Name = "deletable" diff --git a/kraken/src/api/handler/attacks.rs b/kraken/src/api/handler/attacks.rs index 044344499..e57ec99c5 100644 --- a/kraken/src/api/handler/attacks.rs +++ b/kraken/src/api/handler/attacks.rs @@ -8,10 +8,11 @@ use chrono::{DateTime, NaiveDateTime, TimeZone, Utc}; use dehashed_rs::{DehashedError, ScheduledRequest, SearchResult}; use futures::StreamExt; use ipnet::IpNet; +use ipnetwork::IpNetwork; use log::{debug, error, warn}; -use rorm::fields::ForeignModelByField; -use rorm::transaction::Transaction; -use rorm::{and, insert, query, update, Database, Model}; +use rorm::db::transaction::Transaction; +use rorm::prelude::ForeignModelByField; +use rorm::{and, insert, query, update, Database, FieldAccess, Model}; use serde::{Deserialize, Serialize}; use tokio::sync::oneshot; use utoipa::{IntoParams, ToSchema}; @@ -26,9 +27,9 @@ use crate::models::{ Attack, AttackInsert, AttackType, DehashedQueryResultInsert, TcpPortScanResult, TcpPortScanResultInsert, Workspace, WorkspaceMember, }; -use crate::rpc::rpc_attacks; -use crate::rpc::rpc_attacks::shared::dns_record::Record; -use crate::rpc::rpc_attacks::CertificateTransparencyRequest; +use crate::rpc::rpc_definitions; +use crate::rpc::rpc_definitions::shared::dns_record::Record; +use crate::rpc::rpc_definitions::CertificateTransparencyRequest; /// The settings of a subdomain bruteforce request #[derive(Deserialize, ToSchema)] @@ -89,7 +90,7 @@ pub async fn bruteforce_subdomains( // start attack tokio::spawn(async move { - let req = rpc_attacks::BruteforceSubdomainRequest { + let req = rpc_definitions::BruteforceSubdomainRequest { attack_uuid: uuid.to_string(), domain: req.domain.clone(), wordlist_path: req.wordlist_path.clone(), @@ -185,7 +186,7 @@ pub async fn bruteforce_subdomains( let now = Utc::now(); if let Err(err) = update!(db.as_ref(), Attack) - .condition(Attack::F.uuid.equals(uuid.as_ref())) + .condition(Attack::F.uuid.equals(uuid)) .set(Attack::F.finished_at, Some(now.naive_utc())) .exec() .await @@ -263,15 +264,15 @@ where }) } -impl From<&PortOrRange> for rpc_attacks::PortOrRange { +impl From<&PortOrRange> for rpc_definitions::PortOrRange { fn from(value: &PortOrRange) -> Self { - rpc_attacks::PortOrRange { + rpc_definitions::PortOrRange { port_or_range: Some(match value { PortOrRange::Port(port) => { - rpc_attacks::port_or_range::PortOrRange::Single(*port as u32) + rpc_definitions::port_or_range::PortOrRange::Single(*port as u32) } PortOrRange::Range(range) => { - rpc_attacks::port_or_range::PortOrRange::Range(rpc_attacks::PortRange { + rpc_definitions::port_or_range::PortOrRange::Range(rpc_definitions::PortRange { start: *range.start() as u32, end: *range.end() as u32, }) @@ -330,7 +331,7 @@ pub async fn scan_tcp_ports( // start attack tokio::spawn(async move { - let req = rpc_attacks::TcpPortScanRequest { + let req = rpc_definitions::TcpPortScanRequest { attack_uuid: uuid.to_string(), targets: req.targets.iter().map(|addr| (*addr).into()).collect(), exclude: req.exclude.iter().map(|addr| addr.to_string()).collect(), @@ -360,11 +361,11 @@ pub async fn scan_tcp_ports( }; let address = match addr { - rpc_attacks::shared::address::Address::Ipv4(addr) => { + rpc_definitions::shared::address::Address::Ipv4(addr) => { IpAddr::V4(addr.into()) } - rpc_attacks::shared::address::Address::Ipv6(addr) => { + rpc_definitions::shared::address::Address::Ipv6(addr) => { IpAddr::V6(addr.into()) } }; @@ -374,7 +375,7 @@ pub async fn scan_tcp_ports( .single(&TcpPortScanResultInsert { uuid: Uuid::new_v4(), attack: ForeignModelByField::Key(uuid), - address: rorm::fields::Json(address), + address: IpNetwork::from(address), port: v.port as i32, }) .await @@ -435,7 +436,7 @@ pub async fn scan_tcp_ports( let now = Utc::now(); if let Err(err) = update!(db.as_ref(), Attack) - .condition(Attack::F.uuid.equals(uuid.as_ref())) + .condition(Attack::F.uuid.equals(uuid)) .set(Attack::F.finished_at, Some(now.naive_utc())) .exec() .await @@ -598,7 +599,7 @@ pub async fn query_certificate_transparency( let now = Utc::now(); if let Err(err) = update!(db.as_ref(), Attack) - .condition(Attack::F.uuid.equals(uuid.as_ref())) + .condition(Attack::F.uuid.equals(uuid)) .set(Attack::F.finished_at, Some(now.naive_utc())) .exec() .await @@ -710,7 +711,7 @@ pub async fn query_dehashed( address: x.address, phone: x.phone, vin: x.vin, - ip_address: rorm::fields::Json(x.ip_address), + ip_address: x.ip_address.map(|x| IpNetwork::from(x)), attack: ForeignModelByField::Key(attack_uuid), }) .collect(); @@ -784,7 +785,7 @@ pub(crate) async fn get_attack( Attack::F.started_by.display_name, ) ) - .condition(Attack::F.uuid.equals(req.uuid.as_ref())) + .condition(Attack::F.uuid.equals(req.uuid)) .optional() .await? .ok_or(ApiError::InvalidUuid)?; @@ -856,7 +857,7 @@ pub(crate) struct SimpleTcpPortScanResult { pub attack: Uuid, pub created_at: DateTime, #[schema(value_type = String)] - pub address: IpAddr, + pub address: IpNetwork, pub port: u16, } @@ -888,11 +889,11 @@ pub(crate) async fn get_tcp_port_scan_results( Err(ApiError::MissingPrivileges) } else { let (total,) = query!(&mut tx, (TcpPortScanResult::F.uuid.count(),)) - .condition(TcpPortScanResult::F.attack.equals(uuid.as_ref())) + .condition(TcpPortScanResult::F.attack.equals(uuid)) .one() .await?; let results = query!(&mut tx, TcpPortScanResult) - .condition(TcpPortScanResult::F.attack.equals(uuid.as_ref())) + .condition(TcpPortScanResult::F.attack.equals(uuid)) .order_asc(TcpPortScanResult::F.uuid) .limit(limit) .offset(offset) @@ -902,8 +903,8 @@ pub(crate) async fn get_tcp_port_scan_results( .map(|result| SimpleTcpPortScanResult { uuid: result.uuid, attack: *result.attack.key(), - created_at: Utc.from_utc_datetime(&result.created_at), - address: result.address.into_inner(), + created_at: result.created_at, + address: result.address, port: result.port as u16, }) .collect(); @@ -943,7 +944,7 @@ pub(crate) async fn delete_attack( let user = query_user(&mut tx, &session).await?; let attack = query!(&mut tx, Attack) - .condition(Attack::F.uuid.equals(req.uuid.as_ref())) + .condition(Attack::F.uuid.equals(req.uuid)) .optional() .await? .ok_or(ApiError::InvalidUuid)?; @@ -972,7 +973,7 @@ async fn has_access(tx: &mut Transaction, attack_uuid: Uuid, session: &Session) let uuid: Uuid = session.get("uuid")?.ok_or(ApiError::SessionCorrupt)?; let (workspace, owner) = query!(&mut *tx, (Workspace::F.uuid, Workspace::F.owner)) - .condition(Workspace::F.attacks.uuid.equals(attack_uuid.as_ref())) + .condition(Workspace::F.attacks.uuid.equals(attack_uuid)) .one() .await?; if *owner.key() == uuid { @@ -981,8 +982,8 @@ async fn has_access(tx: &mut Transaction, attack_uuid: Uuid, session: &Session) Ok(query!(&mut *tx, (WorkspaceMember::F.id,)) .condition(and!( - WorkspaceMember::F.workspace.equals(workspace.as_ref()), - WorkspaceMember::F.member.equals(uuid.as_ref()), + WorkspaceMember::F.workspace.equals(workspace), + WorkspaceMember::F.member.equals(uuid), )) .optional() .await? diff --git a/kraken/src/api/handler/auth.rs b/kraken/src/api/handler/auth.rs index cf7e14207..02440a7e7 100644 --- a/kraken/src/api/handler/auth.rs +++ b/kraken/src/api/handler/auth.rs @@ -5,8 +5,8 @@ use argon2::password_hash::Error; use argon2::{Argon2, PasswordHash, PasswordVerifier}; use chrono::Utc; use log::{debug, error}; -use rorm::fields::ForeignModelByField; -use rorm::{insert, query, update, Database, Model}; +use rorm::prelude::ForeignModelByField; +use rorm::{insert, query, update, Database, FieldAccess, Model}; use serde::Deserialize; use utoipa::ToSchema; use uuid::Uuid; @@ -84,8 +84,8 @@ pub(crate) async fn login( })?; update!(&mut tx, User) - .condition(User::F.uuid.equals(user.uuid.as_ref())) - .set(User::F.last_login, Some(Utc::now().naive_utc())) + .condition(User::F.uuid.equals(user.uuid)) + .set(User::F.last_login, Some(Utc::now())) .exec() .await?; @@ -157,7 +157,7 @@ pub(crate) async fn start_auth( session.remove("auth_state"); let keys = query!(db.as_ref(), UserKey) - .condition(UserKey::F.user.equals(uuid.as_ref())) + .condition(UserKey::F.user.equals(uuid)) .all() .await?; @@ -207,8 +207,8 @@ pub(crate) async fn finish_auth( webauthn.finish_passkey_authentication(&auth, &auth_state)?; update!(db.as_ref(), User) - .condition(User::F.uuid.equals(uuid.as_ref())) - .set(User::F.last_login, Utc::now().naive_utc()) + .condition(User::F.uuid.equals(uuid)) + .set(User::F.last_login, Some(Utc::now())) .exec() .await?; @@ -245,7 +245,7 @@ pub(crate) async fn start_register( let mut tx = db.start_transaction().await?; let mut user = query!(&mut tx, User) - .condition(User::F.uuid.equals(uuid.as_ref())) + .condition(User::F.uuid.equals(uuid)) .optional() .await? .ok_or(ApiError::SessionCorrupt)?; @@ -261,7 +261,7 @@ pub(crate) async fn start_register( session.remove("reg_state"); let excluded_keys: Vec = query!(&mut tx, UserKey) - .condition(UserKey::F.user.equals(uuid.as_ref())) + .condition(UserKey::F.user.equals(uuid)) .all() .await? .into_iter() @@ -327,7 +327,7 @@ pub(crate) async fn finish_register( .single(&UserKeyInsert { uuid: Uuid::new_v4(), user: ForeignModelByField::Key(uuid), - key: rorm::fields::Json(passkey), + key: rorm::fields::types::Json(passkey), name: req.name.clone(), }) .await?; diff --git a/kraken/src/api/handler/leeches.rs b/kraken/src/api/handler/leeches.rs index cd594b0e4..bea73533d 100644 --- a/kraken/src/api/handler/leeches.rs +++ b/kraken/src/api/handler/leeches.rs @@ -1,7 +1,7 @@ use actix_web::web::{Data, Json, Path}; use actix_web::{delete, get, post, put, HttpResponse}; use log::error; -use rorm::{insert, query, update, Database, Model}; +use rorm::{insert, query, update, Database, FieldAccess, Model}; use serde::{Deserialize, Serialize}; use utoipa::ToSchema; use uuid::Uuid; @@ -113,13 +113,13 @@ pub(crate) async fn delete_leech( let mut tx = db.start_transaction().await?; query!(&mut tx, (Leech::F.uuid,)) - .condition(Leech::F.uuid.equals(path.uuid.as_ref())) + .condition(Leech::F.uuid.equals(path.uuid)) .optional() .await? .ok_or(ApiError::InvalidUuid)?; rorm::delete!(&mut tx, Leech) - .condition(Leech::F.uuid.equals(path.uuid.as_ref())) + .condition(Leech::F.uuid.equals(path.uuid)) .await?; tx.commit().await?; @@ -162,7 +162,7 @@ pub(crate) async fn get_leech( db: Data, ) -> ApiResult> { let leech = query!(db.as_ref(), Leech) - .condition(Leech::F.uuid.equals(req.uuid.as_ref())) + .condition(Leech::F.uuid.equals(req.uuid)) .optional() .await? .ok_or(ApiError::InvalidUuid)?; @@ -248,7 +248,7 @@ pub(crate) async fn update_leech( let req = req.into_inner(); query!(&mut tx, (Leech::F.uuid,)) - .condition(Leech::F.uuid.equals(path.uuid.as_ref())) + .condition(Leech::F.uuid.equals(path.uuid)) .optional() .await? .ok_or(ApiError::InvalidUuid)?; diff --git a/kraken/src/api/handler/mod.rs b/kraken/src/api/handler/mod.rs index 2dba895c4..35e3286fb 100644 --- a/kraken/src/api/handler/mod.rs +++ b/kraken/src/api/handler/mod.rs @@ -4,8 +4,8 @@ use actix_toolbox::tb_middleware::{actix_session, Session}; use actix_web::body::BoxBody; use actix_web::HttpResponse; use log::{debug, error, info, trace, warn}; -use rorm::executor::Executor; -use rorm::{query, Model}; +use rorm::db::Executor; +use rorm::{query, FieldAccess, Model}; use serde::{Deserialize, Deserializer, Serialize}; use serde_repr::Serialize_repr; use thiserror::Error; @@ -35,7 +35,7 @@ mod workspaces; pub(crate) async fn query_user(db: impl Executor<'_>, session: &Session) -> ApiResult { let uuid: Uuid = session.get("uuid")?.ok_or(ApiError::SessionCorrupt)?; query!(db, User) - .condition(User::F.uuid.equals(uuid.as_ref())) + .condition(User::F.uuid.equals(uuid)) .optional() .await? .ok_or(ApiError::SessionCorrupt) diff --git a/kraken/src/api/handler/reporting.rs b/kraken/src/api/handler/reporting.rs index ea72e70e2..d20d7e632 100644 --- a/kraken/src/api/handler/reporting.rs +++ b/kraken/src/api/handler/reporting.rs @@ -1,11 +1,11 @@ use std::collections::HashMap; -use std::net::IpAddr; use actix_web::get; use actix_web::web::{Data, Json, Path}; use chrono::{DateTime, TimeZone, Utc}; use futures::StreamExt; -use rorm::{query, Database, Model}; +use ipnetwork::IpNetwork; +use rorm::{query, Database, FieldAccess, Model}; use serde::Serialize; use utoipa::ToSchema; use uuid::Uuid; @@ -55,7 +55,7 @@ pub(crate) struct ReportingUser { pub(crate) struct ReportingIpPort { /// Ip address (v4 or v6) #[schema(value_type = String, example = "10.13.37.1")] - pub(crate) ip: IpAddr, + pub(crate) ip: IpNetwork, /// Port number #[schema(example = 80)] @@ -86,7 +86,7 @@ pub(crate) async fn report_workspace_results( // Check workspace to exist let (_,) = query!(&mut tx, (Workspace::F.uuid,)) - .condition(Workspace::F.uuid.equals(uuid.as_ref())) + .condition(Workspace::F.uuid.equals(uuid)) .optional() .await? .ok_or(ApiError::InvalidUuid)?; @@ -101,7 +101,7 @@ pub(crate) async fn report_workspace_results( TcpPortScanResult::F.port ) ) - .condition(TcpPortScanResult::F.attack.workspace.equals(uuid.as_ref())) + .condition(TcpPortScanResult::F.attack.workspace.equals(uuid)) .stream(); while let Some(result) = stream.next().await { let (attack, address, port) = result?; @@ -109,7 +109,7 @@ pub(crate) async fn report_workspace_results( .entry(*attack.key()) .or_default() .push(ReportingIpPort { - ip: address.into_inner(), + ip: address, port: port as u16, }); } @@ -128,7 +128,7 @@ pub(crate) async fn report_workspace_results( Attack::F.started_by.display_name ) ) - .condition(Attack::F.workspace.equals(uuid.as_ref())) + .condition(Attack::F.workspace.equals(uuid)) .stream(); while let Some(result) = stream.next().await { let (attack, created_at, finished_at, uuid, username, display_name) = result?; diff --git a/kraken/src/api/handler/users.rs b/kraken/src/api/handler/users.rs index f4bc09860..27416b179 100644 --- a/kraken/src/api/handler/users.rs +++ b/kraken/src/api/handler/users.rs @@ -6,7 +6,7 @@ use argon2::{Argon2, PasswordHash, PasswordHasher, PasswordVerifier}; use chrono::{DateTime, Utc}; use log::error; use rand::thread_rng; -use rorm::{query, update, Database, Model}; +use rorm::{query, update, Database, FieldAccess, Model}; use serde::{Deserialize, Serialize}; use utoipa::{IntoParams, ToSchema}; use uuid::Uuid; @@ -100,7 +100,7 @@ pub(crate) async fn delete_user( db: Data, ) -> ApiResult { rorm::delete!(db.as_ref(), User) - .condition(User::F.uuid.equals(req.uuid.as_ref())) + .condition(User::F.uuid.equals(req.uuid)) .await?; Ok(HttpResponse::Ok().finish()) @@ -139,7 +139,7 @@ pub(crate) struct GetUserResponse { #[get("/users/{uuid}")] pub(crate) async fn get_user(req: Path, db: Data) -> ApiResult> { let user = query!(db.as_ref(), User) - .condition(User::F.uuid.equals(req.uuid.as_ref())) + .condition(User::F.uuid.equals(req.uuid)) .optional() .await? .ok_or(ApiError::InvalidUsername)?; @@ -149,10 +149,8 @@ pub(crate) async fn get_user(req: Path, db: Data) -> ApiResu username: user.username, display_name: user.display_name, admin: user.admin, - created_at: DateTime::from_naive_utc_and_offset(user.created_at, Utc), - last_login: user - .last_login - .map(|dt| DateTime::from_naive_utc_and_offset(dt, Utc)), + created_at: user.created_at, + last_login: user.last_login, })) } @@ -179,10 +177,8 @@ pub(crate) async fn get_all_users(db: Data) -> ApiResult) -> ApiResult) -> ApiResult ApiResult { let uuid: Uuid = session.get("uuid")?.ok_or(ApiError::SessionCorrupt)?; + let req = req.into_inner(); let mut tx = db.start_transaction().await?; @@ -337,10 +332,10 @@ pub(crate) async fn update_me( } update!(&mut tx, User) - .condition(User::F.uuid.equals(uuid.as_ref())) + .condition(User::F.uuid.equals(uuid)) .begin_dyn_set() - .set_if(User::F.username, req.username.as_ref()) - .set_if(User::F.display_name, req.display_name.as_ref()) + .set_if(User::F.username, req.username) + .set_if(User::F.display_name, req.display_name) .finish_dyn_set() .map_err(|_| ApiError::EmptyJson)? .await?; diff --git a/kraken/src/api/handler/workspaces.rs b/kraken/src/api/handler/workspaces.rs index d86623e6a..0bc422d41 100644 --- a/kraken/src/api/handler/workspaces.rs +++ b/kraken/src/api/handler/workspaces.rs @@ -3,9 +3,9 @@ use actix_web::web::{Data, Json, Path}; use actix_web::{delete, get, post, put, HttpResponse}; use chrono::{DateTime, TimeZone, Utc}; use log::debug; -use rorm::fields::ForeignModelByField; -use rorm::transaction::Transaction; -use rorm::{and, insert, query, update, Database, Model}; +use rorm::db::transaction::Transaction; +use rorm::fields::types::ForeignModelByField; +use rorm::{and, insert, query, update, Database, FieldAccess, Model}; use serde::{Deserialize, Serialize}; use utoipa::ToSchema; use uuid::Uuid; @@ -80,7 +80,7 @@ pub(crate) async fn delete_workspace( let executing_user = query_user(&mut tx, &session).await?; let workspace = query!(&mut tx, Workspace) - .condition(Workspace::F.uuid.equals(req.uuid.as_ref())) + .condition(Workspace::F.uuid.equals(req.uuid)) .optional() .await? .ok_or(ApiError::InvalidUuid)?; @@ -161,8 +161,8 @@ pub(crate) async fn get_workspace( let is_member = query!(&mut tx, (WorkspaceMember::F.id,)) .condition(and!( - WorkspaceMember::F.member.equals(user_uuid.as_ref()), - WorkspaceMember::F.workspace.equals(req.uuid.as_ref()) + WorkspaceMember::F.member.equals(user_uuid), + WorkspaceMember::F.workspace.equals(req.uuid) )) .optional() .await? @@ -170,8 +170,8 @@ pub(crate) async fn get_workspace( let is_owner = query!(&mut tx, (Workspace::F.uuid,)) .condition(and!( - Workspace::F.uuid.equals(req.uuid.as_ref()), - Workspace::F.owner.equals(user_uuid.as_ref()) + Workspace::F.uuid.equals(req.uuid), + Workspace::F.owner.equals(user_uuid) )) .optional() .await? @@ -211,7 +211,7 @@ pub(crate) async fn get_all_workspaces( let owner = query_user(&mut tx, &session).await?; let workspaces = query!(&mut tx, Workspace) - .condition(Workspace::F.owner.equals(owner.uuid.as_ref())) + .condition(Workspace::F.owner.equals(owner.uuid)) .all() .await?; @@ -229,7 +229,7 @@ pub(crate) async fn get_all_workspaces( username: owner.username.clone(), display_name: owner.display_name.clone(), }, - created_at: w.created_at.and_utc(), + created_at: w.created_at, }) .collect(), })) @@ -281,7 +281,7 @@ pub(crate) async fn update_workspace( let mut tx = db.start_transaction().await?; let w = query!(&mut tx, Workspace) - .condition(Workspace::F.uuid.equals(path.uuid.as_ref())) + .condition(Workspace::F.uuid.equals(path.uuid)) .optional() .await? .ok_or(ApiError::InvalidUuid)?; @@ -297,7 +297,7 @@ pub(crate) async fn update_workspace( } update!(&mut tx, Workspace) - .condition(Workspace::F.uuid.equals(w.uuid.as_ref())) + .condition(Workspace::F.uuid.equals(w.uuid)) .begin_dyn_set() .set_if(Workspace::F.name, req.name) .set_if(Workspace::F.description, req.description) @@ -385,7 +385,7 @@ pub(crate) async fn get_all_workspaces_admin( username, display_name, }, - created_at: created_at.and_utc(), + created_at, } }, ) @@ -396,13 +396,13 @@ pub(crate) async fn get_all_workspaces_admin( /// Get a [`FullWorkspace`] by its uuid without permission checks async fn get_workspace_unchecked(uuid: Uuid, tx: &mut Transaction) -> ApiResult { let workspace = query!(&mut *tx, Workspace) - .condition(Workspace::F.uuid.equals(uuid.as_ref())) + .condition(Workspace::F.uuid.equals(uuid)) .optional() .await? .ok_or(ApiError::InvalidUuid)?; let owner = query!(&mut *tx, User) - .condition(User::F.uuid.equals(workspace.owner.key().as_ref())) + .condition(User::F.uuid.equals(*workspace.owner.key())) .one() .await?; @@ -418,7 +418,7 @@ async fn get_workspace_unchecked(uuid: Uuid, tx: &mut Transaction) -> ApiResult< Attack::F.started_by.display_name, ) ) - .condition(Attack::F.workspace.equals(uuid.as_ref())) + .condition(Attack::F.workspace.equals(uuid)) .all() .await? .into_iter() @@ -448,7 +448,7 @@ async fn get_workspace_unchecked(uuid: Uuid, tx: &mut Transaction) -> ApiResult< WorkspaceMember::F.member.display_name ) ) - .condition(WorkspaceMember::F.workspace.equals(uuid.as_ref())) + .condition(WorkspaceMember::F.workspace.equals(uuid)) .all() .await? .into_iter() @@ -470,6 +470,6 @@ async fn get_workspace_unchecked(uuid: Uuid, tx: &mut Transaction) -> ApiResult< }, attacks, members, - created_at: workspace.created_at.and_utc(), + created_at: workspace.created_at, }) } diff --git a/kraken/src/api/middleware/admin_required.rs b/kraken/src/api/middleware/admin_required.rs index a75afa7a6..c9f572533 100644 --- a/kraken/src/api/middleware/admin_required.rs +++ b/kraken/src/api/middleware/admin_required.rs @@ -4,7 +4,7 @@ use actix_toolbox::tb_middleware::actix_session::SessionExt; use actix_web::dev::{forward_ready, Service, ServiceRequest, ServiceResponse, Transform}; use actix_web::web::Data; use futures::future::LocalBoxFuture; -use rorm::{query, Database, Model}; +use rorm::{query, Database, FieldAccess, Model}; use uuid::Uuid; use crate::api::handler::ApiError; @@ -75,7 +75,7 @@ where .ok_or(ApiError::SessionCorrupt)?; let second_factor_required = query!(&db, (UserKey::F.uuid,)) - .condition(UserKey::F.user.equals(uuid.as_ref())) + .condition(UserKey::F.user.equals(uuid)) .optional() .await .map_err(ApiError::DatabaseError)?; @@ -85,7 +85,7 @@ where } let (is_admin,) = query!(&db, (User::F.admin,)) - .condition(User::F.uuid.equals(uuid.as_ref())) + .condition(User::F.uuid.equals(uuid)) .optional() .await .map_err(ApiError::DatabaseError)? diff --git a/kraken/src/api/middleware/authentication_required.rs b/kraken/src/api/middleware/authentication_required.rs index dd6e9aaa7..1617c55b9 100644 --- a/kraken/src/api/middleware/authentication_required.rs +++ b/kraken/src/api/middleware/authentication_required.rs @@ -4,7 +4,7 @@ use actix_toolbox::tb_middleware::actix_session::SessionExt; use actix_web::dev::{forward_ready, Service, ServiceRequest, ServiceResponse, Transform}; use actix_web::web::Data; use futures::future::LocalBoxFuture; -use rorm::{query, Database, Model}; +use rorm::{query, Database, FieldAccess, Model}; use uuid::Uuid; use crate::api::handler::ApiError; @@ -75,7 +75,7 @@ where .ok_or(ApiError::SessionCorrupt)?; let second_factor_required = query!(&db, (UserKey::F.uuid,)) - .condition(UserKey::F.user.equals(uuid.as_ref())) + .condition(UserKey::F.user.equals(uuid)) .optional() .await .map_err(ApiError::DatabaseError)?; diff --git a/kraken/src/chan/rpc_manager.rs b/kraken/src/chan/rpc_manager.rs index c396cfbec..870e6ce1d 100644 --- a/kraken/src/chan/rpc_manager.rs +++ b/kraken/src/chan/rpc_manager.rs @@ -4,7 +4,7 @@ use std::time::Duration; use actix_web::web::Data; use log::{debug, warn}; -use rorm::{query, Database, Model}; +use rorm::{query, Database, FieldAccess, Model}; use tokio::sync::mpsc::Sender; use tokio::sync::{mpsc, RwLock}; use tokio::task::JoinHandle; @@ -13,7 +13,7 @@ use tonic::transport::{Channel, Endpoint}; use uuid::Uuid; use crate::models::Leech; -use crate::rpc::rpc_attacks::req_attack_service_client::ReqAttackServiceClient; +use crate::rpc::rpc_definitions::req_attack_service_client::ReqAttackServiceClient; pub(crate) type RpcManagerChannel = Sender; pub(crate) type RpcClients = Data>>>; @@ -120,7 +120,7 @@ pub async fn start_rpc_manager(db: Database) -> Result<(RpcManagerChannel, RpcCl } RpcManagerEvent::Created(uuid) => { if let Ok(Some(leech)) = query!(&db, Leech) - .condition(Leech::F.uuid.equals(uuid.as_ref())) + .condition(Leech::F.uuid.equals(uuid)) .optional() .await { @@ -136,7 +136,7 @@ pub async fn start_rpc_manager(db: Database) -> Result<(RpcManagerChannel, RpcCl join_handle.abort(); if let Ok(Some(leech)) = query!(&db, Leech) - .condition(Leech::F.uuid.equals(uuid.as_ref())) + .condition(Leech::F.uuid.equals(uuid)) .optional() .await { diff --git a/kraken/src/main.rs b/kraken/src/main.rs index 73a7cd8d3..e8bb414ec 100644 --- a/kraken/src/main.rs +++ b/kraken/src/main.rs @@ -29,12 +29,15 @@ use base64::prelude::BASE64_STANDARD; use base64::Engine; use clap::{Parser, Subcommand}; use rand::thread_rng; -use rorm::{cli, insert, query, Database, DatabaseConfiguration, DatabaseDriver, Model}; +use rorm::{ + cli, insert, query, Database, DatabaseConfiguration, DatabaseDriver, FieldAccess, Model, +}; use webauthn_rs::prelude::Uuid; use crate::api::server; use crate::config::Config; use crate::models::{User, UserInsert}; +use crate::rpc::server::start_rpc_server; mod api; pub mod chan; @@ -116,6 +119,8 @@ async fn main() -> Result<(), String> { let dehashed_scheduler = chan::start_dehashed_manager(settings_manager_chan.clone()).await?; + start_rpc_server(&config, db.clone())?; + server::start_server( db, &config, diff --git a/kraken/src/models/attack.rs b/kraken/src/models/attack.rs index 86635dce0..a24f4c2ee 100644 --- a/kraken/src/models/attack.rs +++ b/kraken/src/models/attack.rs @@ -1,10 +1,8 @@ //! This module holds all the information regarding attacks -use std::net::IpAddr; - use chrono::{DateTime, Utc}; -use rorm::fields::{ForeignModel, Json}; -use rorm::{DbEnum, Model, Patch}; +use ipnetwork::IpNetwork; +use rorm::prelude::*; use serde::{Deserialize, Serialize}; use utoipa::ToSchema; use uuid::Uuid; @@ -78,10 +76,10 @@ pub struct TcpPortScanResult { /// The point in time, this result was produced #[rorm(auto_create_time)] - pub created_at: chrono::NaiveDateTime, + pub created_at: DateTime, /// The ip address a port was found on - pub address: Json, + pub address: IpNetwork, /// The found port /// @@ -94,7 +92,7 @@ pub struct TcpPortScanResult { pub(crate) struct TcpPortScanResultInsert { pub(crate) uuid: Uuid, pub(crate) attack: ForeignModel, - pub(crate) address: Json, + pub(crate) address: IpNetwork, pub(crate) port: i32, } @@ -129,7 +127,7 @@ pub struct DehashedQueryResult { pub hashed_password: Option, /// An ip address, may be [None] if the result didn't include this field #[rorm(max_length = 255)] - pub ip_address: Json>, + pub ip_address: Option, /// A name, may be [None] if the result didn't include this field #[rorm(max_length = 255)] pub name: Option, @@ -157,10 +155,79 @@ pub(crate) struct DehashedQueryResultInsert { pub(crate) username: Option, pub(crate) password: Option, pub(crate) hashed_password: Option, - pub(crate) ip_address: Json>, + pub(crate) ip_address: Option, pub(crate) name: Option, pub(crate) vin: Option, pub(crate) address: Option, pub(crate) phone: Option, pub(crate) database_name: Option, } + +/// A value name in a [AttackType::QueryCertificateTransparency] result +#[derive(Model)] +pub struct CertificateTransparencyValueName { + /// The primary key + #[rorm(primary_key)] + pub uuid: Uuid, + + /// a single value + #[rorm(max_length = 255)] + pub value_name: String, + + /// The result this value is originating from + #[rorm(on_update = "Cascade", on_delete = "Cascade")] + pub ct_result: ForeignModel, +} + +#[derive(Patch)] +#[rorm(model = "CertificateTransparencyValueName")] +pub(crate) struct CertificateTransparencyValueNameInsert { + pub(crate) uuid: Uuid, + pub(crate) value_name: String, + pub(crate) ct_result: ForeignModel, +} + +/// Representation of a [AttackType::QueryCertificateTransparency] result +#[derive(Model)] +pub struct CertificateTransparencyResult { + /// The primary key + #[rorm(primary_key)] + pub uuid: Uuid, + + /// The attack which produced this result + #[rorm(on_delete = "Cascade", on_update = "Cascade")] + pub attack: ForeignModel, + + /// The point in time, this result was produced + #[rorm(auto_create_time)] + pub created_at: DateTime, + + /// The name of the issuer + #[rorm(max_length = 255)] + pub issuer_name: String, + /// The common name of the certificate + #[rorm(max_length = 255)] + pub common_name: String, + /// The values of the certificate + pub value_names: BackRef, + /// The start date of the certificate + pub not_before: Option>, + /// The end date of the certificate + pub not_after: Option>, + /// The serial number of the certificate + #[rorm(max_length = 255)] + pub serial_number: String, +} + +#[derive(Patch)] +#[rorm(model = "CertificateTransparencyResult")] +pub(crate) struct CertificateTransparencyResultInsert { + pub(crate) uuid: Uuid, + pub(crate) attack: ForeignModel, + pub(crate) created_at: DateTime, + pub(crate) issuer_name: String, + pub(crate) common_name: String, + pub(crate) not_before: Option>, + pub(crate) not_after: Option>, + pub(crate) serial_number: String, +} diff --git a/kraken/src/models/leech.rs b/kraken/src/models/leech.rs index 4096619d2..8665961ef 100644 --- a/kraken/src/models/leech.rs +++ b/kraken/src/models/leech.rs @@ -1,4 +1,4 @@ -use rorm::{Model, Patch}; +use rorm::prelude::*; use uuid::Uuid; /// The data collectors of kraken diff --git a/kraken/src/models/settings.rs b/kraken/src/models/settings.rs index efa3becc5..d88b8053c 100644 --- a/kraken/src/models/settings.rs +++ b/kraken/src/models/settings.rs @@ -1,5 +1,5 @@ use chrono::{DateTime, Utc}; -use rorm::{Model, Patch}; +use rorm::prelude::*; use uuid::Uuid; /// The settings of kraken diff --git a/kraken/src/models/user.rs b/kraken/src/models/user.rs index f0ce59696..7ef9fc32a 100644 --- a/kraken/src/models/user.rs +++ b/kraken/src/models/user.rs @@ -1,5 +1,6 @@ -use rorm::fields::{BackRef, ForeignModel, Json}; -use rorm::{field, Model, Patch}; +use chrono::{DateTime, Utc}; +use rorm::fields::types::Json; +use rorm::prelude::*; use uuid::Uuid; use webauthn_rs::prelude::Passkey; @@ -26,11 +27,11 @@ pub struct User { pub admin: bool, /// Last time the user has logged in - pub last_login: Option, + pub last_login: Option>, /// Creation time of the user #[rorm(auto_create_time)] - pub created_at: chrono::NaiveDateTime, + pub created_at: DateTime, /// Backreference to the security keys of a user pub user_keys: BackRef, @@ -44,7 +45,7 @@ pub(crate) struct UserInsert { pub(crate) display_name: String, pub(crate) password_hash: String, pub(crate) admin: bool, - pub(crate) last_login: Option, + pub(crate) last_login: Option>, } /// A security key (yubikey, e.g.) of a user diff --git a/kraken/src/models/workspace.rs b/kraken/src/models/workspace.rs index 6c9112253..038d9eb76 100644 --- a/kraken/src/models/workspace.rs +++ b/kraken/src/models/workspace.rs @@ -2,8 +2,8 @@ //! This module holds all database related definitions of workspace related structs //! -use rorm::fields::{BackRef, ForeignModel}; -use rorm::{field, Model, Patch}; +use chrono::{DateTime, Utc}; +use rorm::prelude::*; use uuid::Uuid; use crate::models::{Attack, User}; @@ -27,7 +27,7 @@ pub struct WorkspaceMember { /// The point in time the member was granted access to the workspace #[rorm(auto_create_time)] - pub created_at: chrono::NaiveDateTime, + pub created_at: DateTime, } #[derive(Patch)] @@ -60,7 +60,7 @@ pub struct Workspace { /// Timestamp when the workspace was created #[rorm(auto_create_time)] - pub created_at: chrono::NaiveDateTime, + pub created_at: DateTime, /// The workspace's members pub members: BackRef, diff --git a/kraken/src/modules/user/create.rs b/kraken/src/modules/user/create.rs index 5ad20477c..1a1f89789 100644 --- a/kraken/src/modules/user/create.rs +++ b/kraken/src/modules/user/create.rs @@ -5,7 +5,7 @@ use std::fmt::{Display, Formatter}; use argon2::password_hash::SaltString; use argon2::{Argon2, PasswordHasher}; use rand::thread_rng; -use rorm::transaction::Transaction; +use rorm::db::transaction::Transaction; use rorm::{insert, query, Database, Model}; use webauthn_rs::prelude::Uuid; diff --git a/kraken/src/rpc/definitions.rs b/kraken/src/rpc/definitions.rs new file mode 100644 index 000000000..0d640d311 --- /dev/null +++ b/kraken/src/rpc/definitions.rs @@ -0,0 +1,52 @@ +pub mod rpc_definitions { + use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; + + pub mod shared { + tonic::include_proto!("attacks.shared"); + } + + tonic::include_proto!("attacks"); + + impl From for Ipv4Addr { + fn from(value: shared::Ipv4) -> Self { + Ipv4Addr::from(value.address.to_le_bytes()) + } + } + + impl From for shared::Ipv4 { + fn from(value: Ipv4Addr) -> Self { + shared::Ipv4 { + address: i32::from_le_bytes(value.octets()), + } + } + } + + impl From for Ipv6Addr { + fn from(value: shared::Ipv6) -> Self { + let [a, b, c, d, e, f, g, h] = value.part0.to_le_bytes(); + let [i, j, k, l, m, n, o, p] = value.part1.to_le_bytes(); + Ipv6Addr::from([a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p]) + } + } + + impl From for shared::Ipv6 { + fn from(value: Ipv6Addr) -> Self { + let [a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p] = value.octets(); + shared::Ipv6 { + part0: i64::from_le_bytes([a, b, c, d, e, f, g, h]), + part1: i64::from_le_bytes([i, j, k, l, m, n, o, p]), + } + } + } + + impl From for shared::Address { + fn from(value: IpAddr) -> Self { + Self { + address: Some(match value { + IpAddr::V4(addr) => shared::address::Address::Ipv4(addr.into()), + IpAddr::V6(addr) => shared::address::Address::Ipv6(addr.into()), + }), + } + } + } +} diff --git a/kraken/src/rpc/mod.rs b/kraken/src/rpc/mod.rs index 82a3f236c..1e7962ef7 100644 --- a/kraken/src/rpc/mod.rs +++ b/kraken/src/rpc/mod.rs @@ -1,52 +1,11 @@ -pub mod rpc_attacks { - use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; +//! This module holds all rpc related definitions. +//! +//! In the default configuration, kraken has a rpc server and a client per leech running. +//! The leech has a server running. +//! If you want to use the leech as cli utility and push results to kraken, it will start a +//! rpc client and connect to the rpc server of kraken - pub mod shared { - tonic::include_proto!("attacks.shared"); - } +pub use definitions::*; - tonic::include_proto!("attacks"); - - impl From for Ipv4Addr { - fn from(value: shared::Ipv4) -> Self { - Ipv4Addr::from(value.address.to_le_bytes()) - } - } - - impl From for shared::Ipv4 { - fn from(value: Ipv4Addr) -> Self { - shared::Ipv4 { - address: i32::from_le_bytes(value.octets()), - } - } - } - - impl From for Ipv6Addr { - fn from(value: shared::Ipv6) -> Self { - let [a, b, c, d, e, f, g, h] = value.part0.to_le_bytes(); - let [i, j, k, l, m, n, o, p] = value.part1.to_le_bytes(); - Ipv6Addr::from([a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p]) - } - } - - impl From for shared::Ipv6 { - fn from(value: Ipv6Addr) -> Self { - let [a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p] = value.octets(); - shared::Ipv6 { - part0: i64::from_le_bytes([a, b, c, d, e, f, g, h]), - part1: i64::from_le_bytes([i, j, k, l, m, n, o, p]), - } - } - } - - impl From for shared::Address { - fn from(value: IpAddr) -> Self { - Self { - address: Some(match value { - IpAddr::V4(addr) => shared::address::Address::Ipv4(addr.into()), - IpAddr::V6(addr) => shared::address::Address::Ipv6(addr.into()), - }), - } - } - } -} +mod definitions; +pub mod server; diff --git a/kraken/src/rpc/server.rs b/kraken/src/rpc/server.rs new file mode 100644 index 000000000..3d66f0f0e --- /dev/null +++ b/kraken/src/rpc/server.rs @@ -0,0 +1,150 @@ +use std::net::SocketAddr; + +use chrono::{DateTime, NaiveDateTime, Utc}; +use log::{error, info}; +use rorm::prelude::ForeignModelByField; +use rorm::{insert, query, Database, FieldAccess, Model}; +use tonic::transport::Server; +use tonic::{Code, Request, Response, Status, Streaming}; +use uuid::Uuid; + +use crate::config::Config; +use crate::models::{ + AttackInsert, AttackType, CertificateTransparencyResultInsert, + CertificateTransparencyValueNameInsert, User, Workspace, +}; +use crate::rpc::definitions::rpc_definitions::attack_results_service_server::AttackResultsService; +use crate::rpc::rpc_definitions::attack_results_service_server::AttackResultsServiceServer; +use crate::rpc::rpc_definitions::{ + CertificateTransparencyResult, ResultResponse, SubdomainEnumerationResult, +}; + +/// Helper type to implement result handler to +pub struct Results { + db: Database, +} + +#[tonic::async_trait] +impl AttackResultsService for Results { + async fn certificate_transparency( + &self, + request: Request, + ) -> Result, Status> { + let req = request.into_inner(); + + let workspace_uuid = Uuid::try_parse( + &req.attack_info + .ok_or(Status::new(Code::Unknown, ""))? + .workspace_uuid, + ) + .unwrap(); + + let mut tx = self.db.start_transaction().await.unwrap(); + + // TODO: Don't query a random user + let user_uuid = query!(&mut tx, (User::F.uuid,)) + .optional() + .await + .unwrap() + .unwrap() + .0; + + // TODO: User authentication + query!(&mut tx, (Workspace::F.uuid,)) + .condition(Workspace::F.uuid.equals(workspace_uuid)) + .optional() + .await + .unwrap(); + + let attack_uuid = insert!(&mut tx, AttackInsert) + .return_primary_key() + .single(&AttackInsert { + uuid: Uuid::new_v4(), + attack_type: AttackType::QueryCertificateTransparency, + started_by: ForeignModelByField::Key(user_uuid), + workspace: ForeignModelByField::Key(workspace_uuid), + finished_at: Some(Utc::now().naive_utc()), + }) + .await + .unwrap(); + + for cert_entry in req.entries { + let entry_uuid = insert!(&mut tx, CertificateTransparencyResultInsert) + .return_primary_key() + .single(&CertificateTransparencyResultInsert { + uuid: Uuid::new_v4(), + attack: ForeignModelByField::Key(attack_uuid), + created_at: Utc::now(), + issuer_name: cert_entry.issuer_name, + common_name: cert_entry.common_name, + not_before: cert_entry.not_before.map(|ts| { + DateTime::from_naive_utc_and_offset( + NaiveDateTime::from_timestamp_opt(ts.seconds, ts.nanos as u32).unwrap(), + Utc, + ) + }), + not_after: cert_entry.not_after.map(|ts| { + DateTime::from_naive_utc_and_offset( + NaiveDateTime::from_timestamp_opt(ts.seconds, ts.nanos as u32).unwrap(), + Utc, + ) + }), + serial_number: cert_entry.serial_number, + }) + .await + .unwrap(); + + insert!(&mut tx, CertificateTransparencyValueNameInsert) + .bulk( + &cert_entry + .value_names + .into_iter() + .map(|x| CertificateTransparencyValueNameInsert { + uuid: Uuid::new_v4(), + value_name: x, + ct_result: ForeignModelByField::Key(entry_uuid), + }) + .collect::>(), + ) + .await + .unwrap(); + } + + tx.commit().await.unwrap(); + + Ok(Response::new(ResultResponse { + uuid: Uuid::new_v4().to_string(), + })) + } + + async fn subdomain_enumeration( + &self, + _request: Request>, + ) -> Result, Status> { + Ok(Response::new(ResultResponse { + uuid: Uuid::new_v4().to_string(), + })) + } +} + +/// Starts the gRPC server +/// +/// **Parameter**: +/// - `config`: Reference to [Config] +pub fn start_rpc_server(config: &Config, db: Database) -> Result<(), String> { + let listen_address = config.server.rpc_listen_address.parse().unwrap(); + let listen_port = config.server.rpc_listen_port; + + tokio::spawn(async move { + info!("Starting gRPC server"); + if let Err(err) = Server::builder() + .add_service(AttackResultsServiceServer::new(Results { db })) + .serve(SocketAddr::new(listen_address, listen_port)) + .await + { + // TODO: add loop to continuously restart the gRPC server + error!("Error running gRPC server: {err}"); + } + }); + Ok(()) +} diff --git a/leech/Cargo.toml b/leech/Cargo.toml index 7b21d2d25..256997c6a 100644 --- a/leech/Cargo.toml +++ b/leech/Cargo.toml @@ -60,7 +60,7 @@ rand = { version = "~0.8" } thiserror = { version = "~1" } # ORM -rorm = { version = "~0.6", features = ["tokio", "rustls", "cli", "uuid"] } +rorm = { version = "~0.6", default-features = false, features = ["tokio", "rustls", "cli", "uuid", "postgres-only", "chrono"] } # Needed because of modules diff --git a/leech/src/config.rs b/leech/src/config.rs index 2c822a5eb..e9777d9c5 100644 --- a/leech/src/config.rs +++ b/leech/src/config.rs @@ -1,10 +1,11 @@ //! The configuration definitions of a leech -use std::fmt::{Display, Formatter}; use std::path::Path; use std::{fs, io}; use serde::{Deserialize, Serialize}; +use thiserror::Error; +use url::Url; use crate::logging::LoggingConfig; @@ -18,6 +19,14 @@ pub struct ServerConfig { pub listen_port: u16, } +/// The configuration of the connection to kraken +#[derive(Deserialize, Serialize)] +#[serde(rename_all = "PascalCase")] +pub struct KrakenConfig { + /// The url to reach kraken's grpc server + pub kraken_uri: Url, +} + /// The configuration of the dehashed API #[derive(Deserialize, Serialize)] #[serde(rename_all = "PascalCase")] @@ -60,47 +69,25 @@ pub struct Config { pub logging: LoggingConfig, /// Dehashed configuration pub dehashed: Option, + /// The configuration for all kraken related stuff + pub kraken: KrakenConfig, } -/// Errors that can occur while +/// Errors that can occur while retrieving the config file +#[derive(Error, Debug)] pub enum GetConfigError { /// No file exists at the specified path + #[error("The config file does not exist at the specified path")] PathDoesNotExist, /// A directory exists at the specified path + #[error("The config file is a directory")] PathIsDirectory, /// An io error occurred. - IO(io::Error), + #[error("io error while reading the config file: {0}")] + IO(#[from] io::Error), /// Invalid toml format found within the file - InvalidToml(toml::de::Error), -} - -impl Display for GetConfigError { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - match self { - GetConfigError::PathDoesNotExist => { - write!(f, "The config file does not exist at the specified path") - } - GetConfigError::PathIsDirectory => { - write!(f, "The config file is a directory") - } - GetConfigError::IO(err) => write!(f, "io error while reading the config file: {err}"), - GetConfigError::InvalidToml(err) => { - write!(f, "The config file contains invalid TOML: {err}") - } - } - } -} - -impl From for GetConfigError { - fn from(value: io::Error) -> Self { - Self::IO(value) - } -} - -impl From for GetConfigError { - fn from(value: toml::de::Error) -> Self { - Self::InvalidToml(value) - } + #[error("The config file contains invalid TOML: {0}")] + InvalidToml(#[from] toml::de::Error), } impl From for String { diff --git a/leech/src/main.rs b/leech/src/main.rs index e80966d3f..126f4be8f 100644 --- a/leech/src/main.rs +++ b/leech/src/main.rs @@ -20,15 +20,19 @@ use std::path::PathBuf; use std::str::FromStr; use std::time::Duration; +use chrono::{Datelike, Timelike}; use clap::{ArgAction, Parser, Subcommand, ValueEnum}; use dehashed_rs::SearchType; use ipnet::IpNet; use itertools::Itertools; -use log::{error, info}; +use log::{error, info, warn}; +use prost_types::Timestamp; use rorm::cli; use tokio::sync::mpsc; use tokio::task; +use tonic::transport::Endpoint; use trust_dns_resolver::Name; +use uuid::Uuid; use crate::config::get_config; use crate::modules::bruteforce_subdomains::{ @@ -38,6 +42,9 @@ use crate::modules::certificate_transparency::{query_ct_api, CertificateTranspar use crate::modules::dehashed; use crate::modules::port_scanner::icmp_scan::{start_icmp_scan, IcmpScanSettings}; use crate::modules::port_scanner::tcp_con::{start_tcp_con_port_scan, TcpPortScannerSettings}; +use crate::rpc::rpc_attacks::attack_results_service_client::AttackResultsServiceClient; +use crate::rpc::rpc_attacks::shared::CertEntry; +use crate::rpc::rpc_attacks::{CertificateTransparencyResult, MetaAttackInfo}; use crate::rpc::start_rpc_server; pub mod config; @@ -153,6 +160,10 @@ pub enum Command { #[clap(short = 'v', global = true, action = ArgAction::Count)] verbosity: u8, + /// Push the results to a workspace in kraken + #[clap(long)] + push: Option, + /// the subcommand to execute #[clap(subcommand)] command: RunCommand, @@ -183,32 +194,17 @@ async fn main() -> Result<(), String> { let cli = Cli::parse(); match cli.commands { - Command::Migrate { migration_dir } => { - let config = get_config(&cli.config_path)?; - cli::migrate::run_migrate_custom( - cli::config::DatabaseConfig { - last_migration_table_name: None, - driver: cli::config::DatabaseDriver::Postgres { - host: config.database.host, - port: config.database.port, - name: config.database.name, - user: config.database.user, - password: config.database.password, - }, - }, - migration_dir, - false, - None, - ) - .await - .map_err(|e| e.to_string())? - } + Command::Migrate { migration_dir } => migrate(&cli.config_path, migration_dir).await?, Command::Server => { let config = get_config(&cli.config_path)?; logging::setup_logging(&config.logging)?; start_rpc_server(&config).await?; } - Command::Execute { command, verbosity } => { + Command::Execute { + command, + verbosity, + push, + } => { if env::var("RUST_LOG").is_err() { match verbosity { 0 => env::set_var("RUST_LOG", "leech=info"), @@ -218,186 +214,280 @@ async fn main() -> Result<(), String> { } env_logger::init(); - match command { - RunCommand::BruteforceSubdomains { - target, - wordlist_path, - concurrent_limit, - } => { - let (tx, mut rx) = mpsc::channel(128); - - task::spawn(async move { - while let Some(res) = rx.recv().await { - match res { - BruteforceSubdomainResult::A { source, target } => { - info!("Found a record for {source}: {target}"); - } - BruteforceSubdomainResult::Aaaa { source, target } => { - info!("Found aaaa record for {source}: {target}"); - } - BruteforceSubdomainResult::Cname { source, target } => { - info!("Found cname record for {source}: {target}"); - } - }; + if let Some(workspace) = push { + let config = get_config(&cli.config_path).map_err(|e| { + format!("Couldn't retrieve necessary config for pushing to kraken: {e}") + })?; + + match command { + RunCommand::CertificateTransparency { + target, + include_expired, + max_retries, + retry_interval, + } => { + let ct = CertificateTransparencySettings { + target, + include_expired, + max_retries, + retry_interval: Duration::from_millis(retry_interval as u64), + }; + + let entries = query_ct_api(ct).await?; + + for x in entries + .iter() + .flat_map(|e| { + let mut name_value = e.name_value.clone(); + + name_value.push(e.common_name.clone()); + name_value + }) + .sorted() + .dedup() + { + info!("{x}"); } - }); - let settings = BruteforceSubdomainsSettings { - domain: target.to_string(), - wordlist_path, - concurrent_limit: u32::from(concurrent_limit), - }; - if let Err(err) = bruteforce_subdomains(settings, tx).await { - error!("{err}"); + info!("Sending results to kraken"); + + let endpoint = + Endpoint::from_str(&config.kraken.kraken_uri.to_string()).unwrap(); + let chan = endpoint.connect().await.unwrap(); + + let mut client = AttackResultsServiceClient::new(chan); + client + .certificate_transparency(CertificateTransparencyResult { + entries: entries + .into_iter() + .map(|x| CertEntry { + value_names: x.name_value, + common_name: x.common_name, + serial_number: x.serial_number, + not_after: x.not_after.map(|ts| { + Timestamp::date_time_nanos( + ts.year() as i64, + ts.month() as u8, + ts.day() as u8, + ts.hour() as u8, + ts.minute() as u8, + ts.second() as u8, + ts.nanosecond(), + ) + .unwrap() + }), + not_before: x.not_before.map(|ts| { + Timestamp::date_time_nanos( + ts.year() as i64, + ts.month() as u8, + ts.day() as u8, + ts.hour() as u8, + ts.minute() as u8, + ts.second() as u8, + ts.nanosecond(), + ) + .unwrap() + }), + issuer_name: x.issuer_name, + }) + .collect(), + attack_info: Some(MetaAttackInfo { + workspace_uuid: workspace.to_string(), + }), + }) + .await + .unwrap(); + + info!("Finished sending results to kraken") } + _ => todo!("Not supported right now for pushing to kraken"), } - RunCommand::CertificateTransparency { - target, - include_expired, - max_retries, - retry_interval, - } => { - let ct = CertificateTransparencySettings { + } else { + match command { + RunCommand::BruteforceSubdomains { + target, + wordlist_path, + concurrent_limit, + } => { + let (tx, mut rx) = mpsc::channel(128); + + task::spawn(async move { + while let Some(res) = rx.recv().await { + match res { + BruteforceSubdomainResult::A { source, target } => { + info!("Found a record for {source}: {target}"); + } + BruteforceSubdomainResult::Aaaa { source, target } => { + info!("Found aaaa record for {source}: {target}"); + } + BruteforceSubdomainResult::Cname { source, target } => { + info!("Found cname record for {source}: {target}"); + } + }; + } + }); + + let settings = BruteforceSubdomainsSettings { + domain: target.to_string(), + wordlist_path, + concurrent_limit: u32::from(concurrent_limit), + }; + if let Err(err) = bruteforce_subdomains(settings, tx).await { + error!("{err}"); + } + } + RunCommand::CertificateTransparency { target, include_expired, max_retries, - retry_interval: Duration::from_millis(retry_interval as u64), - }; - - let entries = query_ct_api(ct).await?; - for x in entries - .into_iter() - .flat_map(|mut e| { - e.name_value.push(e.common_name); - e.name_value - }) - .sorted() - .dedup() - { - info!("{x}"); - } - } - RunCommand::PortScanner { - targets, - exclude, - technique, - ports, - timeout, - concurrent_limit, - max_retries, - retry_interval, - skip_icmp_check, - } => { - let mut addresses = vec![]; - for target in targets { - if let Ok(addr) = IpAddr::from_str(&target) { - addresses.push(addr); - } else if let Ok(net) = IpNet::from_str(&target) { - addresses.extend(net.hosts()); - } else { - return Err(format!("{target} isn't valid ip address or ip net")); + retry_interval, + } => { + let ct = CertificateTransparencySettings { + target, + include_expired, + max_retries, + retry_interval: Duration::from_millis(retry_interval as u64), + }; + + let entries = query_ct_api(ct).await?; + for x in entries + .into_iter() + .flat_map(|mut e| { + e.name_value.push(e.common_name); + e.name_value + }) + .sorted() + .dedup() + { + info!("{x}"); } } + RunCommand::PortScanner { + targets, + exclude, + technique, + ports, + timeout, + concurrent_limit, + max_retries, + retry_interval, + skip_icmp_check, + } => { + let mut addresses = vec![]; + for target in targets { + if let Ok(addr) = IpAddr::from_str(&target) { + addresses.push(addr); + } else if let Ok(net) = IpNet::from_str(&target) { + addresses.extend(net.hosts()); + } else { + return Err(format!("{target} isn't valid ip address or ip net")); + } + } + + let mut exclude_addresses = vec![]; + for ex in exclude { + if let Ok(addr) = IpAddr::from_str(&ex) { + exclude_addresses.push(addr); + } else if let Ok(net) = IpNet::from_str(&ex) { + exclude_addresses.extend(net.hosts()); + } else { + return Err(format!("{ex} isn't valid ip address or ip net")); + } + } + + let addresses: Vec = addresses + .into_iter() + .filter(|addr| !exclude_addresses.contains(addr)) + .sorted() + .dedup() + .collect(); + + let mut port_range = vec![]; - let mut exclude_addresses = vec![]; - for ex in exclude { - if let Ok(addr) = IpAddr::from_str(&ex) { - exclude_addresses.push(addr); - } else if let Ok(net) = IpNet::from_str(&ex) { - exclude_addresses.extend(net.hosts()); + if ports.is_empty() { + port_range.extend(1..=u16::MAX); } else { - return Err(format!("{ex} isn't valid ip address or ip net")); + utils::parse_ports(&ports, &mut port_range)?; } - } - let addresses: Vec = addresses - .into_iter() - .filter(|addr| !exclude_addresses.contains(addr)) - .sorted() - .dedup() - .collect(); + match technique { + PortScanTechnique::TcpCon => { + let settings = TcpPortScannerSettings { + addresses, + port_range, + timeout: Duration::from_millis(timeout as u64), + skip_icmp_check, + max_retries, + retry_interval: Duration::from_millis(retry_interval as u64), + concurrent_limit: u32::from(concurrent_limit), + }; - let mut port_range = vec![]; + let (tx, mut rx) = mpsc::channel(1); - if ports.is_empty() { - port_range.extend(1..=u16::MAX); - } else { - utils::parse_ports(&ports, &mut port_range)?; - } + task::spawn(async move { + while let Some(addr) = rx.recv().await { + info!("Open port found: {addr}"); + } + }); - match technique { - PortScanTechnique::TcpCon => { - let settings = TcpPortScannerSettings { - addresses, - port_range, - timeout: Duration::from_millis(timeout as u64), - skip_icmp_check, - max_retries, - retry_interval: Duration::from_millis(retry_interval as u64), - concurrent_limit: u32::from(concurrent_limit), - }; - - let (tx, mut rx) = mpsc::channel(1); - - task::spawn(async move { - while let Some(addr) = rx.recv().await { - info!("Open port found: {addr}"); + if let Err(err) = start_tcp_con_port_scan(settings, tx).await { + error!("{err}"); } - }); - - if let Err(err) = start_tcp_con_port_scan(settings, tx).await { - error!("{err}"); } - } - PortScanTechnique::Icmp => { - let settings = IcmpScanSettings { - addresses, - timeout: Duration::from_millis(timeout as u64), - }; - let (tx, mut rx) = mpsc::channel(1); - - task::spawn(async move { - while let Some(addr) = rx.recv().await { - info!("Host up: {addr}"); - } - }); + PortScanTechnique::Icmp => { + let settings = IcmpScanSettings { + addresses, + timeout: Duration::from_millis(timeout as u64), + }; + let (tx, mut rx) = mpsc::channel(1); - if let Err(err) = start_icmp_scan(settings, tx).await { - error!("{err}"); + task::spawn(async move { + while let Some(addr) = rx.recv().await { + info!("Host up: {addr}"); + } + }); + + if let Err(err) = start_icmp_scan(settings, tx).await { + error!("{err}"); + } } } } - } - RunCommand::Dehashed { query } => { - let email = match env::var("DEHASHED_EMAIL") { - Ok(x) => x, - Err(_) => { - error!("Missing environment variable DEHASHED_EMAIL"); - return Err("Missing environment variable DEHASHED_EMAIL".to_string()); - } - }; - let api_key = match env::var("DEHASHED_API_KEY") { - Ok(x) => x, - Err(_) => { - error!("Missing environment variable DEHASHED_API_KEY"); - return Err("Missing environment variable DEHASHED_API_KEY".to_string()); - } - }; - - match dehashed::query( - email, - api_key, - dehashed_rs::Query::Domain(SearchType::Simple(query)), - ) - .await - { - Ok(x) => { - for entry in x.entries { - info!("{entry:?}"); + RunCommand::Dehashed { query } => { + let email = match env::var("DEHASHED_EMAIL") { + Ok(x) => x, + Err(_) => { + error!("Missing environment variable DEHASHED_EMAIL"); + return Err( + "Missing environment variable DEHASHED_EMAIL".to_string() + ); + } + }; + let api_key = match env::var("DEHASHED_API_KEY") { + Ok(x) => x, + Err(_) => { + error!("Missing environment variable DEHASHED_API_KEY"); + return Err( + "Missing environment variable DEHASHED_API_KEY".to_string() + ); + } + }; + + match dehashed::query( + email, + api_key, + dehashed_rs::Query::Domain(SearchType::Simple(query)), + ) + .await + { + Ok(x) => { + for entry in x.entries { + info!("{entry:?}"); + } + } + Err(err) => { + error!("{err}"); } - } - Err(err) => { - error!("{err}"); } } } @@ -407,3 +497,24 @@ async fn main() -> Result<(), String> { Ok(()) } + +async fn migrate(config_path: &str, migration_dir: String) -> Result<(), String> { + let config = get_config(config_path)?; + cli::migrate::run_migrate_custom( + cli::config::DatabaseConfig { + last_migration_table_name: None, + driver: cli::config::DatabaseDriver::Postgres { + host: config.database.host, + port: config.database.port, + name: config.database.name, + user: config.database.user, + password: config.database.password, + }, + }, + migration_dir, + false, + None, + ) + .await + .map_err(|e| e.to_string()) +} diff --git a/leech/src/rpc/attacks.rs b/leech/src/rpc/attacks.rs index d3732c626..54f0ca01c 100644 --- a/leech/src/rpc/attacks.rs +++ b/leech/src/rpc/attacks.rs @@ -19,10 +19,10 @@ use crate::modules::certificate_transparency::{query_ct_api, CertificateTranspar use crate::modules::port_scanner::tcp_con::{start_tcp_con_port_scan, TcpPortScannerSettings}; use crate::rpc::rpc_attacks::port_or_range::PortOrRange; use crate::rpc::rpc_attacks::req_attack_service_server::ReqAttackService; +use crate::rpc::rpc_attacks::shared::CertEntry; use crate::rpc::rpc_attacks::{ - BruteforceSubdomainRequest, BruteforceSubdomainResponse, CertEntry, - CertificateTransparencyRequest, CertificateTransparencyResponse, TcpPortScanRequest, - TcpPortScanResponse, + BruteforceSubdomainRequest, BruteforceSubdomainResponse, CertificateTransparencyRequest, + CertificateTransparencyResponse, TcpPortScanRequest, TcpPortScanResponse, }; /// The Attack service diff --git a/proto/attacks.proto b/proto/attacks.proto index 4fda147f9..2586ee6e1 100644 --- a/proto/attacks.proto +++ b/proto/attacks.proto @@ -2,7 +2,6 @@ syntax = "proto3"; package attacks; import "attacks.shared.proto"; -import "google/protobuf/timestamp.proto"; /* -- BruteforceSubdomain @@ -101,30 +100,52 @@ message CertificateTransparencyRequest { uint64 retry_interval = 4; } -// Entry of a certificate transparency response -message CertEntry { - // The name of the issuer - string issuer_name = 1; - // The common name of the certificate - string common_name = 2; - // The values of the certificate - repeated string value_names = 3; - // The start date of the certificate - google.protobuf.Timestamp not_before = 4; - // The end date of the certificate - google.protobuf.Timestamp not_after = 5; - // The serial number of the certificate - string serial_number = 6; -} // Response to a certificate transparency request message CertificateTransparencyResponse { // List of cert entries - repeated CertEntry entries = 1; + repeated shared.CertEntry entries = 1; } service ReqAttackService { rpc BruteforceSubdomains(BruteforceSubdomainRequest) returns (stream BruteforceSubdomainResponse); rpc RunTcpPortScan(TcpPortScanRequest) returns (stream TcpPortScanResponse); rpc QueryCertificateTransparency(CertificateTransparencyRequest) returns (CertificateTransparencyResponse); +} + +/* +------------------------ Results ------------------------------- + */ + +// The response to submitting a result +message ResultResponse { + // The attack uuid assigned by kraken + string uuid = 1; +} + +// Metainfos about the attack +message MetaAttackInfo { + // The uuid of a workspace + string workspace_uuid = 1; +} + +// Result of a certificate transparency request +message CertificateTransparencyResult { + // Information about the attack + MetaAttackInfo attack_info = 1; + // List of cert entries + repeated attacks.shared.CertEntry entries = 2; +} + +// Result of a subdomain enumeration request +message SubdomainEnumerationResult { + // Information about the attack + MetaAttackInfo attack_info = 1; + // Found record + shared.DNSRecord record = 2; +} + +service AttackResultsService { + rpc CertificateTransparency(CertificateTransparencyResult) returns (ResultResponse); + rpc SubdomainEnumeration(stream SubdomainEnumerationResult) returns (ResultResponse); } \ No newline at end of file diff --git a/proto/attacks.shared.proto b/proto/attacks.shared.proto index 136e5f10c..e25347643 100644 --- a/proto/attacks.shared.proto +++ b/proto/attacks.shared.proto @@ -1,6 +1,8 @@ syntax = "proto3"; package attacks.shared; +import "google/protobuf/timestamp.proto"; + // Representation of an ipv4 address message Ipv4 { sfixed32 address = 1; @@ -46,3 +48,20 @@ message DNSRecord { CNAME cname = 3; } } + + +// Entry of a certificate transparency response +message CertEntry { + // The name of the issuer + string issuer_name = 1; + // The common name of the certificate + string common_name = 2; + // The values of the certificate + repeated string value_names = 3; + // The start date of the certificate + google.protobuf.Timestamp not_before = 4; + // The end date of the certificate + google.protobuf.Timestamp not_after = 5; + // The serial number of the certificate + string serial_number = 6; +}