feat: added beacon installer generation, download
This commit is contained in:
parent
b416f35b63
commit
0576c4fd3b
182
Cargo.lock
generated
182
Cargo.lock
generated
@ -95,6 +95,45 @@ version = "1.7.1"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "69f7f8c3906b62b754cd5326047894316021dcfe5a194c8ea52bdd94934a3457"
|
checksum = "69f7f8c3906b62b754cd5326047894316021dcfe5a194c8ea52bdd94934a3457"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "asn1-rs"
|
||||||
|
version = "0.6.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5493c3bedbacf7fd7382c6346bbd66687d12bbaad3a89a2d2c303ee6cf20b048"
|
||||||
|
dependencies = [
|
||||||
|
"asn1-rs-derive",
|
||||||
|
"asn1-rs-impl",
|
||||||
|
"displaydoc",
|
||||||
|
"nom",
|
||||||
|
"num-traits",
|
||||||
|
"rusticata-macros",
|
||||||
|
"thiserror 1.0.69",
|
||||||
|
"time",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "asn1-rs-derive"
|
||||||
|
version = "0.5.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "965c2d33e53cb6b267e148a4cb0760bc01f4904c1cd4bb4002a085bb016d1490"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn 2.0.96",
|
||||||
|
"synstructure",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "asn1-rs-impl"
|
||||||
|
version = "0.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7b18050c2cd6fe86c3a76584ef5e0baf286d038cda203eb6223df2cc413565f7"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn 2.0.96",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "async-compression"
|
name = "async-compression"
|
||||||
version = "0.4.18"
|
version = "0.4.18"
|
||||||
@ -797,6 +836,20 @@ dependencies = [
|
|||||||
"zeroize",
|
"zeroize",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "der-parser"
|
||||||
|
version = "9.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5cd0a5c643689626bec213c4d8bd4d96acc8ffdb4ad4bb6bc16abf27d5f4b553"
|
||||||
|
dependencies = [
|
||||||
|
"asn1-rs",
|
||||||
|
"displaydoc",
|
||||||
|
"nom",
|
||||||
|
"num-bigint",
|
||||||
|
"num-traits",
|
||||||
|
"rusticata-macros",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "deranged"
|
name = "deranged"
|
||||||
version = "0.3.11"
|
version = "0.3.11"
|
||||||
@ -1675,7 +1728,7 @@ dependencies = [
|
|||||||
"oco_ref",
|
"oco_ref",
|
||||||
"or_poisoned",
|
"or_poisoned",
|
||||||
"paste",
|
"paste",
|
||||||
"rand",
|
"rand 0.8.5",
|
||||||
"reactive_graph",
|
"reactive_graph",
|
||||||
"rustc-hash 2.1.0",
|
"rustc-hash 2.1.0",
|
||||||
"send_wrapper",
|
"send_wrapper",
|
||||||
@ -2107,6 +2160,16 @@ dependencies = [
|
|||||||
"winapi",
|
"winapi",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num-bigint"
|
||||||
|
version = "0.4.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9"
|
||||||
|
dependencies = [
|
||||||
|
"num-integer",
|
||||||
|
"num-traits",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "num-bigint-dig"
|
name = "num-bigint-dig"
|
||||||
version = "0.8.4"
|
version = "0.8.4"
|
||||||
@ -2119,7 +2182,7 @@ dependencies = [
|
|||||||
"num-integer",
|
"num-integer",
|
||||||
"num-iter",
|
"num-iter",
|
||||||
"num-traits",
|
"num-traits",
|
||||||
"rand",
|
"rand 0.8.5",
|
||||||
"smallvec",
|
"smallvec",
|
||||||
"zeroize",
|
"zeroize",
|
||||||
]
|
]
|
||||||
@ -2189,6 +2252,15 @@ dependencies = [
|
|||||||
"thiserror 1.0.69",
|
"thiserror 1.0.69",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "oid-registry"
|
||||||
|
version = "0.7.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a8d8034d9489cdaf79228eb9f6a3b8d7bb32ba00d6645ebd48eef4077ceb5bd9"
|
||||||
|
dependencies = [
|
||||||
|
"asn1-rs",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "once_cell"
|
name = "once_cell"
|
||||||
version = "1.20.2"
|
version = "1.20.2"
|
||||||
@ -2247,7 +2319,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "346f04948ba92c43e8469c1ee6736c7563d71012b17d40745260fe106aac2166"
|
checksum = "346f04948ba92c43e8469c1ee6736c7563d71012b17d40745260fe106aac2166"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"base64ct",
|
"base64ct",
|
||||||
"rand_core",
|
"rand_core 0.6.4",
|
||||||
"subtle",
|
"subtle",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -2383,7 +2455,7 @@ version = "0.2.20"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04"
|
checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"zerocopy",
|
"zerocopy 0.7.35",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -2513,8 +2585,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
|
checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
"rand_chacha",
|
"rand_chacha 0.3.1",
|
||||||
"rand_core",
|
"rand_core 0.6.4",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rand"
|
||||||
|
version = "0.9.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3779b94aeb87e8bd4e834cee3650289ee9e0d5677f976ecdb6d219e5f4f6cd94"
|
||||||
|
dependencies = [
|
||||||
|
"rand_chacha 0.9.0",
|
||||||
|
"rand_core 0.9.0",
|
||||||
|
"zerocopy 0.8.14",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -2524,7 +2607,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
|
checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ppv-lite86",
|
"ppv-lite86",
|
||||||
"rand_core",
|
"rand_core 0.6.4",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rand_chacha"
|
||||||
|
version = "0.9.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb"
|
||||||
|
dependencies = [
|
||||||
|
"ppv-lite86",
|
||||||
|
"rand_core 0.9.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -2536,6 +2629,16 @@ dependencies = [
|
|||||||
"getrandom 0.2.15",
|
"getrandom 0.2.15",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rand_core"
|
||||||
|
version = "0.9.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b08f3c9802962f7e1b25113931d94f43ed9725bebc59db9d0c3e9a23b67e15ff"
|
||||||
|
dependencies = [
|
||||||
|
"getrandom 0.3.1",
|
||||||
|
"zerocopy 0.8.14",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rcgen"
|
name = "rcgen"
|
||||||
version = "0.13.2"
|
version = "0.13.2"
|
||||||
@ -2546,6 +2649,7 @@ dependencies = [
|
|||||||
"ring",
|
"ring",
|
||||||
"rustls-pki-types",
|
"rustls-pki-types",
|
||||||
"time",
|
"time",
|
||||||
|
"x509-parser",
|
||||||
"yasna",
|
"yasna",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -2690,7 +2794,7 @@ dependencies = [
|
|||||||
"num-traits",
|
"num-traits",
|
||||||
"pkcs1",
|
"pkcs1",
|
||||||
"pkcs8",
|
"pkcs8",
|
||||||
"rand_core",
|
"rand_core 0.6.4",
|
||||||
"signature",
|
"signature",
|
||||||
"spki",
|
"spki",
|
||||||
"subtle",
|
"subtle",
|
||||||
@ -2740,6 +2844,15 @@ version = "2.1.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c7fb8039b3032c191086b10f11f319a6e99e1e82889c5cc6046f515c9db1d497"
|
checksum = "c7fb8039b3032c191086b10f11f319a6e99e1e82889c5cc6046f515c9db1d497"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rusticata-macros"
|
||||||
|
version = "4.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "faf0c4a6ece9950b9abdb62b1cfcf2a68b3b67a10ba445b3bb85be2a293d0632"
|
||||||
|
dependencies = [
|
||||||
|
"nom",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustix"
|
name = "rustix"
|
||||||
version = "0.38.44"
|
version = "0.38.44"
|
||||||
@ -2760,6 +2873,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "9fb9263ab4eb695e42321db096e3b8fbd715a59b154d5c88d82db2175b681ba7"
|
checksum = "9fb9263ab4eb695e42321db096e3b8fbd715a59b154d5c88d82db2175b681ba7"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"aws-lc-rs",
|
"aws-lc-rs",
|
||||||
|
"log",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"rustls-pki-types",
|
"rustls-pki-types",
|
||||||
"rustls-webpki",
|
"rustls-webpki",
|
||||||
@ -3017,7 +3131,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de"
|
checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"digest",
|
"digest",
|
||||||
"rand_core",
|
"rand_core 0.6.4",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -3079,6 +3193,7 @@ dependencies = [
|
|||||||
"axum",
|
"axum",
|
||||||
"axum-server",
|
"axum-server",
|
||||||
"futures",
|
"futures",
|
||||||
|
"rustls",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"sqlx",
|
"sqlx",
|
||||||
@ -3114,10 +3229,13 @@ dependencies = [
|
|||||||
"leptos_meta",
|
"leptos_meta",
|
||||||
"leptos_router",
|
"leptos_router",
|
||||||
"pbkdf2",
|
"pbkdf2",
|
||||||
|
"rand 0.9.0",
|
||||||
"rcgen",
|
"rcgen",
|
||||||
"rpassword",
|
"rpassword",
|
||||||
|
"rustls-pki-types",
|
||||||
"serde",
|
"serde",
|
||||||
"sha2",
|
"sha2",
|
||||||
|
"sparse-actions",
|
||||||
"sparse-handler",
|
"sparse-handler",
|
||||||
"sqlx",
|
"sqlx",
|
||||||
"structopt",
|
"structopt",
|
||||||
@ -3287,7 +3405,7 @@ dependencies = [
|
|||||||
"memchr",
|
"memchr",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"percent-encoding",
|
"percent-encoding",
|
||||||
"rand",
|
"rand 0.8.5",
|
||||||
"rsa",
|
"rsa",
|
||||||
"serde",
|
"serde",
|
||||||
"sha1",
|
"sha1",
|
||||||
@ -3326,7 +3444,7 @@ dependencies = [
|
|||||||
"md-5",
|
"md-5",
|
||||||
"memchr",
|
"memchr",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"rand",
|
"rand 0.8.5",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"sha2",
|
"sha2",
|
||||||
@ -3934,7 +4052,7 @@ dependencies = [
|
|||||||
"http",
|
"http",
|
||||||
"httparse",
|
"httparse",
|
||||||
"log",
|
"log",
|
||||||
"rand",
|
"rand 0.8.5",
|
||||||
"sha1",
|
"sha1",
|
||||||
"thiserror 1.0.69",
|
"thiserror 1.0.69",
|
||||||
"utf-8",
|
"utf-8",
|
||||||
@ -4465,6 +4583,24 @@ version = "0.5.5"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51"
|
checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "x509-parser"
|
||||||
|
version = "0.16.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "fcbc162f30700d6f3f82a24bf7cc62ffe7caea42c0b2cba8bf7f3ae50cf51f69"
|
||||||
|
dependencies = [
|
||||||
|
"asn1-rs",
|
||||||
|
"data-encoding",
|
||||||
|
"der-parser",
|
||||||
|
"lazy_static",
|
||||||
|
"nom",
|
||||||
|
"oid-registry",
|
||||||
|
"ring",
|
||||||
|
"rusticata-macros",
|
||||||
|
"thiserror 1.0.69",
|
||||||
|
"time",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "xxhash-rust"
|
name = "xxhash-rust"
|
||||||
version = "0.8.15"
|
version = "0.8.15"
|
||||||
@ -4517,7 +4653,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0"
|
checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"byteorder",
|
"byteorder",
|
||||||
"zerocopy-derive",
|
"zerocopy-derive 0.7.35",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "zerocopy"
|
||||||
|
version = "0.8.14"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a367f292d93d4eab890745e75a778da40909cab4d6ff8173693812f79c4a2468"
|
||||||
|
dependencies = [
|
||||||
|
"zerocopy-derive 0.8.14",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -4531,6 +4676,17 @@ dependencies = [
|
|||||||
"syn 2.0.96",
|
"syn 2.0.96",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "zerocopy-derive"
|
||||||
|
version = "0.8.14"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d3931cb58c62c13adec22e38686b559c86a30565e16ad6e8510a337cedc611e1"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn 2.0.96",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "zerofrom"
|
name = "zerofrom"
|
||||||
version = "0.1.5"
|
version = "0.1.5"
|
||||||
|
|||||||
@ -11,6 +11,9 @@ lto = true
|
|||||||
codegen-units = 1
|
codegen-units = 1
|
||||||
panic = "abort"
|
panic = "abort"
|
||||||
|
|
||||||
|
[profile.dev]
|
||||||
|
panic = "abort"
|
||||||
|
|
||||||
[profile.wasm-release]
|
[profile.wasm-release]
|
||||||
inherits = "release"
|
inherits = "release"
|
||||||
strip = true
|
strip = true
|
||||||
|
|||||||
17
flake.nix
17
flake.nix
@ -99,6 +99,7 @@
|
|||||||
|
|
||||||
craneLib = (crane.mkLib pkgs).overrideToolchain (p:
|
craneLib = (crane.mkLib pkgs).overrideToolchain (p:
|
||||||
p.rust-bin.nightly.latest.default.override {
|
p.rust-bin.nightly.latest.default.override {
|
||||||
|
extensions = [ "rust-src" ];
|
||||||
targets = [
|
targets = [
|
||||||
"x86_64-unknown-linux-gnu"
|
"x86_64-unknown-linux-gnu"
|
||||||
"x86_64-unknown-linux-musl"
|
"x86_64-unknown-linux-musl"
|
||||||
@ -138,9 +139,10 @@
|
|||||||
set -eux
|
set -eux
|
||||||
|
|
||||||
${setup-zig-freebsd}/bin/setup-zig-freebsd
|
${setup-zig-freebsd}/bin/setup-zig-freebsd
|
||||||
cargo build -p sparse-windows-beacon --target=x86_64-pc-windows-gnu
|
|
||||||
cargo build -p sparse-unix-beacon --target=x86_64-unknown-freebsd
|
mkdir -p target/x86_64-{unknown-{linux-musl,freebsd},pc-windows-gnu}/debug
|
||||||
cargo build -p sparse-unix-beacon --target=x86_64-unknown-linux-musl
|
touch target/x86_64-unknown-{linux-musl,freebsd}/debug/sparse-unix-{beacon,installer}
|
||||||
|
touch target/x86_64-pc-windows-gnu/debug/sparse-windows-{beacon.dll,installer.exe}
|
||||||
'';
|
'';
|
||||||
in {
|
in {
|
||||||
packages = outputs.packages;
|
packages = outputs.packages;
|
||||||
@ -155,15 +157,18 @@
|
|||||||
|
|
||||||
# Added to make development easier
|
# Added to make development easier
|
||||||
SPARSE_INSTALLER_LINUX =
|
SPARSE_INSTALLER_LINUX =
|
||||||
"../../target/x86_64-unknown-linux-musl/debug/sparse-unix-beacon";
|
"../../target/x86_64-unknown-linux-musl/debug/sparse-unix-installer";
|
||||||
SPARSE_INSTALLER_FREEBSD =
|
SPARSE_INSTALLER_FREEBSD =
|
||||||
"../../target/x86_64-unknown-freebsd/debug/sparse-unix-beacon";
|
"../../target/x86_64-unknown-freebsd/debug/sparse-unix-installer";
|
||||||
|
SPARSE_INSTALLER_WINDOWS =
|
||||||
|
"../../target/x86_64-pc-windows-gnu/debug/sparse-windows-installer.exe";
|
||||||
|
|
||||||
SPARSE_BEACON_LINUX =
|
SPARSE_BEACON_LINUX =
|
||||||
"../../target/x86_64-unknown-linux-musl/debug/sparse-unix-beacon";
|
"../../target/x86_64-unknown-linux-musl/debug/sparse-unix-beacon";
|
||||||
SPARSE_BEACON_FREEBSD =
|
SPARSE_BEACON_FREEBSD =
|
||||||
"../../target/x86_64-unknown-freebsd/debug/sparse-unix-beacon";
|
"../../target/x86_64-unknown-freebsd/debug/sparse-unix-beacon";
|
||||||
SPARSE_BEACON_WINDOWS =
|
SPARSE_BEACON_WINDOWS =
|
||||||
"../../target/x86_64-pc-windows-gnu/debug/sparse-windows-beacon.exe";
|
"../../../target/x86_64-pc-windows-gnu/debug/sparse-windows-beacon.dll";
|
||||||
|
|
||||||
shellHook = ''
|
shellHook = ''
|
||||||
export DATABASE_URL="sqlite://$(${pkgs.git}/bin/git rev-parse --show-toplevel)/sparse-server/db.sqlite"
|
export DATABASE_URL="sqlite://$(${pkgs.git}/bin/git rev-parse --show-toplevel)/sparse-server/db.sqlite"
|
||||||
|
|||||||
@ -288,8 +288,9 @@ let
|
|||||||
|
|
||||||
outputs = rec {
|
outputs = rec {
|
||||||
packages = {
|
packages = {
|
||||||
inherit sparse-server sparse-installer-linux sparse-installer-freebsd
|
inherit sparse-server sparse-beacon-linux sparse-beacon-freebsd
|
||||||
sparse-installer-windows;
|
sparse-beacon-windows linux-loader freebsd-loader sparse-installer-linux
|
||||||
|
sparse-installer-freebsd sparse-installer-windows;
|
||||||
|
|
||||||
inherit freebsd-zig-libc;
|
inherit freebsd-zig-libc;
|
||||||
|
|
||||||
|
|||||||
@ -14,3 +14,4 @@ sqlx = { version = "0.8", default-features = false, features = ["chrono", "macro
|
|||||||
serde = "1.0"
|
serde = "1.0"
|
||||||
serde_json = "1.0"
|
serde_json = "1.0"
|
||||||
axum-server = { version = "^0.7", features = ["tokio-rustls", "tls-rustls"] }
|
axum-server = { version = "^0.7", features = ["tokio-rustls", "tls-rustls"] }
|
||||||
|
rustls = "0.23"
|
||||||
|
|||||||
@ -4,6 +4,7 @@ pub enum Error {
|
|||||||
Sqlx(sqlx::Error),
|
Sqlx(sqlx::Error),
|
||||||
TokioJoin(tokio::task::JoinError),
|
TokioJoin(tokio::task::JoinError),
|
||||||
Io(std::io::Error),
|
Io(std::io::Error),
|
||||||
|
Rustls(rustls::Error),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::fmt::Display for Error {
|
impl std::fmt::Display for Error {
|
||||||
@ -21,6 +22,9 @@ impl std::fmt::Display for Error {
|
|||||||
Error::Io(err) => {
|
Error::Io(err) => {
|
||||||
write!(f, "io error: {err:?}")
|
write!(f, "io error: {err:?}")
|
||||||
}
|
}
|
||||||
|
Error::Rustls(err) => {
|
||||||
|
write!(f, "rustls error: {err:?}")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -31,6 +35,7 @@ impl std::error::Error for Error {
|
|||||||
Error::Sqlx(err) => Some(err),
|
Error::Sqlx(err) => Some(err),
|
||||||
Error::TokioJoin(err) => Some(err),
|
Error::TokioJoin(err) => Some(err),
|
||||||
Error::Io(err) => Some(err),
|
Error::Io(err) => Some(err),
|
||||||
|
Error::Rustls(err) => Some(err),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -61,3 +66,9 @@ impl From<std::io::Error> for Error {
|
|||||||
Self::Io(err)
|
Self::Io(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<rustls::Error> for Error {
|
||||||
|
fn from(err: rustls::Error) -> Self {
|
||||||
|
Self::Rustls(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -4,7 +4,6 @@ use std::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
use axum::routing::{get, post, Router};
|
use axum::routing::{get, post, Router};
|
||||||
use axum_server::tls_rustls::RustlsConfig;
|
|
||||||
use sqlx::SqlitePool;
|
use sqlx::SqlitePool;
|
||||||
use tokio::task::JoinHandle;
|
use tokio::task::JoinHandle;
|
||||||
|
|
||||||
@ -36,8 +35,6 @@ impl std::ops::Deref for BeaconListenerMap {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub async fn start_all_listeners(beacon_listener_map: BeaconListenerMap, db: SqlitePool) -> Result<(), crate::error::Error> {
|
pub async fn start_all_listeners(beacon_listener_map: BeaconListenerMap, db: SqlitePool) -> Result<(), crate::error::Error> {
|
||||||
tracing::debug!("Typeid: {:?}", std::any::TypeId::of::<BeaconListenerMap>());
|
|
||||||
|
|
||||||
let listener_ids = sqlx::query!("SELECT listener_id FROM beacon_listener")
|
let listener_ids = sqlx::query!("SELECT listener_id FROM beacon_listener")
|
||||||
.fetch_all(&db)
|
.fetch_all(&db)
|
||||||
.await?;
|
.await?;
|
||||||
@ -56,6 +53,15 @@ struct ListenerState {
|
|||||||
db: SqlitePool
|
db: SqlitePool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct Listener {
|
||||||
|
listener_id: i64,
|
||||||
|
port: i64,
|
||||||
|
public_ip: String,
|
||||||
|
domain_name: String,
|
||||||
|
certificate: Vec<u8>,
|
||||||
|
privkey: Vec<u8>
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn start_listener(beacon_listener_map: BeaconListenerMap, listener_id: i64, db: SqlitePool) -> Result<(), crate::error::Error> {
|
pub async fn start_listener(beacon_listener_map: BeaconListenerMap, listener_id: i64, db: SqlitePool) -> Result<(), crate::error::Error> {
|
||||||
{
|
{
|
||||||
let Ok(blm_handle) = beacon_listener_map.read() else {
|
let Ok(blm_handle) = beacon_listener_map.read() else {
|
||||||
@ -66,7 +72,7 @@ pub async fn start_listener(beacon_listener_map: BeaconListenerMap, listener_id:
|
|||||||
return Err(crate::error::Error::Generic("Beacon listener already started".to_string()));
|
return Err(crate::error::Error::Generic("Beacon listener already started".to_string()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let listener = sqlx::query!("SELECT * FROM beacon_listener WHERE listener_id = ?", listener_id)
|
let listener = sqlx::query_as!(Listener, "SELECT * FROM beacon_listener WHERE listener_id = ?", listener_id)
|
||||||
.fetch_one(&db)
|
.fetch_one(&db)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
@ -84,17 +90,30 @@ pub async fn start_listener(beacon_listener_map: BeaconListenerMap, listener_id:
|
|||||||
|
|
||||||
let hidden_app = Router::new().nest("/hidden_sparse", app);
|
let hidden_app = Router::new().nest("/hidden_sparse", app);
|
||||||
|
|
||||||
let tls_config = RustlsConfig::from_pem(
|
let keypair = match rustls::pki_types::PrivateKeyDer::try_from(listener.privkey.clone()) {
|
||||||
listener.certificate.as_bytes().to_vec(),
|
Ok(pk) => pk,
|
||||||
listener.privkey.as_bytes().to_vec()
|
Err(e) => {
|
||||||
).await?;
|
return Err(crate::error::Error::Generic(format!("Could not parse private key: {e}")));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let cert = rustls::pki_types::CertificateDer::from(listener.certificate.clone());
|
||||||
|
|
||||||
|
let mut tls_config = rustls::ServerConfig::builder()
|
||||||
|
.with_no_client_auth()
|
||||||
|
.with_single_cert(vec![cert], keypair)?;
|
||||||
|
tls_config.alpn_protocols = vec![b"h2".to_vec(), b"http/1.1".to_vec()];
|
||||||
|
|
||||||
let addr = std::net::SocketAddr::from(([0, 0, 0, 0], listener.port as u16));
|
let addr = std::net::SocketAddr::from(([0, 0, 0, 0], listener.port as u16));
|
||||||
|
|
||||||
tracing::debug!("Starting listener {}, {}, on port {}", listener_id, listener.domain_name, listener.port);
|
tracing::debug!("Starting listener {}, {}, on port {}", listener_id, listener.domain_name, listener.port);
|
||||||
|
|
||||||
let join_handle = tokio::task::spawn(async move {
|
let join_handle = tokio::task::spawn(async move {
|
||||||
let res = axum_server::tls_rustls::bind_rustls(addr, tls_config)
|
let res = axum_server::tls_rustls::bind_rustls(
|
||||||
|
addr,
|
||||||
|
axum_server::tls_rustls::RustlsConfig::from_config(
|
||||||
|
Arc::new(tls_config)
|
||||||
|
)
|
||||||
|
)
|
||||||
.serve(hidden_app.into_make_service())
|
.serve(hidden_app.into_make_service())
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
|
|||||||
@ -9,12 +9,12 @@ crate-type = ["cdylib", "rlib"]
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
leptos = { version = "^0.7", features = ["nightly"] }
|
leptos = { version = "^0.7", features = ["nightly"] }
|
||||||
leptos_router = { version = "^0.7", features = ["nightly"] }
|
leptos_router = { version = "^0.7", features = ["nightly"] }
|
||||||
axum = { version = "^0.7", features = ["ws", "macros"], optional = true }
|
axum = { version = "^0.7", features = ["ws", "macros", "http2"], optional = true }
|
||||||
axum-extra = { version = "^0.9", features = ["cookie"], optional = true }
|
axum-extra = { version = "^0.9", features = ["cookie"], optional = true }
|
||||||
console_error_panic_hook = "0.1"
|
console_error_panic_hook = "0.1"
|
||||||
leptos_axum = { version = "^0.7", optional = true }
|
leptos_axum = { version = "^0.7", optional = true }
|
||||||
leptos_meta = { version = "^0.7" }
|
leptos_meta = { version = "^0.7" }
|
||||||
tokio = { version = "1", features = ["rt-multi-thread", "signal"], optional = true }
|
tokio = { version = "1", features = ["rt-multi-thread", "signal", "fs", "io-std", "io-util"], optional = true }
|
||||||
tower = { version = "0.4", optional = true }
|
tower = { version = "0.4", optional = true }
|
||||||
tower-http = { version = "0.5", features = ["fs", "compression-br", "compression-deflate", "compression-gzip", "compression-zstd", "trace"], optional = true }
|
tower-http = { version = "0.5", features = ["fs", "compression-br", "compression-deflate", "compression-gzip", "compression-zstd", "trace"], optional = true }
|
||||||
wasm-bindgen = "0.2"
|
wasm-bindgen = "0.2"
|
||||||
@ -39,9 +39,12 @@ sha2 = { version = "0.10", optional = true }
|
|||||||
hex = { version = "0.4", optional = true }
|
hex = { version = "0.4", optional = true }
|
||||||
serde = "1.0"
|
serde = "1.0"
|
||||||
cfg-if = "1.0.0"
|
cfg-if = "1.0.0"
|
||||||
rcgen = { version = "0.13.2", optional = true }
|
rcgen = { version = "0.13.2", features = ["pem", "x509-parser", "crypto"], optional = true }
|
||||||
cron = { version = "0.15.0", optional = true }
|
cron = { version = "0.15.0", optional = true }
|
||||||
|
rustls-pki-types = { version = "1.7", optional = true }
|
||||||
|
rand = { version = "0.9", optional = true }
|
||||||
|
|
||||||
|
sparse-actions = { path = "../sparse-actions", optional = true }
|
||||||
sparse-handler = { path = "../sparse-handler", optional = true }
|
sparse-handler = { path = "../sparse-handler", optional = true }
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
@ -67,6 +70,9 @@ ssr = [
|
|||||||
"dep:rcgen",
|
"dep:rcgen",
|
||||||
"dep:cron",
|
"dep:cron",
|
||||||
"dep:sparse-handler",
|
"dep:sparse-handler",
|
||||||
|
"dep:rustls-pki-types",
|
||||||
|
"dep:sparse-actions",
|
||||||
|
"dep:rand",
|
||||||
"leptos/ssr",
|
"leptos/ssr",
|
||||||
"leptos_meta/ssr",
|
"leptos_meta/ssr",
|
||||||
"leptos_router/ssr",
|
"leptos_router/ssr",
|
||||||
|
|||||||
14
sparse-server/migrations/20250202045114_mtls.sql
Normal file
14
sparse-server/migrations/20250202045114_mtls.sql
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
-- Add migration script here
|
||||||
|
ALTER TABLE beacon_template ADD COLUMN client_key blob NOT NULL DEFAULT '';
|
||||||
|
ALTER TABLE beacon_template ADD COLUMN client_cert blob NOT NULL DEFAULT '';
|
||||||
|
|
||||||
|
DROP TABLE beacon_listener;
|
||||||
|
CREATE TABLE beacon_listener (
|
||||||
|
listener_id integer PRIMARY KEY AUTOINCREMENT NOT NULL,
|
||||||
|
|
||||||
|
port int NOT NULL,
|
||||||
|
public_ip varchar NOT NULL,
|
||||||
|
domain_name varchar NOT NULL,
|
||||||
|
certificate blob NOT NULL,
|
||||||
|
privkey blob NOT NULL
|
||||||
|
);
|
||||||
@ -112,6 +112,7 @@ pub fn provide_beacon_resources() {
|
|||||||
|
|
||||||
#[component]
|
#[component]
|
||||||
pub fn BeaconView() -> impl IntoView {
|
pub fn BeaconView() -> impl IntoView {
|
||||||
|
#[cfg(feature = "hydrate")]
|
||||||
Effect::new(move || {
|
Effect::new(move || {
|
||||||
let user = expect_context::<ReadSignal<Option<crate::users::User>>>();
|
let user = expect_context::<ReadSignal<Option<crate::users::User>>>();
|
||||||
if user.get().is_none() {
|
if user.get().is_none() {
|
||||||
|
|||||||
@ -101,7 +101,6 @@ pub async fn rename_category(id: i64, name: String) -> Result<(), ServerFnError>
|
|||||||
pub fn CategoriesView() -> impl IntoView {
|
pub fn CategoriesView() -> impl IntoView {
|
||||||
let BeaconResources { add_category, categories, .. } = expect_context();
|
let BeaconResources { add_category, categories, .. } = expect_context();
|
||||||
|
|
||||||
|
|
||||||
view! {
|
view! {
|
||||||
<div class="categories">
|
<div class="categories">
|
||||||
<h2>"Categories"</h2>
|
<h2>"Categories"</h2>
|
||||||
|
|||||||
@ -71,6 +71,17 @@ pub async fn get_listeners() -> Result<Vec<PubListener>, ServerFnError> {
|
|||||||
.collect())
|
.collect())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "ssr")]
|
||||||
|
pub fn generate_cert_from_keypair(kp: &rcgen::KeyPair, names: Vec<String>) -> Result<rcgen::Certificate, rcgen::Error> {
|
||||||
|
use rcgen::CertificateParams;
|
||||||
|
|
||||||
|
let mut params = CertificateParams::new(names)?;
|
||||||
|
|
||||||
|
params.is_ca = rcgen::IsCa::Ca(rcgen::BasicConstraints::Unconstrained);
|
||||||
|
|
||||||
|
params.self_signed(&kp)
|
||||||
|
}
|
||||||
|
|
||||||
#[server]
|
#[server]
|
||||||
pub async fn add_listener(public_ip: String, port: i16, domain_name: String) -> Result<(), ServerFnError> {
|
pub async fn add_listener(public_ip: String, port: i16, domain_name: String) -> Result<(), ServerFnError> {
|
||||||
let user = user::get_auth_session().await?;
|
let user = user::get_auth_session().await?;
|
||||||
@ -84,15 +95,19 @@ pub async fn add_listener(public_ip: String, port: i16, domain_name: String) ->
|
|||||||
}
|
}
|
||||||
|
|
||||||
let subject_alt_names = vec![public_ip.to_string(), domain_name.clone()];
|
let subject_alt_names = vec![public_ip.to_string(), domain_name.clone()];
|
||||||
let CertifiedKey { cert, key_pair } = tokio::task::spawn_blocking(|| {
|
|
||||||
generate_simple_self_signed(subject_alt_names)
|
|
||||||
|
let (key_pair, cert) = tokio::task::spawn_blocking(|| {
|
||||||
|
rcgen::KeyPair::generate_for(&rcgen::PKCS_ECDSA_P256_SHA256)
|
||||||
|
.and_then(|keypair|
|
||||||
|
generate_cert_from_keypair(&keypair, subject_alt_names).map(|cert| (keypair, cert)))
|
||||||
}).await??;
|
}).await??;
|
||||||
|
|
||||||
let db = expect_context::<SqlitePool>();
|
let db = expect_context::<SqlitePool>();
|
||||||
|
|
||||||
let public_ip = public_ip.to_string();
|
let public_ip = public_ip.to_string();
|
||||||
let cert = cert.pem().to_string();
|
let cert = cert.der().to_vec();
|
||||||
let key_pair = key_pair.serialize_pem().to_string();
|
let key_pair = key_pair.serialize_der();
|
||||||
|
|
||||||
sqlx::query!(
|
sqlx::query!(
|
||||||
"INSERT INTO beacon_listener (port, public_ip, domain_name, certificate, privkey) VALUES (?, ?, ?, ?, ?)",
|
"INSERT INTO beacon_listener (port, public_ip, domain_name, certificate, privkey) VALUES (?, ?, ?, ?, ?)",
|
||||||
@ -116,23 +131,32 @@ pub async fn remove_listener(listener_id: i64) -> Result<(), ServerFnError> {
|
|||||||
return Err(ServerFnError::<NoCustomError>::ServerError("You are not signed in!".to_owned()));
|
return Err(ServerFnError::<NoCustomError>::ServerError("You are not signed in!".to_owned()));
|
||||||
}
|
}
|
||||||
|
|
||||||
let pool = expect_context::<SqlitePool>();
|
{
|
||||||
let blm = expect_context::<BeaconListenerMap>();
|
let blm = expect_context::<BeaconListenerMap>();
|
||||||
|
|
||||||
let Ok(mut blm_handle) = blm.write() else {
|
let Ok(mut blm_handle) = blm.write() else {
|
||||||
return Err(ServerFnError::<NoCustomError>::ServerError("Failed to get write handle for beacon listener map".to_owned()));
|
return Err(ServerFnError::<NoCustomError>::ServerError("Failed to get write handle for beacon listener map".to_owned()));
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some(mut bl) = blm_handle.get_mut(&listener_id) {
|
if let Some(bl) = blm_handle.get_mut(&listener_id) {
|
||||||
bl.abort();
|
bl.abort();
|
||||||
} else {
|
} else {
|
||||||
return Err(ServerFnError::<NoCustomError>::ServerError("Failed to get write handle for beacon listener map".to_owned()));
|
return Err(ServerFnError::<NoCustomError>::ServerError("Failed to get write handle for beacon listener map".to_owned()));
|
||||||
|
}
|
||||||
|
|
||||||
|
blm_handle.remove(&listener_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
blm_handle.remove(&listener_id);
|
let pool = expect_context::<SqlitePool>();
|
||||||
drop(blm_handle);
|
|
||||||
|
|
||||||
unimplemented!()
|
sqlx::query!(
|
||||||
|
"DELETE FROM beacon_listener WHERE listener_id = ?",
|
||||||
|
listener_id
|
||||||
|
)
|
||||||
|
.execute(&pool)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[server]
|
#[server]
|
||||||
|
|||||||
@ -103,6 +103,34 @@ pub async fn add_template(
|
|||||||
|
|
||||||
let db = expect_context::<SqlitePool>();
|
let db = expect_context::<SqlitePool>();
|
||||||
|
|
||||||
|
let listener = sqlx::query!(
|
||||||
|
"SELECT certificate, privkey FROM beacon_listener WHERE listener_id = ?",
|
||||||
|
listener_id
|
||||||
|
)
|
||||||
|
.fetch_one(&db)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
use rcgen::{Certificate, CertificateParams, KeyPair};
|
||||||
|
|
||||||
|
let keypair = KeyPair::from_der_and_sign_algo(
|
||||||
|
match &rustls_pki_types::PrivateKeyDer::try_from(&*listener.privkey) {
|
||||||
|
Ok(pk) => pk,
|
||||||
|
Err(e) => {
|
||||||
|
srverr!("Could not parse private key: {e}");
|
||||||
|
}
|
||||||
|
},
|
||||||
|
&rcgen::PKCS_ECDSA_P256_SHA256
|
||||||
|
)?;
|
||||||
|
let ca_params = CertificateParams::from_ca_cert_der(&(*listener.certificate).into())?;
|
||||||
|
let ca_cert = ca_params.self_signed(&keypair)?;
|
||||||
|
|
||||||
|
let client_key = KeyPair::generate()?;
|
||||||
|
let client_params = CertificateParams::default();
|
||||||
|
let client_cert = client_params.signed_by(&client_key, &ca_cert, &keypair)?;
|
||||||
|
|
||||||
|
let client_key_der = client_key.serialize_der();
|
||||||
|
let client_cert_der = client_cert.der().to_vec();
|
||||||
|
|
||||||
match &*source_mode {
|
match &*source_mode {
|
||||||
"host" => {
|
"host" => {
|
||||||
let source_mac = Some(source_mac).filter(|mac| mac != "00:00:00:00:00:00");
|
let source_mac = Some(source_mac).filter(|mac| mac != "00:00:00:00:00:00");
|
||||||
@ -110,16 +138,18 @@ pub async fn add_template(
|
|||||||
|
|
||||||
sqlx::query!(
|
sqlx::query!(
|
||||||
r"INSERT INTO beacon_template
|
r"INSERT INTO beacon_template
|
||||||
(template_name, operating_system, config_id, listener_id, source_ip, source_mac, source_mode, default_category)
|
(template_name, operating_system, config_id, listener_id, source_ip, source_mac, source_mode, default_category, client_key, client_cert)
|
||||||
VALUES
|
VALUES
|
||||||
(?, ?, ?, ?, ?, ?, 'host', ?)",
|
(?, ?, ?, ?, ?, ?, 'host', ?, ?, ?)",
|
||||||
template_name,
|
template_name,
|
||||||
operating_system,
|
operating_system,
|
||||||
config_id,
|
config_id,
|
||||||
listener_id,
|
listener_id,
|
||||||
source_ip,
|
source_ip,
|
||||||
source_mac,
|
source_mac,
|
||||||
default_category
|
default_category,
|
||||||
|
client_key_der,
|
||||||
|
client_cert_der
|
||||||
)
|
)
|
||||||
.execute(&db)
|
.execute(&db)
|
||||||
.await?;
|
.await?;
|
||||||
@ -132,9 +162,9 @@ pub async fn add_template(
|
|||||||
|
|
||||||
sqlx::query!(
|
sqlx::query!(
|
||||||
r"INSERT INTO beacon_template
|
r"INSERT INTO beacon_template
|
||||||
(template_name, operating_system, config_id, listener_id, source_ip, source_mac, source_mode, source_netmask, source_gateway, default_category)
|
(template_name, operating_system, config_id, listener_id, source_ip, source_mac, source_mode, source_netmask, source_gateway, default_category, client_key, client_cert)
|
||||||
VALUES
|
VALUES
|
||||||
(?, ?, ?, ?, ?, ?, 'host', ?, ?, ?)",
|
(?, ?, ?, ?, ?, ?, 'host', ?, ?, ?, ?, ?)",
|
||||||
template_name,
|
template_name,
|
||||||
operating_system,
|
operating_system,
|
||||||
config_id,
|
config_id,
|
||||||
@ -143,7 +173,9 @@ pub async fn add_template(
|
|||||||
source_mac,
|
source_mac,
|
||||||
source_netmask,
|
source_netmask,
|
||||||
source_gateway,
|
source_gateway,
|
||||||
default_category
|
default_category,
|
||||||
|
client_key_der,
|
||||||
|
client_cert_der
|
||||||
)
|
)
|
||||||
.execute(&db)
|
.execute(&db)
|
||||||
.await?;
|
.await?;
|
||||||
@ -376,9 +408,13 @@ pub fn DisplayTemplates(
|
|||||||
")"
|
")"
|
||||||
</h4>
|
</h4>
|
||||||
<div>
|
<div>
|
||||||
<button>
|
<a
|
||||||
|
class="button"
|
||||||
|
download=""
|
||||||
|
href=format!("/installer/{}", template.template_id)
|
||||||
|
>
|
||||||
"Download installer"
|
"Download installer"
|
||||||
</button>
|
</a>
|
||||||
<button
|
<button
|
||||||
on:click={
|
on:click={
|
||||||
let template_id = template.template_id;
|
let template_id = template.template_id;
|
||||||
@ -386,6 +422,7 @@ pub fn DisplayTemplates(
|
|||||||
remove_template.dispatch(RemoveTemplate { template_id });
|
remove_template.dispatch(RemoveTemplate { template_id });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
class="warning"
|
||||||
>
|
>
|
||||||
"Delete template"
|
"Delete template"
|
||||||
</button>
|
</button>
|
||||||
|
|||||||
@ -10,6 +10,7 @@ pub enum Error {
|
|||||||
Pbkdf2(pbkdf2::password_hash::errors::Error),
|
Pbkdf2(pbkdf2::password_hash::errors::Error),
|
||||||
#[cfg(feature = "ssr")]
|
#[cfg(feature = "ssr")]
|
||||||
Io(std::io::Error),
|
Io(std::io::Error),
|
||||||
|
AddrParse(std::net::AddrParseError),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::fmt::Display for Error {
|
impl std::fmt::Display for Error {
|
||||||
@ -37,6 +38,9 @@ impl std::fmt::Display for Error {
|
|||||||
Error::Io(err) => {
|
Error::Io(err) => {
|
||||||
write!(f, "io error: {err:?}")
|
write!(f, "io error: {err:?}")
|
||||||
}
|
}
|
||||||
|
Error::AddrParse(err) => {
|
||||||
|
write!(f, "ip address parse error: {err:?}")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -50,11 +54,23 @@ impl std::error::Error for Error {
|
|||||||
Error::TokioJoin(err) => Some(err),
|
Error::TokioJoin(err) => Some(err),
|
||||||
#[cfg(feature = "ssr")]
|
#[cfg(feature = "ssr")]
|
||||||
Error::Io(err) => Some(err),
|
Error::Io(err) => Some(err),
|
||||||
|
Error::AddrParse(err) => Some(err),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "ssr")]
|
||||||
|
impl axum::response::IntoResponse for Error {
|
||||||
|
fn into_response(self) -> axum::response::Response {
|
||||||
|
(
|
||||||
|
axum::http::StatusCode::INTERNAL_SERVER_ERROR,
|
||||||
|
format!("{:?}", self),
|
||||||
|
)
|
||||||
|
.into_response()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl std::str::FromStr for Error {
|
impl std::str::FromStr for Error {
|
||||||
type Err = Self;
|
type Err = Self;
|
||||||
|
|
||||||
@ -90,3 +106,9 @@ impl From<std::io::Error> for Error {
|
|||||||
Self::Io(err)
|
Self::Io(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<std::net::AddrParseError> for Error {
|
||||||
|
fn from(err: std::net::AddrParseError) -> Self {
|
||||||
|
Self::AddrParse(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -1,19 +1,3 @@
|
|||||||
#[cfg(feature = "hydrate")]
|
|
||||||
pub(crate) mod beacon_binaries {
|
|
||||||
#[allow(dead_code)]
|
|
||||||
pub const LINUX_BEACON: &'static [u8] = include_bytes!(std::env!("SPARSE_BEACON_LINUX"));
|
|
||||||
#[allow(dead_code)]
|
|
||||||
pub const FREEBSD_BEACON: &'static [u8] = include_bytes!(std::env!("SPARSE_BEACON_FREEBSD"));
|
|
||||||
#[allow(dead_code)]
|
|
||||||
pub const WINDOWS_BEACON: &'static [u8] = include_bytes!(std::env!("SPARSE_BEACON_WINDOWS"));
|
|
||||||
|
|
||||||
#[allow(dead_code)]
|
|
||||||
pub const LINUX_INSTALLER: &'static [u8] = include_bytes!(std::env!("SPARSE_INSTALLER_LINUX"));
|
|
||||||
#[allow(dead_code)]
|
|
||||||
pub const FREEBSD_INSTALLER: &'static [u8] = include_bytes!(std::env!("SPARSE_INSTALLER_FREEBSD"));
|
|
||||||
#[allow(dead_code)]
|
|
||||||
pub const WINDOWS_INSTALLER: &'static [u8] = include_bytes!(std::env!("SPARSE_INSTALLER_WINDOWS"));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "ssr")]
|
#[cfg(feature = "ssr")]
|
||||||
mod cli;
|
mod cli;
|
||||||
@ -29,6 +13,7 @@ pub mod db;
|
|||||||
#[cfg(feature = "ssr")]
|
#[cfg(feature = "ssr")]
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
async fn main() -> anyhow::Result<std::process::ExitCode> {
|
async fn main() -> anyhow::Result<std::process::ExitCode> {
|
||||||
|
|
||||||
use std::{path::PathBuf, process::ExitCode, str::FromStr};
|
use std::{path::PathBuf, process::ExitCode, str::FromStr};
|
||||||
|
|
||||||
use structopt::StructOpt;
|
use structopt::StructOpt;
|
||||||
@ -38,7 +23,7 @@ async fn main() -> anyhow::Result<std::process::ExitCode> {
|
|||||||
tracing_subscriber::registry()
|
tracing_subscriber::registry()
|
||||||
.with(
|
.with(
|
||||||
tracing_subscriber::EnvFilter::try_from_default_env()
|
tracing_subscriber::EnvFilter::try_from_default_env()
|
||||||
.unwrap_or_else(|_| format!("{}=debug,sparse_handler=debug,tower_http=trace", env!("CARGO_CRATE_NAME")).into()),
|
.unwrap_or_else(|_| format!("{}=debug,sparse_handler=debug", env!("CARGO_CRATE_NAME")).into()),
|
||||||
)
|
)
|
||||||
.with(tracing_subscriber::fmt::layer())
|
.with(tracing_subscriber::fmt::layer())
|
||||||
.init();
|
.init();
|
||||||
|
|||||||
@ -1,13 +1,167 @@
|
|||||||
use std::{net::SocketAddrV4, process::ExitCode};
|
use std::{net::SocketAddrV4, process::ExitCode};
|
||||||
|
|
||||||
use sqlx::sqlite::SqlitePool;
|
use sqlx::sqlite::SqlitePool;
|
||||||
use axum::Router;
|
use axum::{extract::{FromRef, Path, State}, response::IntoResponse, Router, routing::get};
|
||||||
use leptos::prelude::*;
|
use leptos::prelude::*;
|
||||||
use leptos_axum::{generate_route_list, LeptosRoutes};
|
use leptos_axum::{generate_route_list, LeptosRoutes};
|
||||||
use tokio::signal;
|
use tokio::signal;
|
||||||
|
|
||||||
use sparse_server::app::*;
|
use sparse_server::app::*;
|
||||||
|
|
||||||
|
#[cfg(not(debug_assertions))]
|
||||||
|
pub(crate) mod beacon_binaries {
|
||||||
|
pub const LINUX_INSTALLER: &'static [u8] = include_bytes!(std::env!("SPARSE_INSTALLER_LINUX"));
|
||||||
|
pub const FREEBSD_INSTALLER: &'static [u8] = include_bytes!(std::env!("SPARSE_INSTALLER_FREEBSD"));
|
||||||
|
pub const WINDOWS_INSTALLER: &'static [u8] = include_bytes!(std::env!("SPARSE_INSTALLER_WINDOWS"));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(debug_assertions)]
|
||||||
|
pub async fn get_installer(btype: &str) -> Result<Vec<u8>, crate::error::Error> {
|
||||||
|
let path = match btype {
|
||||||
|
"linux" => "target/x86_64-unknown-linux-musl/debug/sparse-unix-installer",
|
||||||
|
"freebsd" => "target/x86_64-unknown-freebsd/debug/sparse-unix-installer",
|
||||||
|
"windows" => "target/x86_64-pc-windows-gnu/debug/sparse-unix-installer",
|
||||||
|
other => return Err(crate::error::Error::Generic(format!("unknown beacon type: {other}"))),
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(tokio::fs::read(path).await?)
|
||||||
|
}
|
||||||
|
#[cfg(not(debug_assertions))]
|
||||||
|
pub async fn get_installer(btype: &str) -> Result<Vec<u8>, crate::error::Error> {
|
||||||
|
match btype {
|
||||||
|
"linux" => Ok(beacon_binaries::LINUX_INSTALLER.to_owned()),
|
||||||
|
"windows" => Ok(beacon_binaries::WINDOWS_INSTALLER.to_owned()),
|
||||||
|
"freebsd" => Ok(beacon_binaries::FREEBSD_INSTALLER.to_owned()),
|
||||||
|
other => Err(crate::error::Error::Generic(format!("unknown beacon type: {other}")))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(FromRef, Clone, Debug)]
|
||||||
|
pub struct AppState {
|
||||||
|
db: SqlitePool,
|
||||||
|
leptos_options: leptos::config::LeptosOptions
|
||||||
|
}
|
||||||
|
|
||||||
|
#[axum::debug_handler]
|
||||||
|
pub async fn download_beacon_installer(
|
||||||
|
Path(template_id): Path<i64>,
|
||||||
|
State(db): State<AppState>
|
||||||
|
) -> Result<impl IntoResponse, crate::error::Error> {
|
||||||
|
use rand::{rngs::OsRng, TryRngCore};
|
||||||
|
use sparse_actions::payload_types::Parameters_t;
|
||||||
|
|
||||||
|
let mut parameters_buffer = vec![0u8; std::mem::size_of::<Parameters_t>()];
|
||||||
|
//let _ = OsRng.try_fill_bytes(&mut parameters_buffer);
|
||||||
|
|
||||||
|
let parameters: &mut Parameters_t = unsafe { std::mem::transmute(parameters_buffer.as_mut_ptr()) };
|
||||||
|
|
||||||
|
let template = sqlx::query!(
|
||||||
|
r"SELECT operating_system, source_ip, source_mac, source_mode, source_netmask,
|
||||||
|
source_gateway, port, public_ip, domain_name, certificate, client_cert, client_key
|
||||||
|
FROM beacon_template JOIN beacon_listener"
|
||||||
|
)
|
||||||
|
.fetch_one(&db.db)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
let dest_ip = template.public_ip.parse::<std::net::Ipv4Addr>()?;
|
||||||
|
let src_ip = template.source_ip.parse::<std::net::Ipv4Addr>()?;
|
||||||
|
|
||||||
|
let dest_octets = dest_ip.octets();
|
||||||
|
parameters.destination_ip.a = dest_octets[0];
|
||||||
|
parameters.destination_ip.b = dest_octets[1];
|
||||||
|
parameters.destination_ip.c = dest_octets[2];
|
||||||
|
parameters.destination_ip.d = dest_octets[3];
|
||||||
|
|
||||||
|
let src_mac: [u8; 6] = template
|
||||||
|
.source_mac
|
||||||
|
.unwrap_or("00:00:00:00:00:00".to_string())
|
||||||
|
.split(":")
|
||||||
|
.map(|by| u8::from_str_radix(by, 16))
|
||||||
|
.collect::<Result<Vec<u8>, _>>()
|
||||||
|
.map_err(|_| crate::error::Error::Generic("Could not parse source MAC address".to_string()))
|
||||||
|
.and_then(
|
||||||
|
|bytes| bytes.try_into().map_err(|_| crate::error::Error::Generic("Could not parse source MAC address".to_string()))
|
||||||
|
)?;
|
||||||
|
|
||||||
|
let src_octets = src_ip.octets();
|
||||||
|
match (template.source_mode.as_deref(), template.source_netmask, template.source_gateway) {
|
||||||
|
(Some("custom"), Some(nm), Some(ip)) => unsafe {
|
||||||
|
let gateway = ip.parse::<std::net::Ipv4Addr>()?;
|
||||||
|
let gw_octets = gateway.octets();
|
||||||
|
|
||||||
|
parameters.source_ip.custom_networking.mode = 0;
|
||||||
|
parameters.source_ip.custom_networking.source_mac.copy_from_slice(&src_mac[..]);
|
||||||
|
parameters.source_ip.custom_networking.netmask = nm as u16;
|
||||||
|
parameters.source_ip.custom_networking.source_ip.a = src_octets[0];
|
||||||
|
parameters.source_ip.custom_networking.source_ip.b = src_octets[1];
|
||||||
|
parameters.source_ip.custom_networking.source_ip.c = src_octets[2];
|
||||||
|
parameters.source_ip.custom_networking.source_ip.d = src_octets[3];
|
||||||
|
parameters.source_ip.custom_networking.gateway.a = gw_octets[0];
|
||||||
|
parameters.source_ip.custom_networking.gateway.b = gw_octets[1];
|
||||||
|
parameters.source_ip.custom_networking.gateway.c = gw_octets[2];
|
||||||
|
parameters.source_ip.custom_networking.gateway.d = gw_octets[3];
|
||||||
|
}
|
||||||
|
(Some("host"), _, _) => unsafe {
|
||||||
|
parameters.source_ip.use_host_networking.mode = 1;
|
||||||
|
parameters.source_ip.use_host_networking.source_mac.copy_from_slice(&src_mac[..]);
|
||||||
|
parameters.source_ip.use_host_networking.source_ip.a = src_octets[0];
|
||||||
|
parameters.source_ip.use_host_networking.source_ip.b = src_octets[1];
|
||||||
|
parameters.source_ip.use_host_networking.source_ip.c = src_octets[2];
|
||||||
|
parameters.source_ip.use_host_networking.source_ip.d = src_octets[3];
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
return Err(crate::error::Error::Generic("Could not parse host networking configuration".to_string()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
parameters.destination_port = template.port as u16;
|
||||||
|
parameters.template_id = template_id as u16;
|
||||||
|
|
||||||
|
let pubkey_cert = template.certificate;
|
||||||
|
parameters.pubkey_cert[..pubkey_cert.len()].copy_from_slice(&pubkey_cert[..]);
|
||||||
|
parameters.pubkey_cert_size = pubkey_cert.len() as u16;
|
||||||
|
|
||||||
|
let client_key = template.client_key;
|
||||||
|
parameters.client_key[..client_key.len()].copy_from_slice(&client_key[..]);
|
||||||
|
parameters.client_key_length = client_key.len() as u16;
|
||||||
|
|
||||||
|
let client_cert = template.client_cert;
|
||||||
|
parameters.client_cert[..client_cert.len()].copy_from_slice(&client_cert[..]);
|
||||||
|
parameters.client_cert_length = client_cert.len() as u16;
|
||||||
|
|
||||||
|
let domain_name = template.domain_name.as_bytes();
|
||||||
|
parameters.domain_name[..domain_name.len()].copy_from_slice(&domain_name[..]);
|
||||||
|
parameters.domain_name_length = domain_name.len() as u16;
|
||||||
|
|
||||||
|
let installer_bytes = get_installer(&template.operating_system).await?;
|
||||||
|
|
||||||
|
use axum::http::header;
|
||||||
|
|
||||||
|
Ok((
|
||||||
|
[
|
||||||
|
(
|
||||||
|
header::CONTENT_TYPE,
|
||||||
|
"application/octet-stream".to_string()
|
||||||
|
),
|
||||||
|
(
|
||||||
|
header::CONTENT_DISPOSITION,
|
||||||
|
format!(
|
||||||
|
r#"attachement; filename="sparse-installer{}""#,
|
||||||
|
if template.operating_system == "windows" {
|
||||||
|
".exe"
|
||||||
|
} else {
|
||||||
|
""
|
||||||
|
}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
],
|
||||||
|
[
|
||||||
|
&installer_bytes[..],
|
||||||
|
¶meters_buffer[..]
|
||||||
|
].concat()
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn serve_web(management_address: SocketAddrV4, db: SqlitePool) -> anyhow::Result<ExitCode> {
|
pub async fn serve_web(management_address: SocketAddrV4, db: SqlitePool) -> anyhow::Result<ExitCode> {
|
||||||
let conf = get_configuration(None).unwrap();
|
let conf = get_configuration(None).unwrap();
|
||||||
let leptos_options = conf.leptos_options;
|
let leptos_options = conf.leptos_options;
|
||||||
@ -22,9 +176,15 @@ pub async fn serve_web(management_address: SocketAddrV4, db: SqlitePool) -> anyh
|
|||||||
|
|
||||||
sparse_handler::start_all_listeners(beacon_listeners.clone(), db.clone()).await?;
|
sparse_handler::start_all_listeners(beacon_listeners.clone(), db.clone()).await?;
|
||||||
|
|
||||||
|
let state = AppState {
|
||||||
|
leptos_options: leptos_options.clone(),
|
||||||
|
db: db.clone()
|
||||||
|
};
|
||||||
|
|
||||||
let app = Router::new()
|
let app = Router::new()
|
||||||
|
.route("/installer/:template_id", get(download_beacon_installer))
|
||||||
.leptos_routes_with_context(
|
.leptos_routes_with_context(
|
||||||
&leptos_options,
|
&state,
|
||||||
routes,
|
routes,
|
||||||
move || {
|
move || {
|
||||||
provide_context(beacon_listeners.clone());
|
provide_context(beacon_listeners.clone());
|
||||||
@ -36,7 +196,7 @@ pub async fn serve_web(management_address: SocketAddrV4, db: SqlitePool) -> anyh
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
.fallback(leptos_axum::file_and_error_handler::<leptos::config::LeptosOptions, _>(shell))
|
.fallback(leptos_axum::file_and_error_handler::<leptos::config::LeptosOptions, _>(shell))
|
||||||
.with_state(leptos_options)
|
.with_state(state)
|
||||||
.layer(
|
.layer(
|
||||||
tower::ServiceBuilder::new()
|
tower::ServiceBuilder::new()
|
||||||
.layer(tower_http::trace::TraceLayer::new_for_http())
|
.layer(tower_http::trace::TraceLayer::new_for_http())
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
main.beacons div.categories {
|
main.beacons div.categories {
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
|
overflow-y: scroll;
|
||||||
|
|
||||||
fieldset {
|
fieldset {
|
||||||
display: grid;
|
display: grid;
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
main.beacons div.config {
|
main.beacons div.config {
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
|
overflow-y: scroll;
|
||||||
|
|
||||||
fieldset {
|
fieldset {
|
||||||
display: grid;
|
display: grid;
|
||||||
|
|||||||
@ -1,4 +1,6 @@
|
|||||||
main.beacons div.listeners {
|
main.beacons div.listeners {
|
||||||
|
overflow-y: scroll;
|
||||||
|
|
||||||
form, p, h2 {
|
form, p, h2 {
|
||||||
margin: 10px;
|
margin: 10px;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
main.beacons div.templates {
|
main.beacons div.templates {
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
|
overflow-y: scroll;
|
||||||
|
|
||||||
fieldset {
|
fieldset {
|
||||||
display: grid;
|
display: grid;
|
||||||
|
|||||||
@ -70,7 +70,11 @@ main {
|
|||||||
|
|
||||||
input[type="submit"],
|
input[type="submit"],
|
||||||
input[type="button"],
|
input[type="button"],
|
||||||
button {
|
button,
|
||||||
|
a.button {
|
||||||
|
font-family: sans-serif;
|
||||||
|
font-size: 0.9rem;
|
||||||
|
color: black;
|
||||||
background-color: #fff;
|
background-color: #fff;
|
||||||
border: 1px solid black;
|
border: 1px solid black;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
@ -82,4 +86,13 @@ button {
|
|||||||
&:hover {
|
&:hover {
|
||||||
background-color: #ccc;
|
background-color: #ccc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&.warning {
|
||||||
|
background-color: #f00;
|
||||||
|
color: white;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: #c00;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -10,12 +10,12 @@ typedef struct {
|
|||||||
typedef union SourceIp {
|
typedef union SourceIp {
|
||||||
struct {
|
struct {
|
||||||
char mode; // set to 0
|
char mode; // set to 0
|
||||||
char source_mac[6];
|
unsigned char source_mac[6];
|
||||||
ipaddr_t source_ip;
|
ipaddr_t source_ip;
|
||||||
} use_host_networking;
|
} use_host_networking;
|
||||||
struct {
|
struct {
|
||||||
char mode; // set to 1
|
char mode; // set to 1
|
||||||
char source_mac[6];
|
unsigned char source_mac[6];
|
||||||
unsigned short netmask;
|
unsigned short netmask;
|
||||||
ipaddr_t source_ip;
|
ipaddr_t source_ip;
|
||||||
ipaddr_t gateway;
|
ipaddr_t gateway;
|
||||||
@ -27,12 +27,17 @@ typedef struct Parameters {
|
|||||||
SourceIp_t source_ip;
|
SourceIp_t source_ip;
|
||||||
unsigned short destination_port;
|
unsigned short destination_port;
|
||||||
unsigned short pubkey_cert_size;
|
unsigned short pubkey_cert_size;
|
||||||
unsigned short template_name_length;
|
|
||||||
unsigned short domain_name_length;
|
unsigned short domain_name_length;
|
||||||
unsigned short beacon_name_length;
|
unsigned short beacon_name_length;
|
||||||
char pubkey_cert[1024];
|
unsigned short client_key_length;
|
||||||
char beacon_identifier[64];
|
unsigned short client_cert_length;
|
||||||
char template_name[128];
|
unsigned short template_id;
|
||||||
char domain_name[128];
|
unsigned char delay_seconds_min;
|
||||||
char beacon_name[128];
|
unsigned char delay_seconds_max;
|
||||||
|
unsigned char pubkey_cert[512];
|
||||||
|
unsigned char client_key[256];
|
||||||
|
unsigned char client_cert[384];
|
||||||
|
unsigned char beacon_identifier[64];
|
||||||
|
unsigned char domain_name[64];
|
||||||
|
unsigned char beacon_name[128];
|
||||||
} Parameters_t;
|
} Parameters_t;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user