Add integration tests, do not show secret in logs
The code is restructured so that the library contains the actix-web code and the binary only does commandline parsing and running of the lib.
This commit is contained in:
parent
6fd36936a3
commit
ce315c429c
291
Cargo.lock
generated
291
Cargo.lock
generated
@ -897,6 +897,22 @@ version = "0.1.5"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a2df960f5d869b2dd8532793fde43eb5427cceb126c929747a26823ab0eeb536"
|
checksum = "a2df960f5d869b2dd8532793fde43eb5427cceb126c929747a26823ab0eeb536"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "core-foundation"
|
||||||
|
version = "0.9.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0a89e2ae426ea83155dccf10c0fa6b1463ef6d5fcb44cee0b224a408fa640a62"
|
||||||
|
dependencies = [
|
||||||
|
"core-foundation-sys",
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "core-foundation-sys"
|
||||||
|
version = "0.8.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ea221b5284a47e40033bf9b66f35f984ec0ea2931eb03505246cd27a963f981b"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cpuid-bool"
|
name = "cpuid-bool"
|
||||||
version = "0.1.2"
|
version = "0.1.2"
|
||||||
@ -1247,6 +1263,21 @@ version = "1.0.7"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
|
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "foreign-types"
|
||||||
|
version = "0.3.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1"
|
||||||
|
dependencies = [
|
||||||
|
"foreign-types-shared",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "foreign-types-shared"
|
||||||
|
version = "0.1.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "form_urlencoded"
|
name = "form_urlencoded"
|
||||||
version = "1.0.1"
|
version = "1.0.1"
|
||||||
@ -1625,12 +1656,28 @@ dependencies = [
|
|||||||
"itoa",
|
"itoa",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "http-body"
|
||||||
|
version = "0.3.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "13d5ff830006f7646652e057693569bfe0d51760c0085a071769d142a205111b"
|
||||||
|
dependencies = [
|
||||||
|
"bytes 0.5.6",
|
||||||
|
"http",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "httparse"
|
name = "httparse"
|
||||||
version = "1.3.6"
|
version = "1.3.6"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "bc35c995b9d93ec174cf9a27d425c7892722101e14993cd227fdb51d70cf9589"
|
checksum = "bc35c995b9d93ec174cf9a27d425c7892722101e14993cd227fdb51d70cf9589"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "httpdate"
|
||||||
|
version = "0.3.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "494b4d60369511e7dea41cf646832512a94e542f68bb9c49e54518e0f468eb47"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "humansize"
|
name = "humansize"
|
||||||
version = "1.1.0"
|
version = "1.1.0"
|
||||||
@ -1646,6 +1693,43 @@ dependencies = [
|
|||||||
"quick-error",
|
"quick-error",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hyper"
|
||||||
|
version = "0.13.10"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8a6f157065790a3ed2f88679250419b5cdd96e714a0d65f7797fd337186e96bb"
|
||||||
|
dependencies = [
|
||||||
|
"bytes 0.5.6",
|
||||||
|
"futures-channel",
|
||||||
|
"futures-core",
|
||||||
|
"futures-util",
|
||||||
|
"h2",
|
||||||
|
"http",
|
||||||
|
"http-body",
|
||||||
|
"httparse",
|
||||||
|
"httpdate",
|
||||||
|
"itoa",
|
||||||
|
"pin-project 1.0.6",
|
||||||
|
"socket2",
|
||||||
|
"tokio",
|
||||||
|
"tower-service",
|
||||||
|
"tracing",
|
||||||
|
"want",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hyper-tls"
|
||||||
|
version = "0.4.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d979acc56dcb5b8dddba3917601745e877576475aa046df3226eabdecef78eed"
|
||||||
|
dependencies = [
|
||||||
|
"bytes 0.5.6",
|
||||||
|
"hyper",
|
||||||
|
"native-tls",
|
||||||
|
"tokio",
|
||||||
|
"tokio-tls",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "idna"
|
name = "idna"
|
||||||
version = "0.2.2"
|
version = "0.2.2"
|
||||||
@ -1757,9 +1841,15 @@ dependencies = [
|
|||||||
"socket2",
|
"socket2",
|
||||||
"widestring",
|
"widestring",
|
||||||
"winapi 0.3.9",
|
"winapi 0.3.9",
|
||||||
"winreg",
|
"winreg 0.6.2",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ipnet"
|
||||||
|
version = "2.3.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "47be2f14c678be2fdcab04ab1171db51b2762ce6f0a8ee87c8dd4a04ed216135"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "itoa"
|
name = "itoa"
|
||||||
version = "0.4.7"
|
version = "0.4.7"
|
||||||
@ -2016,6 +2106,24 @@ dependencies = [
|
|||||||
"getrandom 0.2.2",
|
"getrandom 0.2.2",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "native-tls"
|
||||||
|
version = "0.2.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b8d96b2e1c8da3957d58100b09f102c6d9cfdfced01b7ec5a8974044bb09dbd4"
|
||||||
|
dependencies = [
|
||||||
|
"lazy_static",
|
||||||
|
"libc",
|
||||||
|
"log",
|
||||||
|
"openssl",
|
||||||
|
"openssl-probe",
|
||||||
|
"openssl-sys",
|
||||||
|
"schannel",
|
||||||
|
"security-framework",
|
||||||
|
"security-framework-sys",
|
||||||
|
"tempfile",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "net2"
|
name = "net2"
|
||||||
version = "0.2.37"
|
version = "0.2.37"
|
||||||
@ -2125,6 +2233,39 @@ version = "0.3.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5"
|
checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "openssl"
|
||||||
|
version = "0.10.33"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a61075b62a23fef5a29815de7536d940aa35ce96d18ce0cc5076272db678a577"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags",
|
||||||
|
"cfg-if 1.0.0",
|
||||||
|
"foreign-types",
|
||||||
|
"libc",
|
||||||
|
"once_cell",
|
||||||
|
"openssl-sys",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "openssl-probe"
|
||||||
|
version = "0.1.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "77af24da69f9d9341038eba93a073b1fdaaa1b788221b00a69bce9e762cb32de"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "openssl-sys"
|
||||||
|
version = "0.9.61"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "313752393519e876837e09e1fa183ddef0be7735868dced3196f4472d536277f"
|
||||||
|
dependencies = [
|
||||||
|
"autocfg 1.0.1",
|
||||||
|
"cc",
|
||||||
|
"libc",
|
||||||
|
"pkg-config",
|
||||||
|
"vcpkg",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "opentelemetry"
|
name = "opentelemetry"
|
||||||
version = "0.13.0"
|
version = "0.13.0"
|
||||||
@ -2433,6 +2574,7 @@ name = "pslink"
|
|||||||
version = "0.3.1"
|
version = "0.3.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"actix-identity",
|
"actix-identity",
|
||||||
|
"actix-rt",
|
||||||
"actix-slog",
|
"actix-slog",
|
||||||
"actix-web",
|
"actix-web",
|
||||||
"actix-web-static-files",
|
"actix-web-static-files",
|
||||||
@ -2448,10 +2590,13 @@ dependencies = [
|
|||||||
"opentelemetry-jaeger",
|
"opentelemetry-jaeger",
|
||||||
"qrcode",
|
"qrcode",
|
||||||
"rand 0.8.3",
|
"rand 0.8.3",
|
||||||
|
"reqwest",
|
||||||
"rpassword",
|
"rpassword",
|
||||||
"serde",
|
"serde",
|
||||||
"sqlx",
|
"sqlx",
|
||||||
|
"tempdir",
|
||||||
"tera",
|
"tera",
|
||||||
|
"test_bin",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
"tracing",
|
"tracing",
|
||||||
"tracing-actix-web",
|
"tracing-actix-web",
|
||||||
@ -2779,6 +2924,41 @@ dependencies = [
|
|||||||
"winapi 0.3.9",
|
"winapi 0.3.9",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "reqwest"
|
||||||
|
version = "0.10.10"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0718f81a8e14c4dbb3b34cf23dc6aaf9ab8a0dfec160c534b3dbca1aaa21f47c"
|
||||||
|
dependencies = [
|
||||||
|
"base64 0.13.0",
|
||||||
|
"bytes 0.5.6",
|
||||||
|
"encoding_rs",
|
||||||
|
"futures-core",
|
||||||
|
"futures-util",
|
||||||
|
"http",
|
||||||
|
"http-body",
|
||||||
|
"hyper",
|
||||||
|
"hyper-tls",
|
||||||
|
"ipnet",
|
||||||
|
"js-sys",
|
||||||
|
"lazy_static",
|
||||||
|
"log",
|
||||||
|
"mime",
|
||||||
|
"mime_guess",
|
||||||
|
"native-tls",
|
||||||
|
"percent-encoding",
|
||||||
|
"pin-project-lite 0.2.6",
|
||||||
|
"serde",
|
||||||
|
"serde_urlencoded",
|
||||||
|
"tokio",
|
||||||
|
"tokio-tls",
|
||||||
|
"url",
|
||||||
|
"wasm-bindgen",
|
||||||
|
"wasm-bindgen-futures",
|
||||||
|
"web-sys",
|
||||||
|
"winreg 0.7.0",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "resolv-conf"
|
name = "resolv-conf"
|
||||||
version = "0.7.0"
|
version = "0.7.0"
|
||||||
@ -2863,6 +3043,16 @@ dependencies = [
|
|||||||
"winapi-util",
|
"winapi-util",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "schannel"
|
||||||
|
version = "0.1.19"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8f05ba609c234e60bee0d547fe94a4c7e9da733d1c962cf6e59efa4cd9c8bc75"
|
||||||
|
dependencies = [
|
||||||
|
"lazy_static",
|
||||||
|
"winapi 0.3.9",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "scoped_threadpool"
|
name = "scoped_threadpool"
|
||||||
version = "0.1.9"
|
version = "0.1.9"
|
||||||
@ -2891,6 +3081,29 @@ dependencies = [
|
|||||||
"untrusted",
|
"untrusted",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "security-framework"
|
||||||
|
version = "2.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3670b1d2fdf6084d192bc71ead7aabe6c06aa2ea3fbd9cc3ac111fa5c2b1bd84"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags",
|
||||||
|
"core-foundation",
|
||||||
|
"core-foundation-sys",
|
||||||
|
"libc",
|
||||||
|
"security-framework-sys",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "security-framework-sys"
|
||||||
|
version = "2.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3676258fd3cfe2c9a0ec99ce3038798d847ce3e4bb17746373eb9f0f1ac16339"
|
||||||
|
dependencies = [
|
||||||
|
"core-foundation-sys",
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "semver"
|
name = "semver"
|
||||||
version = "0.9.0"
|
version = "0.9.0"
|
||||||
@ -3340,6 +3553,20 @@ dependencies = [
|
|||||||
"remove_dir_all",
|
"remove_dir_all",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tempfile"
|
||||||
|
version = "3.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "dac1c663cfc93810f88aed9b8941d48cabf856a1b111c29a40439018d870eb22"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if 1.0.0",
|
||||||
|
"libc",
|
||||||
|
"rand 0.8.3",
|
||||||
|
"redox_syscall",
|
||||||
|
"remove_dir_all",
|
||||||
|
"winapi 0.3.9",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tera"
|
name = "tera"
|
||||||
version = "1.7.0"
|
version = "1.7.0"
|
||||||
@ -3371,6 +3598,12 @@ dependencies = [
|
|||||||
"winapi-util",
|
"winapi-util",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "test_bin"
|
||||||
|
version = "0.3.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1937bab04b0bd0f2c19628d3408fb6dd78faf5aa60f4bdb03212507a9b7314ba"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "textwrap"
|
name = "textwrap"
|
||||||
version = "0.11.0"
|
version = "0.11.0"
|
||||||
@ -3518,6 +3751,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "6703a273949a90131b290be1fe7b039d0fc884aa1935860dfcbe056f28cd8092"
|
checksum = "6703a273949a90131b290be1fe7b039d0fc884aa1935860dfcbe056f28cd8092"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bytes 0.5.6",
|
"bytes 0.5.6",
|
||||||
|
"fnv",
|
||||||
"futures-core",
|
"futures-core",
|
||||||
"iovec",
|
"iovec",
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
@ -3556,6 +3790,16 @@ dependencies = [
|
|||||||
"webpki",
|
"webpki",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tokio-tls"
|
||||||
|
version = "0.3.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9a70f4fcd7b3b24fb194f837560168208f669ca8cb70d0c4b862944452396343"
|
||||||
|
dependencies = [
|
||||||
|
"native-tls",
|
||||||
|
"tokio",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tokio-util"
|
name = "tokio-util"
|
||||||
version = "0.3.1"
|
version = "0.3.1"
|
||||||
@ -3570,6 +3814,12 @@ dependencies = [
|
|||||||
"tokio",
|
"tokio",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tower-service"
|
||||||
|
version = "0.3.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "360dfd1d6d30e05fda32ace2c8c70e9c0a9da713275777f5a4dbb8a1893930c6"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tracing"
|
name = "tracing"
|
||||||
version = "0.1.25"
|
version = "0.1.25"
|
||||||
@ -3738,6 +3988,12 @@ dependencies = [
|
|||||||
"trust-dns-proto",
|
"trust-dns-proto",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "try-lock"
|
||||||
|
version = "0.2.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "type-map"
|
name = "type-map"
|
||||||
version = "0.4.0"
|
version = "0.4.0"
|
||||||
@ -3981,6 +4237,16 @@ dependencies = [
|
|||||||
"winapi-util",
|
"winapi-util",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "want"
|
||||||
|
version = "0.3.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1ce8a968cb1cd110d136ff8b819a556d6fb6d919363c61534f6860c7eb172ba0"
|
||||||
|
dependencies = [
|
||||||
|
"log",
|
||||||
|
"try-lock",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasi"
|
name = "wasi"
|
||||||
version = "0.9.0+wasi-snapshot-preview1"
|
version = "0.9.0+wasi-snapshot-preview1"
|
||||||
@ -4000,6 +4266,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "83240549659d187488f91f33c0f8547cbfef0b2088bc470c116d1d260ef623d9"
|
checksum = "83240549659d187488f91f33c0f8547cbfef0b2088bc470c116d1d260ef623d9"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if 1.0.0",
|
"cfg-if 1.0.0",
|
||||||
|
"serde",
|
||||||
|
"serde_json",
|
||||||
"wasm-bindgen-macro",
|
"wasm-bindgen-macro",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -4018,6 +4286,18 @@ dependencies = [
|
|||||||
"wasm-bindgen-shared",
|
"wasm-bindgen-shared",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wasm-bindgen-futures"
|
||||||
|
version = "0.4.23"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "81b8b767af23de6ac18bf2168b690bed2902743ddf0fb39252e36f9e2bfc63ea"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if 1.0.0",
|
||||||
|
"js-sys",
|
||||||
|
"wasm-bindgen",
|
||||||
|
"web-sys",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasm-bindgen-macro"
|
name = "wasm-bindgen-macro"
|
||||||
version = "0.2.73"
|
version = "0.2.73"
|
||||||
@ -4160,6 +4440,15 @@ dependencies = [
|
|||||||
"winapi 0.3.9",
|
"winapi 0.3.9",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "winreg"
|
||||||
|
version = "0.7.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0120db82e8a1e0b9fb3345a539c478767c0048d842860994d96113d5b667bd69"
|
||||||
|
dependencies = [
|
||||||
|
"winapi 0.3.9",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ws2_32-sys"
|
name = "ws2_32-sys"
|
||||||
version = "0.2.1"
|
version = "0.2.1"
|
||||||
|
99
Cargo.toml
99
Cargo.toml
@ -1,51 +1,68 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "pslink"
|
|
||||||
version = "0.3.1"
|
|
||||||
description = "A simple webservice that allows registered users to create short links including qr-codes.\nAnyone can visit the shortened links. This is an ideal setup for small busines or for publishing papers."
|
|
||||||
authors = ["Dietrich <dietrich@teilgedanken.de>"]
|
authors = ["Dietrich <dietrich@teilgedanken.de>"]
|
||||||
edition = "2018"
|
build = "build.rs"
|
||||||
license = "MIT OR Apache-2.0"
|
|
||||||
keywords = ["url", "link", "webpage", "actix", "web"]
|
|
||||||
categories = ["web-programming", "network-programming", "web-programming::http-server", "command-line-utilities"]
|
categories = ["web-programming", "network-programming", "web-programming::http-server", "command-line-utilities"]
|
||||||
|
description = "A simple webservice that allows registered users to create short links including qr-codes.\nAnyone can visit the shortened links. This is an ideal setup for small busines or for publishing papers."
|
||||||
|
edition = "2018"
|
||||||
|
keywords = ["url", "link", "webpage", "actix", "web"]
|
||||||
|
license = "MIT OR Apache-2.0"
|
||||||
|
name = "pslink"
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
repository = "https://github.com/enaut/pslink/"
|
repository = "https://github.com/enaut/pslink/"
|
||||||
build = "build.rs"
|
version = "0.3.1"
|
||||||
|
|
||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
|
||||||
|
|
||||||
[dependencies]
|
|
||||||
actix-web = "3"
|
|
||||||
actix-web-static-files = "3.0"
|
|
||||||
actix-slog = "0.2"
|
|
||||||
tera = "1.6"
|
|
||||||
serde = "1.0"
|
|
||||||
sqlx={version="0.4", features = [ "sqlite", "macros", "runtime-actix-rustls", "chrono", "migrate", "offline" ]}
|
|
||||||
dotenv = "0.15.0"
|
|
||||||
actix-identity = "0.3"
|
|
||||||
chrono = { version = "0.4", features = ["serde"] }
|
|
||||||
argonautica = "0.2"
|
|
||||||
tracing = { version = "0.1", features = ["log"] }
|
|
||||||
tracing-bunyan-formatter = "0.2.0"
|
|
||||||
tracing-subscriber = { version = "0.2.17", features = ["registry", "env-filter"] }
|
|
||||||
tracing-actix-web = "0.2.1"
|
|
||||||
tracing-opentelemetry = "0.12"
|
|
||||||
opentelemetry = "0.13"
|
|
||||||
opentelemetry-jaeger="0.12"
|
|
||||||
qrcode = "0.12"
|
|
||||||
image = "0.23"
|
|
||||||
rand="0.8"
|
|
||||||
rpassword = "5.0"
|
|
||||||
clap = "2.33"
|
|
||||||
fluent-templates = { version = "0.6", features = ["tera"] }
|
|
||||||
fluent-langneg = "0.13"
|
|
||||||
thiserror = "1.0"
|
|
||||||
anyhow = "1.0"
|
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
actix-web-static-files = "3.0"
|
actix-web-static-files = "3.0"
|
||||||
|
|
||||||
# optimize for size at cost of compilation speed.
|
[dependencies]
|
||||||
|
actix-identity = "0.3"
|
||||||
|
actix-rt = "1.1"
|
||||||
|
actix-slog = "0.2"
|
||||||
|
actix-web = "3"
|
||||||
|
actix-web-static-files = "3.0"
|
||||||
|
anyhow = "1.0"
|
||||||
|
argonautica = "0.2"
|
||||||
|
clap = "2.33"
|
||||||
|
dotenv = "0.15.0"
|
||||||
|
fluent-langneg = "0.13"
|
||||||
|
image = "0.23"
|
||||||
|
opentelemetry = "0.13"
|
||||||
|
opentelemetry-jaeger = "0.12"
|
||||||
|
qrcode = "0.12"
|
||||||
|
rand = "0.8"
|
||||||
|
rpassword = "5.0"
|
||||||
|
serde = "1.0"
|
||||||
|
tera = "1.6"
|
||||||
|
thiserror = "1.0"
|
||||||
|
tracing-actix-web = "0.2.1"
|
||||||
|
tracing-bunyan-formatter = "0.2.0"
|
||||||
|
tracing-opentelemetry = "0.12"
|
||||||
|
|
||||||
|
[dependencies.chrono]
|
||||||
|
features = ["serde"]
|
||||||
|
version = "0.4"
|
||||||
|
|
||||||
|
[dependencies.fluent-templates]
|
||||||
|
features = ["tera"]
|
||||||
|
version = "0.6"
|
||||||
|
|
||||||
|
[dependencies.sqlx]
|
||||||
|
features = ["sqlite", "macros", "runtime-actix-rustls", "chrono", "migrate", "offline"]
|
||||||
|
version = "0.4"
|
||||||
|
|
||||||
|
[dependencies.tracing]
|
||||||
|
features = ["log"]
|
||||||
|
version = "0.1"
|
||||||
|
|
||||||
|
[dependencies.tracing-subscriber]
|
||||||
|
features = ["registry", "env-filter"]
|
||||||
|
version = "0.2.17"
|
||||||
|
|
||||||
|
[dev-dependencies]
|
||||||
|
reqwest = "0.10.10"
|
||||||
|
tempdir = "0.3"
|
||||||
|
test_bin = "0.3"
|
||||||
|
|
||||||
|
[profile]
|
||||||
[profile.release]
|
[profile.release]
|
||||||
lto = true
|
lto = true #timize for size at cost of compilation speed.
|
||||||
#codegen-units = 1
|
#codegen-units = 1
|
@ -147,6 +147,7 @@ async fn parse_args_to_config(config: ArgMatches<'_>) -> ServerConfig {
|
|||||||
} else {
|
} else {
|
||||||
secret
|
secret
|
||||||
};
|
};
|
||||||
|
let secret = pslink::Secret::new(secret);
|
||||||
let db = config
|
let db = config
|
||||||
.value_of("database")
|
.value_of("database")
|
||||||
.expect(concat!(
|
.expect(concat!(
|
||||||
@ -219,9 +220,12 @@ pub(crate) async fn setup() -> Result<Option<crate::ServerConfig>, ServerError>
|
|||||||
))
|
))
|
||||||
.parse::<PathBuf>()
|
.parse::<PathBuf>()
|
||||||
.expect("Failed to parse Database path.");
|
.expect("Failed to parse Database path.");
|
||||||
|
|
||||||
if !db.exists() {
|
if !db.exists() {
|
||||||
trace!("No database file found {}", db.display());
|
trace!("No database file found {}", db.display());
|
||||||
if config.subcommand_matches("migrate-database").is_none() {
|
if !(config.subcommand_matches("migrate-database").is_none()
|
||||||
|
| config.subcommand_matches("generate-env").is_none())
|
||||||
|
{
|
||||||
let msg = format!(
|
let msg = format!(
|
||||||
concat!(
|
concat!(
|
||||||
"Database not found at {}!",
|
"Database not found at {}!",
|
||||||
@ -239,7 +243,6 @@ pub(crate) async fn setup() -> Result<Option<crate::ServerConfig>, ServerError>
|
|||||||
// create an empty database file. The if above makes sure that this file does not exist.
|
// create an empty database file. The if above makes sure that this file does not exist.
|
||||||
File::create(db)?;
|
File::create(db)?;
|
||||||
};
|
};
|
||||||
|
|
||||||
let server_config: crate::ServerConfig = parse_args_to_config(config.clone()).await;
|
let server_config: crate::ServerConfig = parse_args_to_config(config.clone()).await;
|
||||||
|
|
||||||
if let Some(_migrate_config) = config.subcommand_matches("generate-env") {
|
if let Some(_migrate_config) = config.subcommand_matches("generate-env") {
|
||||||
|
@ -1,20 +1,11 @@
|
|||||||
extern crate sqlx;
|
extern crate sqlx;
|
||||||
|
|
||||||
mod cli;
|
mod cli;
|
||||||
mod views;
|
|
||||||
|
|
||||||
use actix_identity::{CookieIdentityPolicy, IdentityService};
|
use pslink::ServerConfig;
|
||||||
use actix_web::{web, App, HttpServer};
|
|
||||||
use anyhow::{Context, Result};
|
|
||||||
use fluent_templates::{static_loader, FluentLoader};
|
|
||||||
use tera::Tera;
|
|
||||||
|
|
||||||
use pslink::{ServerConfig, ServerError};
|
|
||||||
|
|
||||||
use tracing::instrument;
|
use tracing::instrument;
|
||||||
use tracing::{error, info, trace};
|
|
||||||
use tracing::{subscriber::set_global_default, Subscriber};
|
use tracing::{subscriber::set_global_default, Subscriber};
|
||||||
use tracing_actix_web::TracingLogger;
|
|
||||||
use tracing_opentelemetry::OpenTelemetryLayer;
|
use tracing_opentelemetry::OpenTelemetryLayer;
|
||||||
use tracing_subscriber::{layer::SubscriberExt, EnvFilter, Registry};
|
use tracing_subscriber::{layer::SubscriberExt, EnvFilter, Registry};
|
||||||
|
|
||||||
@ -48,185 +39,24 @@ pub fn init_subscriber(subscriber: impl Subscriber + Send + Sync) {
|
|||||||
set_global_default(subscriber).expect("Failed to set subscriber");
|
set_global_default(subscriber).expect("Failed to set subscriber");
|
||||||
}
|
}
|
||||||
|
|
||||||
include!(concat!(env!("OUT_DIR"), "/generated.rs"));
|
|
||||||
|
|
||||||
static_loader! {
|
|
||||||
static LOCALES = {
|
|
||||||
locales: "./locales",
|
|
||||||
fallback_language: "en",
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
#[instrument]
|
|
||||||
fn build_tera() -> Result<Tera> {
|
|
||||||
let mut tera = Tera::default();
|
|
||||||
|
|
||||||
// Add translation support
|
|
||||||
tera.register_function("fluent", FluentLoader::new(&*LOCALES));
|
|
||||||
|
|
||||||
tera.add_raw_templates(vec![
|
|
||||||
("admin.html", include_str!("../../../templates/admin.html")),
|
|
||||||
("base.html", include_str!("../../../templates/base.html")),
|
|
||||||
(
|
|
||||||
"edit_link.html",
|
|
||||||
include_str!("../../../templates/edit_link.html"),
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"edit_profile.html",
|
|
||||||
include_str!("../../../templates/edit_profile.html"),
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"index_users.html",
|
|
||||||
include_str!("../../../templates/index_users.html"),
|
|
||||||
),
|
|
||||||
("index.html", include_str!("../../../templates/index.html")),
|
|
||||||
("login.html", include_str!("../../../templates/login.html")),
|
|
||||||
(
|
|
||||||
"not_found.html",
|
|
||||||
include_str!("../../../templates/not_found.html"),
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"signup.html",
|
|
||||||
include_str!("../../../templates/signup.html"),
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"submission.html",
|
|
||||||
include_str!("../../../templates/submission.html"),
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"view_link.html",
|
|
||||||
include_str!("../../../templates/view_link.html"),
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"view_profile.html",
|
|
||||||
include_str!("../../../templates/view_profile.html"),
|
|
||||||
),
|
|
||||||
])
|
|
||||||
.context("Failed to load Templates")?;
|
|
||||||
Ok(tera)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(clippy::future_not_send, clippy::too_many_lines)]
|
|
||||||
async fn webservice(server_config: ServerConfig) -> Result<()> {
|
|
||||||
let host_port = format!("{}:{}", &server_config.internal_ip, &server_config.port);
|
|
||||||
info!(
|
|
||||||
"Running on: {}://{}/admin/login/",
|
|
||||||
&server_config.protocol, host_port
|
|
||||||
);
|
|
||||||
info!(
|
|
||||||
"If the public url is set up correctly it should be accessible via: {}://{}/admin/login/",
|
|
||||||
&server_config.protocol, &server_config.public_url
|
|
||||||
);
|
|
||||||
let tera = build_tera()?;
|
|
||||||
trace!("The tera templates are ready");
|
|
||||||
|
|
||||||
HttpServer::new(move || {
|
|
||||||
let generated = generate();
|
|
||||||
App::new()
|
|
||||||
.data(server_config.clone())
|
|
||||||
.wrap(TracingLogger)
|
|
||||||
.wrap(IdentityService::new(
|
|
||||||
CookieIdentityPolicy::new(&[0; 32])
|
|
||||||
.name("auth-cookie")
|
|
||||||
.secure(false),
|
|
||||||
))
|
|
||||||
.data(tera.clone())
|
|
||||||
.service(actix_web_static_files::ResourceFiles::new(
|
|
||||||
"/static", generated,
|
|
||||||
))
|
|
||||||
// directly go to the main page set the target with the environment variable.
|
|
||||||
.route("/", web::get().to(views::redirect_empty))
|
|
||||||
// admin block
|
|
||||||
.service(
|
|
||||||
web::scope("/admin")
|
|
||||||
// list all links
|
|
||||||
.route("/index/", web::get().to(views::index))
|
|
||||||
// invite users
|
|
||||||
.route("/signup/", web::get().to(views::signup))
|
|
||||||
.route("/signup/", web::post().to(views::process_signup))
|
|
||||||
// logout
|
|
||||||
.route("/logout/", web::to(views::logout))
|
|
||||||
// submit a new url for shortening
|
|
||||||
.route("/submit/", web::get().to(views::create_link))
|
|
||||||
.route("/submit/", web::post().to(views::process_link_creation))
|
|
||||||
// view an existing url
|
|
||||||
.service(
|
|
||||||
web::scope("/view")
|
|
||||||
.service(
|
|
||||||
web::scope("/link")
|
|
||||||
.route("/{redirect_id}", web::get().to(views::view_link))
|
|
||||||
.route("/", web::get().to(views::view_link_empty)),
|
|
||||||
)
|
|
||||||
.service(
|
|
||||||
web::scope("/profile")
|
|
||||||
.route("/{user_id}", web::get().to(views::view_profile)),
|
|
||||||
)
|
|
||||||
.route("/users/", web::get().to(views::index_users)),
|
|
||||||
)
|
|
||||||
.service(
|
|
||||||
web::scope("/edit")
|
|
||||||
.service(
|
|
||||||
web::scope("/link")
|
|
||||||
.route("/{redirect_id}", web::get().to(views::edit_link))
|
|
||||||
.route(
|
|
||||||
"/{redirect_id}",
|
|
||||||
web::post().to(views::process_link_edit),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
.service(
|
|
||||||
web::scope("/profile")
|
|
||||||
.route("/{user_id}", web::get().to(views::edit_profile))
|
|
||||||
.route(
|
|
||||||
"/{user_id}",
|
|
||||||
web::post().to(views::process_edit_profile),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
.route("/set_admin/{user_id}", web::get().to(views::toggle_admin))
|
|
||||||
.route(
|
|
||||||
"/set_language/{language}",
|
|
||||||
web::get().to(views::set_language),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
.service(
|
|
||||||
web::scope("/delete").service(
|
|
||||||
web::scope("/link")
|
|
||||||
.route("/{redirect_id}", web::get().to(views::process_link_delete)),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
.service(
|
|
||||||
web::scope("/download")
|
|
||||||
.route("/png/{redirect_id}", web::get().to(views::download_png)),
|
|
||||||
)
|
|
||||||
// login to the admin area
|
|
||||||
.route("/login/", web::get().to(views::login))
|
|
||||||
.route("/login/", web::post().to(views::process_login)),
|
|
||||||
)
|
|
||||||
// redirect to the url hidden behind the code
|
|
||||||
.route("/{redirect_id}", web::get().to(views::redirect))
|
|
||||||
})
|
|
||||||
.bind(host_port)
|
|
||||||
.context("Failed to bind to port")
|
|
||||||
.map_err(|e| {
|
|
||||||
error!("Failed to bind to port!");
|
|
||||||
e
|
|
||||||
})?
|
|
||||||
.run()
|
|
||||||
.await
|
|
||||||
.context("Failed to run the webservice")
|
|
||||||
}
|
|
||||||
|
|
||||||
#[instrument]
|
#[instrument]
|
||||||
#[actix_web::main]
|
#[actix_web::main]
|
||||||
async fn main() -> std::result::Result<(), ServerError> {
|
async fn main() -> std::result::Result<(), std::io::Error> {
|
||||||
let subscriber = get_subscriber("fhs.li", "info");
|
let subscriber = get_subscriber("fhs.li", "info");
|
||||||
init_subscriber(subscriber);
|
init_subscriber(subscriber);
|
||||||
|
|
||||||
match cli::setup().await {
|
match cli::setup().await {
|
||||||
Ok(Some(server_config)) => webservice(server_config).await.map_err(|e| {
|
Ok(Some(server_config)) => {
|
||||||
println!("{:?}", e);
|
pslink::webservice(server_config)
|
||||||
std::thread::sleep(std::time::Duration::from_millis(100));
|
.await
|
||||||
std::process::exit(0);
|
.map_err(|e| {
|
||||||
}),
|
println!("{:?}", e);
|
||||||
|
std::thread::sleep(std::time::Duration::from_millis(100));
|
||||||
|
std::process::exit(0);
|
||||||
|
})
|
||||||
|
.expect("Failed to launch the service")
|
||||||
|
.await
|
||||||
|
}
|
||||||
Ok(None) => {
|
Ok(None) => {
|
||||||
std::thread::sleep(std::time::Duration::from_millis(100));
|
std::thread::sleep(std::time::Duration::from_millis(100));
|
||||||
std::process::exit(0);
|
std::process::exit(0);
|
||||||
|
208
src/lib.rs
208
src/lib.rs
@ -3,14 +3,21 @@ extern crate sqlx;
|
|||||||
pub mod forms;
|
pub mod forms;
|
||||||
pub mod models;
|
pub mod models;
|
||||||
pub mod queries;
|
pub mod queries;
|
||||||
|
mod views;
|
||||||
|
|
||||||
use std::{fmt::Display, path::PathBuf, str::FromStr};
|
use actix_identity::{CookieIdentityPolicy, IdentityService};
|
||||||
|
|
||||||
use actix_web::HttpResponse;
|
use actix_web::HttpResponse;
|
||||||
|
use actix_web::{web, App, HttpServer};
|
||||||
|
use fluent_templates::{static_loader, FluentLoader};
|
||||||
use qrcode::types::QrError;
|
use qrcode::types::QrError;
|
||||||
use sqlx::{Pool, Sqlite};
|
use sqlx::{Pool, Sqlite};
|
||||||
|
use std::{fmt::Display, path::PathBuf, str::FromStr};
|
||||||
|
use tera::Tera;
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
use tracing::instrument;
|
||||||
|
use tracing::{error, info, trace};
|
||||||
|
use tracing_actix_web::TracingLogger;
|
||||||
|
|
||||||
#[derive(Error, Debug)]
|
#[derive(Error, Debug)]
|
||||||
pub enum ServerError {
|
pub enum ServerError {
|
||||||
#[error("Failed to encrypt the password {0} - aborting!")]
|
#[error("Failed to encrypt the password {0} - aborting!")]
|
||||||
@ -148,9 +155,33 @@ impl FromStr for Protocol {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct Secret {
|
||||||
|
secret: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Secret {
|
||||||
|
#[must_use]
|
||||||
|
pub const fn new(secret: String) -> Self {
|
||||||
|
Self { secret }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::fmt::Debug for Secret {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
f.write_str("*****SECRET*****")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::fmt::Display for Secret {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
f.write_str("*****SECRET*****")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct ServerConfig {
|
pub struct ServerConfig {
|
||||||
pub secret: String,
|
pub secret: Secret,
|
||||||
pub db: PathBuf,
|
pub db: PathBuf,
|
||||||
pub db_pool: Pool<Sqlite>,
|
pub db_pool: Pool<Sqlite>,
|
||||||
pub public_url: String,
|
pub public_url: String,
|
||||||
@ -181,3 +212,172 @@ impl ServerConfig {
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
include!(concat!(env!("OUT_DIR"), "/generated.rs"));
|
||||||
|
|
||||||
|
static_loader! {
|
||||||
|
static LOCALES = {
|
||||||
|
locales: "./locales",
|
||||||
|
fallback_language: "en",
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[instrument]
|
||||||
|
fn build_tera() -> Result<Tera, ServerError> {
|
||||||
|
let mut tera = Tera::default();
|
||||||
|
|
||||||
|
// Add translation support
|
||||||
|
tera.register_function("fluent", FluentLoader::new(&*LOCALES));
|
||||||
|
|
||||||
|
tera.add_raw_templates(vec![
|
||||||
|
("admin.html", include_str!("../templates/admin.html")),
|
||||||
|
("base.html", include_str!("../templates/base.html")),
|
||||||
|
(
|
||||||
|
"edit_link.html",
|
||||||
|
include_str!("../templates/edit_link.html"),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"edit_profile.html",
|
||||||
|
include_str!("../templates/edit_profile.html"),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"index_users.html",
|
||||||
|
include_str!("../templates/index_users.html"),
|
||||||
|
),
|
||||||
|
("index.html", include_str!("../templates/index.html")),
|
||||||
|
("login.html", include_str!("../templates/login.html")),
|
||||||
|
(
|
||||||
|
"not_found.html",
|
||||||
|
include_str!("../templates/not_found.html"),
|
||||||
|
),
|
||||||
|
("signup.html", include_str!("../templates/signup.html")),
|
||||||
|
(
|
||||||
|
"submission.html",
|
||||||
|
include_str!("../templates/submission.html"),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"view_link.html",
|
||||||
|
include_str!("../templates/view_link.html"),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"view_profile.html",
|
||||||
|
include_str!("../templates/view_profile.html"),
|
||||||
|
),
|
||||||
|
])?;
|
||||||
|
Ok(tera)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Launch the pslink-webservice
|
||||||
|
///
|
||||||
|
/// # Errors
|
||||||
|
/// This produces a [`ServerError`] if:
|
||||||
|
/// * Tera failed to build its templates
|
||||||
|
/// * The server failed to bind to the designated port.
|
||||||
|
#[allow(clippy::future_not_send, clippy::too_many_lines)]
|
||||||
|
pub async fn webservice(
|
||||||
|
server_config: ServerConfig,
|
||||||
|
) -> Result<actix_web::dev::Server, ServerError> {
|
||||||
|
let host_port = format!("{}:{}", &server_config.internal_ip, &server_config.port);
|
||||||
|
info!(
|
||||||
|
"Running on: {}://{}/admin/login/",
|
||||||
|
&server_config.protocol, host_port
|
||||||
|
);
|
||||||
|
info!(
|
||||||
|
"If the public url is set up correctly it should be accessible via: {}://{}/admin/login/",
|
||||||
|
&server_config.protocol, &server_config.public_url
|
||||||
|
);
|
||||||
|
let tera = build_tera()?;
|
||||||
|
trace!("The tera templates are ready");
|
||||||
|
|
||||||
|
let server = HttpServer::new(move || {
|
||||||
|
let generated = generate();
|
||||||
|
App::new()
|
||||||
|
.data(server_config.clone())
|
||||||
|
.wrap(TracingLogger)
|
||||||
|
.wrap(IdentityService::new(
|
||||||
|
CookieIdentityPolicy::new(&[0; 32])
|
||||||
|
.name("auth-cookie")
|
||||||
|
.secure(false),
|
||||||
|
))
|
||||||
|
.data(tera.clone())
|
||||||
|
.service(actix_web_static_files::ResourceFiles::new(
|
||||||
|
"/static", generated,
|
||||||
|
))
|
||||||
|
// directly go to the main page set the target with the environment variable.
|
||||||
|
.route("/", web::get().to(views::redirect_empty))
|
||||||
|
// admin block
|
||||||
|
.service(
|
||||||
|
web::scope("/admin")
|
||||||
|
// list all links
|
||||||
|
.route("/index/", web::get().to(views::index))
|
||||||
|
// invite users
|
||||||
|
.route("/signup/", web::get().to(views::signup))
|
||||||
|
.route("/signup/", web::post().to(views::process_signup))
|
||||||
|
// logout
|
||||||
|
.route("/logout/", web::to(views::logout))
|
||||||
|
// submit a new url for shortening
|
||||||
|
.route("/submit/", web::get().to(views::create_link))
|
||||||
|
.route("/submit/", web::post().to(views::process_link_creation))
|
||||||
|
// view an existing url
|
||||||
|
.service(
|
||||||
|
web::scope("/view")
|
||||||
|
.service(
|
||||||
|
web::scope("/link")
|
||||||
|
.route("/{redirect_id}", web::get().to(views::view_link))
|
||||||
|
.route("/", web::get().to(views::view_link_empty)),
|
||||||
|
)
|
||||||
|
.service(
|
||||||
|
web::scope("/profile")
|
||||||
|
.route("/{user_id}", web::get().to(views::view_profile)),
|
||||||
|
)
|
||||||
|
.route("/users/", web::get().to(views::index_users)),
|
||||||
|
)
|
||||||
|
.service(
|
||||||
|
web::scope("/edit")
|
||||||
|
.service(
|
||||||
|
web::scope("/link")
|
||||||
|
.route("/{redirect_id}", web::get().to(views::edit_link))
|
||||||
|
.route(
|
||||||
|
"/{redirect_id}",
|
||||||
|
web::post().to(views::process_link_edit),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.service(
|
||||||
|
web::scope("/profile")
|
||||||
|
.route("/{user_id}", web::get().to(views::edit_profile))
|
||||||
|
.route(
|
||||||
|
"/{user_id}",
|
||||||
|
web::post().to(views::process_edit_profile),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.route("/set_admin/{user_id}", web::get().to(views::toggle_admin))
|
||||||
|
.route(
|
||||||
|
"/set_language/{language}",
|
||||||
|
web::get().to(views::set_language),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.service(
|
||||||
|
web::scope("/delete").service(
|
||||||
|
web::scope("/link")
|
||||||
|
.route("/{redirect_id}", web::get().to(views::process_link_delete)),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.service(
|
||||||
|
web::scope("/download")
|
||||||
|
.route("/png/{redirect_id}", web::get().to(views::download_png)),
|
||||||
|
)
|
||||||
|
// login to the admin area
|
||||||
|
.route("/login/", web::get().to(views::login))
|
||||||
|
.route("/login/", web::post().to(views::process_login)),
|
||||||
|
)
|
||||||
|
// redirect to the url hidden behind the code
|
||||||
|
.route("/{redirect_id}", web::get().to(views::redirect))
|
||||||
|
})
|
||||||
|
.bind(host_port)
|
||||||
|
.map_err(|e| {
|
||||||
|
error!("Failed to bind to port!");
|
||||||
|
e
|
||||||
|
})?
|
||||||
|
.run();
|
||||||
|
Ok(server)
|
||||||
|
}
|
||||||
|
@ -146,7 +146,7 @@ impl NewUser {
|
|||||||
|
|
||||||
let hash = Hasher::default()
|
let hash = Hasher::default()
|
||||||
.with_password(password)
|
.with_password(password)
|
||||||
.with_secret_key(secret)
|
.with_secret_key(&secret.secret)
|
||||||
.hash()?;
|
.hash()?;
|
||||||
|
|
||||||
Ok(hash)
|
Ok(hash)
|
||||||
|
@ -17,10 +17,10 @@ use queries::{authenticate, Role};
|
|||||||
use tera::{Context, Tera};
|
use tera::{Context, Tera};
|
||||||
use tracing::{info, instrument, trace, warn};
|
use tracing::{info, instrument, trace, warn};
|
||||||
|
|
||||||
use pslink::forms::LinkForm;
|
use crate::forms::LinkForm;
|
||||||
use pslink::models::{LoginUser, NewUser};
|
use crate::models::{LoginUser, NewUser};
|
||||||
use pslink::queries;
|
use crate::queries;
|
||||||
use pslink::ServerError;
|
use crate::ServerError;
|
||||||
|
|
||||||
#[instrument]
|
#[instrument]
|
||||||
fn redirect_builder(target: &str) -> HttpResponse {
|
fn redirect_builder(target: &str) -> HttpResponse {
|
||||||
@ -69,7 +69,7 @@ fn detect_language(request: &HttpRequest) -> Result<String, ServerError> {
|
|||||||
#[instrument(skip(id, tera))]
|
#[instrument(skip(id, tera))]
|
||||||
pub async fn index(
|
pub async fn index(
|
||||||
tera: web::Data<Tera>,
|
tera: web::Data<Tera>,
|
||||||
config: web::Data<pslink::ServerConfig>,
|
config: web::Data<crate::ServerConfig>,
|
||||||
id: Identity,
|
id: Identity,
|
||||||
) -> Result<HttpResponse, ServerError> {
|
) -> Result<HttpResponse, ServerError> {
|
||||||
if let Ok(links) = queries::list_all_allowed(&id, &config).await {
|
if let Ok(links) = queries::list_all_allowed(&id, &config).await {
|
||||||
@ -88,7 +88,7 @@ pub async fn index(
|
|||||||
#[instrument(skip(id, tera))]
|
#[instrument(skip(id, tera))]
|
||||||
pub async fn index_users(
|
pub async fn index_users(
|
||||||
tera: web::Data<Tera>,
|
tera: web::Data<Tera>,
|
||||||
config: web::Data<pslink::ServerConfig>,
|
config: web::Data<crate::ServerConfig>,
|
||||||
id: Identity,
|
id: Identity,
|
||||||
) -> Result<HttpResponse, ServerError> {
|
) -> Result<HttpResponse, ServerError> {
|
||||||
if let Ok(users) = queries::list_users(&id, &config).await {
|
if let Ok(users) = queries::list_users(&id, &config).await {
|
||||||
@ -107,7 +107,7 @@ pub async fn index_users(
|
|||||||
#[instrument(skip(id, tera))]
|
#[instrument(skip(id, tera))]
|
||||||
pub async fn view_link_empty(
|
pub async fn view_link_empty(
|
||||||
tera: web::Data<Tera>,
|
tera: web::Data<Tera>,
|
||||||
config: web::Data<pslink::ServerConfig>,
|
config: web::Data<crate::ServerConfig>,
|
||||||
id: Identity,
|
id: Identity,
|
||||||
) -> Result<HttpResponse, ServerError> {
|
) -> Result<HttpResponse, ServerError> {
|
||||||
view_link(tera, config, id, web::Path::from("".to_owned())).await
|
view_link(tera, config, id, web::Path::from("".to_owned())).await
|
||||||
@ -116,7 +116,7 @@ pub async fn view_link_empty(
|
|||||||
#[instrument(skip(id, tera))]
|
#[instrument(skip(id, tera))]
|
||||||
pub async fn view_link(
|
pub async fn view_link(
|
||||||
tera: web::Data<Tera>,
|
tera: web::Data<Tera>,
|
||||||
config: web::Data<pslink::ServerConfig>,
|
config: web::Data<crate::ServerConfig>,
|
||||||
id: Identity,
|
id: Identity,
|
||||||
link_id: web::Path<String>,
|
link_id: web::Path<String>,
|
||||||
) -> Result<HttpResponse, ServerError> {
|
) -> Result<HttpResponse, ServerError> {
|
||||||
@ -156,7 +156,7 @@ pub async fn view_link(
|
|||||||
#[instrument(skip(id, tera))]
|
#[instrument(skip(id, tera))]
|
||||||
pub async fn view_profile(
|
pub async fn view_profile(
|
||||||
tera: web::Data<Tera>,
|
tera: web::Data<Tera>,
|
||||||
config: web::Data<pslink::ServerConfig>,
|
config: web::Data<crate::ServerConfig>,
|
||||||
id: Identity,
|
id: Identity,
|
||||||
user_id: web::Path<String>,
|
user_id: web::Path<String>,
|
||||||
) -> Result<HttpResponse, ServerError> {
|
) -> Result<HttpResponse, ServerError> {
|
||||||
@ -184,7 +184,7 @@ pub async fn view_profile(
|
|||||||
#[instrument(skip(id, tera))]
|
#[instrument(skip(id, tera))]
|
||||||
pub async fn edit_profile(
|
pub async fn edit_profile(
|
||||||
tera: web::Data<Tera>,
|
tera: web::Data<Tera>,
|
||||||
config: web::Data<pslink::ServerConfig>,
|
config: web::Data<crate::ServerConfig>,
|
||||||
id: Identity,
|
id: Identity,
|
||||||
user_id: web::Path<String>,
|
user_id: web::Path<String>,
|
||||||
) -> Result<HttpResponse, ServerError> {
|
) -> Result<HttpResponse, ServerError> {
|
||||||
@ -211,7 +211,7 @@ pub async fn edit_profile(
|
|||||||
#[instrument(skip(id))]
|
#[instrument(skip(id))]
|
||||||
pub async fn process_edit_profile(
|
pub async fn process_edit_profile(
|
||||||
data: web::Form<NewUser>,
|
data: web::Form<NewUser>,
|
||||||
config: web::Data<pslink::ServerConfig>,
|
config: web::Data<crate::ServerConfig>,
|
||||||
id: Identity,
|
id: Identity,
|
||||||
user_id: web::Path<String>,
|
user_id: web::Path<String>,
|
||||||
) -> Result<HttpResponse, ServerError> {
|
) -> Result<HttpResponse, ServerError> {
|
||||||
@ -225,7 +225,7 @@ pub async fn process_edit_profile(
|
|||||||
#[instrument(skip(id))]
|
#[instrument(skip(id))]
|
||||||
pub async fn download_png(
|
pub async fn download_png(
|
||||||
id: Identity,
|
id: Identity,
|
||||||
config: web::Data<pslink::ServerConfig>,
|
config: web::Data<crate::ServerConfig>,
|
||||||
link_code: web::Path<String>,
|
link_code: web::Path<String>,
|
||||||
) -> Result<HttpResponse, ServerError> {
|
) -> Result<HttpResponse, ServerError> {
|
||||||
match queries::get_link(&id, &link_code.0, &config).await {
|
match queries::get_link(&id, &link_code.0, &config).await {
|
||||||
@ -250,7 +250,7 @@ pub async fn download_png(
|
|||||||
#[instrument(skip(id, tera))]
|
#[instrument(skip(id, tera))]
|
||||||
pub async fn signup(
|
pub async fn signup(
|
||||||
tera: web::Data<Tera>,
|
tera: web::Data<Tera>,
|
||||||
config: web::Data<pslink::ServerConfig>,
|
config: web::Data<crate::ServerConfig>,
|
||||||
id: Identity,
|
id: Identity,
|
||||||
) -> Result<HttpResponse, ServerError> {
|
) -> Result<HttpResponse, ServerError> {
|
||||||
match queries::authenticate(&id, &config).await? {
|
match queries::authenticate(&id, &config).await? {
|
||||||
@ -271,7 +271,7 @@ pub async fn signup(
|
|||||||
#[instrument(skip(id))]
|
#[instrument(skip(id))]
|
||||||
pub async fn process_signup(
|
pub async fn process_signup(
|
||||||
data: web::Form<NewUser>,
|
data: web::Form<NewUser>,
|
||||||
config: web::Data<pslink::ServerConfig>,
|
config: web::Data<crate::ServerConfig>,
|
||||||
id: Identity,
|
id: Identity,
|
||||||
) -> Result<HttpResponse, ServerError> {
|
) -> Result<HttpResponse, ServerError> {
|
||||||
info!("Creating a User: {:?}", &data);
|
info!("Creating a User: {:?}", &data);
|
||||||
@ -286,7 +286,7 @@ pub async fn process_signup(
|
|||||||
#[instrument(skip(id))]
|
#[instrument(skip(id))]
|
||||||
pub async fn toggle_admin(
|
pub async fn toggle_admin(
|
||||||
data: web::Path<String>,
|
data: web::Path<String>,
|
||||||
config: web::Data<pslink::ServerConfig>,
|
config: web::Data<crate::ServerConfig>,
|
||||||
id: Identity,
|
id: Identity,
|
||||||
) -> Result<HttpResponse, ServerError> {
|
) -> Result<HttpResponse, ServerError> {
|
||||||
let update = queries::toggle_admin(&id, &data.0, &config).await?;
|
let update = queries::toggle_admin(&id, &data.0, &config).await?;
|
||||||
@ -299,18 +299,18 @@ pub async fn toggle_admin(
|
|||||||
#[instrument(skip(id))]
|
#[instrument(skip(id))]
|
||||||
pub async fn set_language(
|
pub async fn set_language(
|
||||||
data: web::Path<String>,
|
data: web::Path<String>,
|
||||||
config: web::Data<pslink::ServerConfig>,
|
config: web::Data<crate::ServerConfig>,
|
||||||
id: Identity,
|
id: Identity,
|
||||||
) -> Result<HttpResponse, ServerError> {
|
) -> Result<HttpResponse, ServerError> {
|
||||||
queries::set_language(&id, &data.0, &config).await?;
|
queries::set_language(&id, &data.0, &config).await?;
|
||||||
Ok(redirect_builder("/admin/index/"))
|
Ok(redirect_builder("/admin/index/"))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[instrument(skip(id))]
|
#[instrument(skip(tera, id))]
|
||||||
pub async fn login(
|
pub async fn login(
|
||||||
tera: web::Data<Tera>,
|
tera: web::Data<Tera>,
|
||||||
id: Identity,
|
id: Identity,
|
||||||
config: web::Data<pslink::ServerConfig>,
|
config: web::Data<crate::ServerConfig>,
|
||||||
req: HttpRequest,
|
req: HttpRequest,
|
||||||
) -> Result<HttpResponse, ServerError> {
|
) -> Result<HttpResponse, ServerError> {
|
||||||
let language_code = detect_language(&req)?;
|
let language_code = detect_language(&req)?;
|
||||||
@ -343,7 +343,7 @@ pub async fn login(
|
|||||||
#[instrument(skip(id))]
|
#[instrument(skip(id))]
|
||||||
pub async fn process_login(
|
pub async fn process_login(
|
||||||
data: web::Form<LoginUser>,
|
data: web::Form<LoginUser>,
|
||||||
config: web::Data<pslink::ServerConfig>,
|
config: web::Data<crate::ServerConfig>,
|
||||||
id: Identity,
|
id: Identity,
|
||||||
) -> Result<HttpResponse, ServerError> {
|
) -> Result<HttpResponse, ServerError> {
|
||||||
let user = queries::get_user_by_name(&data.username, &config).await;
|
let user = queries::get_user_by_name(&data.username, &config).await;
|
||||||
@ -354,7 +354,7 @@ pub async fn process_login(
|
|||||||
let valid = Verifier::default()
|
let valid = Verifier::default()
|
||||||
.with_hash(&u.password)
|
.with_hash(&u.password)
|
||||||
.with_password(&data.password)
|
.with_password(&data.password)
|
||||||
.with_secret_key(secret)
|
.with_secret_key(&secret.secret)
|
||||||
.verify()?;
|
.verify()?;
|
||||||
|
|
||||||
if valid {
|
if valid {
|
||||||
@ -383,7 +383,7 @@ pub async fn logout(id: Identity) -> Result<HttpResponse, ServerError> {
|
|||||||
#[instrument]
|
#[instrument]
|
||||||
pub async fn redirect(
|
pub async fn redirect(
|
||||||
tera: web::Data<Tera>,
|
tera: web::Data<Tera>,
|
||||||
config: web::Data<pslink::ServerConfig>,
|
config: web::Data<crate::ServerConfig>,
|
||||||
data: web::Path<String>,
|
data: web::Path<String>,
|
||||||
req: HttpRequest,
|
req: HttpRequest,
|
||||||
) -> Result<HttpResponse, ServerError> {
|
) -> Result<HttpResponse, ServerError> {
|
||||||
@ -413,7 +413,7 @@ pub async fn redirect(
|
|||||||
|
|
||||||
#[instrument]
|
#[instrument]
|
||||||
pub async fn redirect_empty(
|
pub async fn redirect_empty(
|
||||||
config: web::Data<pslink::ServerConfig>,
|
config: web::Data<crate::ServerConfig>,
|
||||||
) -> Result<HttpResponse, ServerError> {
|
) -> Result<HttpResponse, ServerError> {
|
||||||
Ok(redirect_builder(&config.empty_forward_url))
|
Ok(redirect_builder(&config.empty_forward_url))
|
||||||
}
|
}
|
||||||
@ -421,7 +421,7 @@ pub async fn redirect_empty(
|
|||||||
#[instrument(skip(id))]
|
#[instrument(skip(id))]
|
||||||
pub async fn create_link(
|
pub async fn create_link(
|
||||||
tera: web::Data<Tera>,
|
tera: web::Data<Tera>,
|
||||||
config: web::Data<pslink::ServerConfig>,
|
config: web::Data<crate::ServerConfig>,
|
||||||
id: Identity,
|
id: Identity,
|
||||||
) -> Result<HttpResponse, ServerError> {
|
) -> Result<HttpResponse, ServerError> {
|
||||||
match queries::authenticate(&id, &config).await? {
|
match queries::authenticate(&id, &config).await? {
|
||||||
@ -442,7 +442,7 @@ pub async fn create_link(
|
|||||||
#[instrument(skip(id))]
|
#[instrument(skip(id))]
|
||||||
pub async fn process_link_creation(
|
pub async fn process_link_creation(
|
||||||
data: web::Form<LinkForm>,
|
data: web::Form<LinkForm>,
|
||||||
config: web::Data<pslink::ServerConfig>,
|
config: web::Data<crate::ServerConfig>,
|
||||||
id: Identity,
|
id: Identity,
|
||||||
) -> Result<HttpResponse, ServerError> {
|
) -> Result<HttpResponse, ServerError> {
|
||||||
let new_link = queries::create_link(&id, data, &config).await?;
|
let new_link = queries::create_link(&id, data, &config).await?;
|
||||||
@ -455,7 +455,7 @@ pub async fn process_link_creation(
|
|||||||
#[instrument(skip(id))]
|
#[instrument(skip(id))]
|
||||||
pub async fn edit_link(
|
pub async fn edit_link(
|
||||||
tera: web::Data<Tera>,
|
tera: web::Data<Tera>,
|
||||||
config: web::Data<pslink::ServerConfig>,
|
config: web::Data<crate::ServerConfig>,
|
||||||
id: Identity,
|
id: Identity,
|
||||||
link_id: web::Path<String>,
|
link_id: web::Path<String>,
|
||||||
) -> Result<HttpResponse, ServerError> {
|
) -> Result<HttpResponse, ServerError> {
|
||||||
@ -472,7 +472,7 @@ pub async fn edit_link(
|
|||||||
}
|
}
|
||||||
pub async fn process_link_edit(
|
pub async fn process_link_edit(
|
||||||
data: web::Form<LinkForm>,
|
data: web::Form<LinkForm>,
|
||||||
config: web::Data<pslink::ServerConfig>,
|
config: web::Data<crate::ServerConfig>,
|
||||||
id: Identity,
|
id: Identity,
|
||||||
link_code: web::Path<String>,
|
link_code: web::Path<String>,
|
||||||
) -> Result<HttpResponse, ServerError> {
|
) -> Result<HttpResponse, ServerError> {
|
||||||
@ -488,7 +488,7 @@ pub async fn process_link_edit(
|
|||||||
#[instrument(skip(id))]
|
#[instrument(skip(id))]
|
||||||
pub async fn process_link_delete(
|
pub async fn process_link_delete(
|
||||||
id: Identity,
|
id: Identity,
|
||||||
config: web::Data<pslink::ServerConfig>,
|
config: web::Data<crate::ServerConfig>,
|
||||||
link_code: web::Path<String>,
|
link_code: web::Path<String>,
|
||||||
) -> Result<HttpResponse, ServerError> {
|
) -> Result<HttpResponse, ServerError> {
|
||||||
queries::delete_link(&id, &link_code.0, &config).await?;
|
queries::delete_link(&id, &link_code.0, &config).await?;
|
215
tests/integration-tests.rs
Normal file
215
tests/integration-tests.rs
Normal file
@ -0,0 +1,215 @@
|
|||||||
|
#[test]
|
||||||
|
fn test_help_of_command_for_breaking_changes() {
|
||||||
|
let output = test_bin::get_test_bin("pslink")
|
||||||
|
.output()
|
||||||
|
.expect("Failed to start pslink");
|
||||||
|
assert!(String::from_utf8_lossy(&output.stdout).contains("USAGE"));
|
||||||
|
|
||||||
|
let output = test_bin::get_test_bin("pslink")
|
||||||
|
.args(&["--help"])
|
||||||
|
.output()
|
||||||
|
.expect("Failed to start pslink");
|
||||||
|
let outstring = String::from_utf8_lossy(&output.stdout);
|
||||||
|
|
||||||
|
let args = &[
|
||||||
|
"USAGE",
|
||||||
|
"-h",
|
||||||
|
"--help",
|
||||||
|
"-b",
|
||||||
|
"-e",
|
||||||
|
"-i",
|
||||||
|
"-p",
|
||||||
|
"-t",
|
||||||
|
"-u",
|
||||||
|
"runserver",
|
||||||
|
"create-admin",
|
||||||
|
"generate-env",
|
||||||
|
"migrate-database",
|
||||||
|
"help",
|
||||||
|
];
|
||||||
|
|
||||||
|
for s in args {
|
||||||
|
assert!(
|
||||||
|
outstring.contains(s),
|
||||||
|
"{} was not found in the help - this is a breaking change",
|
||||||
|
s
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_generate_env() {
|
||||||
|
use std::io::BufRead;
|
||||||
|
let tmp_dir = tempdir::TempDir::new("pslink_test_env").expect("create temp dir");
|
||||||
|
let output = test_bin::get_test_bin("pslink")
|
||||||
|
.args(&["generate-env"])
|
||||||
|
.current_dir(&tmp_dir)
|
||||||
|
.output()
|
||||||
|
.expect("Failed to start pslink");
|
||||||
|
let envfile = tmp_dir.path().join(".env");
|
||||||
|
let dbfile = tmp_dir.path().join("links.db");
|
||||||
|
println!("{}", envfile.display());
|
||||||
|
println!("{}", dbfile.display());
|
||||||
|
println!("{}", String::from_utf8_lossy(&output.stdout));
|
||||||
|
assert!(envfile.exists(), "No .env-file was created!");
|
||||||
|
assert!(dbfile.exists(), "No database-file was created!");
|
||||||
|
|
||||||
|
let envfile = std::fs::File::open(envfile).unwrap();
|
||||||
|
let mut envcontent = std::io::BufReader::new(envfile).lines();
|
||||||
|
assert!(
|
||||||
|
envcontent.any(|s| s.as_ref().unwrap().starts_with("PSLINK_PORT=")),
|
||||||
|
"Failed to find DATABASE_URL in the generated .env file."
|
||||||
|
);
|
||||||
|
let output = test_bin::get_test_bin("pslink")
|
||||||
|
.args(&["generate-env"])
|
||||||
|
.current_dir(&tmp_dir)
|
||||||
|
.output()
|
||||||
|
.expect("Failed to start pslink");
|
||||||
|
let second_out = String::from_utf8_lossy(&output.stdout);
|
||||||
|
assert!(!second_out.contains("secret"));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[actix_rt::test]
|
||||||
|
async fn test_migrate_database() {
|
||||||
|
use std::io::Write;
|
||||||
|
#[derive(serde::Serialize, Debug)]
|
||||||
|
pub struct Count {
|
||||||
|
pub number: i32,
|
||||||
|
}
|
||||||
|
|
||||||
|
let tmp_dir = tempdir::TempDir::new("pslink_test_env").expect("create temp dir");
|
||||||
|
// generate .env file
|
||||||
|
let _output = test_bin::get_test_bin("pslink")
|
||||||
|
.args(&["generate-env"])
|
||||||
|
.current_dir(&tmp_dir)
|
||||||
|
.output()
|
||||||
|
.expect("Failed generate .env");
|
||||||
|
|
||||||
|
// migrate the database
|
||||||
|
let output = test_bin::get_test_bin("pslink")
|
||||||
|
.args(&["migrate-database"])
|
||||||
|
.current_dir(&tmp_dir)
|
||||||
|
.output()
|
||||||
|
.expect("Failed to migrate the database");
|
||||||
|
println!("{}", String::from_utf8_lossy(&output.stdout));
|
||||||
|
|
||||||
|
// check if the users table exists by counting the number of admins.
|
||||||
|
let db_pool = sqlx::pool::Pool::<sqlx::sqlite::Sqlite>::connect(
|
||||||
|
&tmp_dir.path().join("links.db").display().to_string(),
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.expect("Error: Failed to connect to database!");
|
||||||
|
let num = sqlx::query_as!(Count, "select count(*) as number from users where role = 2")
|
||||||
|
.fetch_one(&db_pool)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
// initially no admin is present
|
||||||
|
assert_eq!(num.number, 0, "Failed to create the database!");
|
||||||
|
|
||||||
|
// create a new admin
|
||||||
|
let mut input = test_bin::get_test_bin("pslink")
|
||||||
|
.args(&["create-admin"])
|
||||||
|
.current_dir(&tmp_dir)
|
||||||
|
.stdin(std::process::Stdio::piped())
|
||||||
|
.stdout(std::process::Stdio::piped())
|
||||||
|
.spawn()
|
||||||
|
.expect("Failed to migrate the database");
|
||||||
|
let mut procin = input.stdin.take().unwrap();
|
||||||
|
|
||||||
|
procin.write_all(b"test\n").unwrap();
|
||||||
|
procin.write_all(b"test@mail.test\n").unwrap();
|
||||||
|
procin.write_all(b"testpw\n").unwrap();
|
||||||
|
|
||||||
|
let r = input.wait().unwrap();
|
||||||
|
println!("Exitstatus is: {}", r);
|
||||||
|
|
||||||
|
println!("{}", String::from_utf8_lossy(&output.stdout));
|
||||||
|
let num = sqlx::query_as!(Count, "select count(*) as number from users where role = 2")
|
||||||
|
.fetch_one(&db_pool)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
// now 1 admin is there
|
||||||
|
assert_eq!(num.number, 1, "Failed to create an admin!");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* async fn run_server() {
|
||||||
|
use std::io::Write;
|
||||||
|
#[derive(serde::Serialize, Debug)]
|
||||||
|
pub struct Count {
|
||||||
|
pub number: i32,
|
||||||
|
}
|
||||||
|
let tmp_dir = tempdir::TempDir::new("pslink_test_env").expect("create temp dir");
|
||||||
|
// generate .env file
|
||||||
|
let _output = test_bin::get_test_bin("pslink")
|
||||||
|
.args(&["generate-env"])
|
||||||
|
.current_dir(&tmp_dir)
|
||||||
|
.output()
|
||||||
|
.expect("Failed generate .env");
|
||||||
|
// migrate the database
|
||||||
|
let output = test_bin::get_test_bin("pslink")
|
||||||
|
.args(&["migrate-database"])
|
||||||
|
.current_dir(&tmp_dir)
|
||||||
|
.output()
|
||||||
|
.expect("Failed to migrate the database");
|
||||||
|
|
||||||
|
// create a database connection.
|
||||||
|
let db_pool = sqlx::pool::Pool::<sqlx::sqlite::Sqlite>::connect(
|
||||||
|
&tmp_dir.path().join("links.db").display().to_string(),
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.expect("Error: Failed to connect to database!"); // create a new admin
|
||||||
|
let mut input = test_bin::get_test_bin("pslink")
|
||||||
|
.args(&["create-admin"])
|
||||||
|
.current_dir(&tmp_dir)
|
||||||
|
.stdin(std::process::Stdio::piped())
|
||||||
|
.stdout(std::process::Stdio::piped())
|
||||||
|
.spawn()
|
||||||
|
.expect("Failed to migrate the database");
|
||||||
|
let mut procin = input.stdin.take().unwrap();
|
||||||
|
|
||||||
|
procin.write_all(b"test\n").unwrap();
|
||||||
|
procin.write_all(b"test@mail.test\n").unwrap();
|
||||||
|
procin.write_all(b"testpw\n").unwrap();
|
||||||
|
|
||||||
|
let r = input.wait().unwrap();
|
||||||
|
println!("Exitstatus is: {}", r);
|
||||||
|
|
||||||
|
println!("{}", String::from_utf8_lossy(&output.stdout));
|
||||||
|
let num = sqlx::query_as!(Count, "select count(*) as number from users where role = 2")
|
||||||
|
.fetch_one(&db_pool)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
// now 1 admin is there
|
||||||
|
assert_eq!(
|
||||||
|
num.number, 1,
|
||||||
|
"Failed to create an admin! See previous tests!"
|
||||||
|
);
|
||||||
|
let output = test_bin::get_test_bin("pslink")
|
||||||
|
.args(&["runserver"])
|
||||||
|
.current_dir(&tmp_dir)
|
||||||
|
.spawn()
|
||||||
|
.expect("Failed to migrate the database");
|
||||||
|
let out = output.wait_with_output().unwrap();
|
||||||
|
println!("{}", String::from_utf8_lossy(&out.stdout));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[actix_rt::test]
|
||||||
|
async fn test_web_paths() {
|
||||||
|
actix_rt::spawn(run_server());
|
||||||
|
|
||||||
|
std::thread::sleep(std::time::Duration::new(5, 0));
|
||||||
|
// We need to bring in `reqwest`
|
||||||
|
// to perform HTTP requests against our application.
|
||||||
|
let client = reqwest::Client::new();
|
||||||
|
|
||||||
|
// Act
|
||||||
|
let response = client
|
||||||
|
.get("http://127.0.0.1:8080/admin/login/")
|
||||||
|
.send()
|
||||||
|
.await
|
||||||
|
.expect("Failed to execute request.");
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
assert!(response.status().is_success());
|
||||||
|
//assert_eq!(Some(0), response.content_length());
|
||||||
|
} */
|
Loading…
Reference in New Issue
Block a user