Switch to BLAKE3, slightly better security, simplify with globals

This commit is contained in:
Raphaël Thériault 2020-01-15 23:47:38 -05:00
parent f1c40f4748
commit 5855965e24
8 changed files with 176 additions and 280 deletions

103
Cargo.lock generated
View File

@ -330,6 +330,11 @@ dependencies = [
"nodrop 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "arrayvec"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "async-trait"
version = "0.1.22"
@ -392,7 +397,7 @@ name = "backtrace-sys"
version = "0.1.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"cc 1.0.46 (registry+https://github.com/rust-lang/crates.io-index)",
"cc 1.0.50 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)",
]
@ -414,17 +419,6 @@ name = "bitflags"
version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "blake2"
version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"byte-tools 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
"crypto-mac 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
"digest 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
"opaque-debug 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "blake2b_simd"
version = "0.5.8"
@ -432,7 +426,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"arrayref 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
"arrayvec 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)",
"constant_time_eq 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
"constant_time_eq 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "blake3"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"arrayref 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
"arrayvec 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
"cc 1.0.50 (registry+https://github.com/rust-lang/crates.io-index)",
"cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
"constant_time_eq 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@ -440,7 +446,7 @@ name = "brotli-sys"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"cc 1.0.46 (registry+https://github.com/rust-lang/crates.io-index)",
"cc 1.0.50 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)",
]
@ -458,11 +464,6 @@ name = "bumpalo"
version = "3.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "byte-tools"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "byteorder"
version = "1.3.2"
@ -491,7 +492,7 @@ dependencies = [
[[package]]
name = "cc"
version = "1.0.46"
version = "1.0.50"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
@ -519,7 +520,7 @@ dependencies = [
[[package]]
name = "constant_time_eq"
version = "0.1.4"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
@ -544,15 +545,6 @@ dependencies = [
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "crypto-mac"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"generic-array 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)",
"subtle 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "derive_more"
version = "0.99.2"
@ -593,14 +585,6 @@ dependencies = [
"migrations_macros 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "digest"
version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"generic-array 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "dirs"
version = "2.0.2"
@ -697,7 +681,7 @@ dependencies = [
"actix-rt 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"actix-web 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"base64 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
"blake2 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
"blake3 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"chrono 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)",
"diesel 1.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
"diesel_migrations 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
@ -839,14 +823,6 @@ dependencies = [
"byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "generic-array"
version = "0.12.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"typenum 1.11.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "getrandom"
version = "0.1.13"
@ -1002,7 +978,7 @@ name = "libsqlite3-sys"
version = "0.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"cc 1.0.46 (registry+https://github.com/rust-lang/crates.io-index)",
"cc 1.0.50 (registry+https://github.com/rust-lang/crates.io-index)",
"pkg-config 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)",
"vcpkg 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)",
]
@ -1176,11 +1152,6 @@ dependencies = [
"libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "opaque-debug"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "parking_lot"
version = "0.9.0"
@ -1438,7 +1409,7 @@ name = "ring"
version = "0.16.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"cc 1.0.46 (registry+https://github.com/rust-lang/crates.io-index)",
"cc 1.0.50 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)",
"spin 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
@ -1590,11 +1561,6 @@ name = "spin"
version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "subtle"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "syn"
version = "1.0.7"
@ -1737,11 +1703,6 @@ dependencies = [
"unchecked-index 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "typenum"
version = "1.11.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "unchecked-index"
version = "0.2.2"
@ -2023,6 +1984,7 @@ dependencies = [
"checksum arc-swap 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "f1a1eca3195b729bbd64e292ef2f5fff6b1c28504fed762ce2b1013dde4d8e92"
"checksum arrayref 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "0d382e583f07208808f6b1249e60848879ba3543f57c32277bf52d69c2f0f0ee"
"checksum arrayvec 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)" = "cd9fd44efafa8690358b7408d253adf110036b88f55672a933f01d616ad9b1b9"
"checksum arrayvec 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cff77d8686867eceff3105329d4698d96c2391c176d5d03adc90c7389162b5b8"
"checksum async-trait 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)" = "c8df72488e87761e772f14ae0c2480396810e51b2c2ade912f97f0f7e5b95e3c"
"checksum atty 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)" = "1803c647a3ec87095e7ae7acfca019e98de5ec9a7d01343f611cf3152ed71a90"
"checksum autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "1d49d90015b3c36167a20fe2810c5cd875ad504b39cff3d4eae7977e6b7c1cb2"
@ -2032,30 +1994,27 @@ dependencies = [
"checksum base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0b25d992356d2eb0ed82172f5248873db5560c4721f564b13cb5193bda5e668e"
"checksum base64 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b41b7ea54a0c9d92199de89e20e58d49f02f8e699814ef3fdf266f6f748d15c7"
"checksum bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
"checksum blake2 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "94cb07b0da6a73955f8fb85d24c466778e70cda767a568229b104f0264089330"
"checksum blake2b_simd 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)" = "5850aeee1552f495dd0250014cf64b82b7c8879a89d83b33bbdace2cc4f63182"
"checksum blake3 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ba0511b7f4f7d9cb1ef7b8dfda5293af6c1071578d65c8a05aa7d11c1985f08c"
"checksum brotli-sys 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4445dea95f4c2b41cde57cc9fee236ae4dbae88d8fcbdb4750fc1bb5d86aaecd"
"checksum brotli2 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "0cb036c3eade309815c15ddbacec5b22c4d1f3983a774ab2eac2e3e9ea85568e"
"checksum bumpalo 3.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "5fb8038c1ddc0a5f73787b130f4cc75151e96ed33e417fde765eb5a81e3532f4"
"checksum byte-tools 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7"
"checksum byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a7c3dd8985a7111efc5c80b44e23ecdd8c007de8ade3b96595387e812b957cf5"
"checksum bytes 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "10004c15deb332055f7a4a208190aed362cf9a7c2f6ab70a305fba50e1105f38"
"checksum bytestring 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "fc267467f58ef6cc8874064c62a0423eb0d099362c8a23edd1c6d044f46eead4"
"checksum c2-chacha 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "214238caa1bf3a496ec3392968969cab8549f96ff30652c9e56885329315f6bb"
"checksum cc 1.0.46 (registry+https://github.com/rust-lang/crates.io-index)" = "0213d356d3c4ea2c18c40b037c3be23cd639825c18f25ee670ac7813beeef99c"
"checksum cc 1.0.50 (registry+https://github.com/rust-lang/crates.io-index)" = "95e28fa049fda1c330bcf9d723be7663a899c4679724b34c81e9f5a326aab8cd"
"checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
"checksum chrono 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "31850b4a4d6bae316f7a09e691c944c28299298837edc0a03f755618c23cbc01"
"checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f"
"checksum constant_time_eq 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "995a44c877f9212528ccc74b21a232f66ad69001e40ede5bcee2ac9ef2657120"
"checksum constant_time_eq 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc"
"checksum copyless 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "6ff9c56c9fb2a49c05ef0e431485a22400af20d33226dc0764d891d09e724127"
"checksum crc32fast 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ba125de2af0df55319f41944744ad91c71113bf74a4646efff39afe1f6842db1"
"checksum crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)" = "04973fa96e96579258a5091af6003abde64af786b860f18622b82e026cca60e6"
"checksum crypto-mac 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4434400df11d95d556bac068ddfedd482915eb18fe8bea89bc80b6e4b1c179e5"
"checksum derive_more 0.99.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2159be042979966de68315bce7034bb000c775f22e3e834e1c52ff78f041cae8"
"checksum diesel 1.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "9d7cc03b910de9935007861dce440881f69102aaaedfd4bc5a6f40340ca5840c"
"checksum diesel_derives 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "45f5098f628d02a7a0f68ddba586fb61e80edec3bdc1be3b921f4ceec60858d3"
"checksum diesel_migrations 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bf3cde8413353dc7f5d72fa8ce0b99a560a359d2c5ef1e5817ca731cd9008f4c"
"checksum digest 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f3d0c8c8752312f9713efd397ff63acb9f85585afbf179282e720e7704954dd5"
"checksum dirs 2.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "13aea89a5c93364a98e9b37b2fa237effbb694d5cfe01c5b70941f7eb087d5e3"
"checksum dirs-sys 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "afa0b23de8fd801745c471deffa6e12d248f962c9fd4b4c33787b055599bde7b"
"checksum dotenv 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)" = "77c90badedccf4105eca100756a0b1289e191f6fcbdadd3cee1d2f614f97da8f"
@ -2081,7 +2040,6 @@ dependencies = [
"checksum futures-task 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0bae52d6b29cf440e298856fec3965ee6fa71b06aa7495178615953fd669e5f9"
"checksum futures-util 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c0d66274fb76985d3c62c886d1da7ac4c0903a8c9f754e8fe0f35a6a6cc39e76"
"checksum fxhash 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c"
"checksum generic-array 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c68f0274ae0e023facc3c97b2e00f076be70e254bc851d972503b328db79b2ec"
"checksum getrandom 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "e7db7ca94ed4cd01190ceee0d8a8052f08a247aa1b469a7f68c6a3b71afcf407"
"checksum h2 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b9433d71e471c1736fd5a61b671fc0b148d7a2992f666c958d03cd8feb3b88d1"
"checksum heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "20564e78d53d2bb135c343b3f47714a56af2061f1c928fdb541dc7b9fdd94205"
@ -2121,7 +2079,6 @@ dependencies = [
"checksum num-integer 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)" = "b85e541ef8255f6cf42bbfe4ef361305c6c135d10919ecc26126c4e5ae94bc09"
"checksum num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "6ba9a427cfca2be13aa6f6403b0b7e7368fe982bfa16fccc450ce74c46cd9b32"
"checksum num_cpus 1.11.1 (registry+https://github.com/rust-lang/crates.io-index)" = "76dac5ed2a876980778b8b85f75a71b6cbf0db0b1232ee12f826bccb00d09d72"
"checksum opaque-debug 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c"
"checksum parking_lot 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "92e98c49ab0b7ce5b222f2cc9193fc4efe11c6d0bd4f648e374684a6857b1cfc"
"checksum parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f842b1982eb6c2fe34036a4fbfb06dd185a3f5c8edfaacdf7d1ea10b07de6252"
"checksum parking_lot_core 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b876b1b9e7ac6e1a74a6da34d25c42e17e8862aa409cbbbdcfc8d86c6f3bc62b"
@ -2174,7 +2131,6 @@ dependencies = [
"checksum socket2 0.3.11 (registry+https://github.com/rust-lang/crates.io-index)" = "e8b74de517221a2cb01a53349cf54182acdc31a074727d3079068448c0676d85"
"checksum sourcefile 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "4bf77cb82ba8453b42b6ae1d692e4cdc92f9a47beaf89a847c8be83f4e328ad3"
"checksum spin 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d"
"checksum subtle 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2d67a5a62ba6e01cb2192ff309324cb4875d0c451d55fe2319433abe7a05a8ee"
"checksum syn 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)" = "0e7bedb3320d0f3035594b0b723c8a28d7d336a3eda3881db79e61d676fb644c"
"checksum synstructure 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3f085a5855930c0441ca1288cf044ea4aecf4f43a91668abdb870b4ba546a203"
"checksum termcolor 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "96d6098003bde162e4277c70665bd87c326f5a0c3f3fbfb285787fa482d54e6e"
@ -2187,7 +2143,6 @@ dependencies = [
"checksum trust-dns-proto 0.18.0-alpha.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2a7f3a2ab8a919f5eca52a468866a67ed7d3efa265d48a652a9a3452272b413f"
"checksum trust-dns-resolver 0.18.0-alpha.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6f90b1502b226f8b2514c6d5b37bafa8c200d7ca4102d57dc36ee0f3b7a04a2f"
"checksum twoway 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "6b40075910de3a912adbd80b5d8bad6ad10a23eeb1f5bf9d4006839e899ba5bc"
"checksum typenum 1.11.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6d2783fe2d6b8c1101136184eb41be8b1ad379e4657050b8aaff0c79ee7575f9"
"checksum unchecked-index 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "eeba86d422ce181a719445e51872fa30f1f7413b62becb52e95ec91aa262d85c"
"checksum unicase 2.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2e2e6bd1e59e56598518beb94fd6db628ded570326f0a98c679a304bd9f00150"
"checksum unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5"

View File

@ -13,6 +13,7 @@ keywords = [
"pastebin"
]
license = "MIT"
build = "build.rs"
[dependencies]
actix-files = "0.2.1"
@ -21,7 +22,7 @@ actix-rt = "1.0.0"
actix-multipart = "0.2.0"
actix-web = "2.0.0"
base64 = "0.11.0"
blake2 = "0.8.1"
blake3 = "0.1.1"
chrono = "0.4.10"
diesel_migrations = "1.4.0"
dirs = "2.0.2"
@ -43,6 +44,9 @@ features = ["bundled"]
version = "1.0.104"
features = ["derive"]
[build-dependencies]
rand = "0.7.3"
[features]
default = []
dev = ["dotenv"]

15
build.rs Normal file
View File

@ -0,0 +1,15 @@
use rand::Rng;
use std::{env, fs::File, io::Write, path::Path};
fn main() {
let mut key = [0; 32];
let mut rng = rand::thread_rng();
for b in key.iter_mut() {
*b = rng.gen();
}
let out_dir = env::var("OUT_DIR").unwrap();
let dest_path = Path::new(&out_dir).join("key");
let mut f = File::create(&dest_path).unwrap();
f.write_all(&key).unwrap();
}

29
src/globals.rs Normal file
View File

@ -0,0 +1,29 @@
pub const KEY: &[u8; 32] = include_bytes!(concat!(env!("OUT_DIR"), "/key"));
lazy_static! {
pub static ref EMPTY_HASH: Vec<u8> = crate::setup::hash(b"");
pub static ref POOL: crate::Pool =
crate::setup::create_pool(&CONFIG.database_url, CONFIG.pool_size);
}
#[cfg(feature = "dev")]
lazy_static! {
pub static ref CONFIG: crate::setup::Config = crate::setup::Config::debug();
pub static ref PASSWORD_HASH: Vec<u8> = {
dotenv::dotenv().ok();
let password = crate::get_env!("PASSWD");
crate::setup::hash(password.as_bytes())
};
}
#[cfg(not(feature = "dev"))]
lazy_static! {
pub static ref CONFIG: crate::setup::Config = crate::setup::init();
pub static ref PASSWORD_HASH: Vec<u8> = {
let password_path = crate::setup::get_password_path();
std::fs::read(&password_path).unwrap_or_else(|e| {
eprintln!("Can't read password hash from disk: {}", e);
std::process::exit(1);
})
};
}

View File

@ -16,13 +16,7 @@ use diesel::{
};
use std::process;
#[cfg(feature = "dev")]
use crate::setup::Config;
#[cfg(feature = "dev")]
use dotenv;
#[cfg(not(feature = "dev"))]
use std::fs;
pub mod globals;
pub mod models;
pub mod queries;
pub mod routes;
@ -35,58 +29,29 @@ pub type Pool = r2d2::Pool<ConnectionManager<SqliteConnection>>;
#[cfg(not(feature = "dev"))]
embed_migrations!();
use globals::{CONFIG, KEY};
#[actix_rt::main]
async fn main() {
let config = {
#[cfg(feature = "dev")]
{
Config::debug()
}
#[cfg(not(feature = "dev"))]
{
setup::init()
}
};
setup::init_logger();
let pool = setup::create_pool(&config.database_url, config.pool_size);
#[cfg(not(feature = "dev"))]
{
embedded_migrations::run(&pool.get().unwrap()).unwrap_or_else(|e| {
embedded_migrations::run(&globals::POOL.get().unwrap()).unwrap_or_else(|e| {
eprintln!("Can't prepare database: {}", e);
process::exit(1);
});
}
let password_hash = {
#[cfg(feature = "dev")]
{
dotenv::dotenv().ok();
let password = get_env!("PASSWD");
setup::hash(&password)
}
#[cfg(not(feature = "dev"))]
{
let password_path = setup::get_password_path();
fs::read(&password_path).unwrap_or_else(|e| {
eprintln!("Can't read password hash from disk: {}.", e);
process::exit(1);
})
}
};
let port = config.port;
let port = CONFIG.port;
println!("Listening on port {}", port);
HttpServer::new(move || {
App::new()
.data(pool.clone())
.data(config.clone())
.data(password_hash.clone())
.wrap(IdentityService::new(
CookieIdentityPolicy::new(&[0; 32])
CookieIdentityPolicy::new(KEY)
.name("filite-auth-cookie")
.secure(false),
.secure(true),
))
.wrap(setup::logger_middleware())
.route("/", web::get().to(routes::index))

View File

@ -42,11 +42,9 @@ macro_rules! common_select {
if let Some(to) = $f.range.1 {
$q = $q.filter(created.lt(to));
}
if let Some(limit) = $f.limit {
$q = $q.limit(limit);
}
$q = if $f.asc {
$q.order(created.asc())
} else {
@ -58,8 +56,8 @@ macro_rules! common_select {
/// SELECT a single entry given its id
macro_rules! find {
($n:ident, $t:ty) => {
pub fn find(f_id: i32, pool: Data<Pool>) -> QueryResult<$t> {
let conn: &SqliteConnection = &pool.get().unwrap();
pub fn find(f_id: i32) -> diesel::result::QueryResult<$t> {
let conn: &SqliteConnection = &crate::globals::POOL.get().unwrap();
$n.find(f_id).first::<$t>(conn)
}
};
@ -68,10 +66,9 @@ macro_rules! find {
/// DELETE an entry
macro_rules! delete {
($n:ident) => {
pub fn delete(d_id: i32, pool: Data<Pool>) -> QueryResult<()> {
let conn: &SqliteConnection = &pool.get().unwrap();
pub fn delete(d_id: i32) -> diesel::result::QueryResult<()> {
let conn: &SqliteConnection = &crate::globals::POOL.get().unwrap();
diesel::delete($n.find(d_id)).execute(conn)?;
Ok(())
}
};
@ -80,27 +77,27 @@ macro_rules! delete {
/// Queries affecting the `files` table
pub mod files {
use crate::{
globals::POOL,
models::files::*,
queries::SelectFilters,
schema::files::{dsl::*, table},
Pool,
};
use actix_web::web::Data;
use diesel::{prelude::*, result::QueryResult};
find!(files, File);
delete!(files);
/// SELECT multiple file entries
pub fn select(filters: SelectFilters, pool: Data<Pool>) -> QueryResult<Vec<File>> {
let conn: &SqliteConnection = &pool.get().unwrap();
pub fn select(filters: SelectFilters) -> QueryResult<Vec<File>> {
let conn: &SqliteConnection = &POOL.get().unwrap();
let mut query = files.into_boxed();
common_select!(query, filters);
query.load::<File>(conn)
}
find!(files, File);
/// REPLACE a file entry
pub fn replace(r_id: i32, r_filepath: &str, pool: Data<Pool>) -> QueryResult<File> {
let conn: &SqliteConnection = &pool.get().unwrap();
pub fn replace(r_id: i32, r_filepath: &str) -> QueryResult<File> {
let conn: &SqliteConnection = &POOL.get().unwrap();
let new_file = NewFile {
id: r_id,
filepath: r_filepath,
@ -108,37 +105,34 @@ pub mod files {
diesel::replace_into(table)
.values(&new_file)
.execute(conn)?;
find(r_id, pool)
find(r_id)
}
delete!(files);
}
/// Queries affecting the `links` table
pub mod links {
use crate::{
globals::POOL,
models::links::*,
queries::SelectFilters,
schema::links::{dsl::*, table},
Pool,
};
use actix_web::web::Data;
use diesel::{prelude::*, result::QueryResult};
find!(links, Link);
delete!(links);
/// SELECT multiple link entries
pub fn select(filters: SelectFilters, pool: Data<Pool>) -> QueryResult<Vec<Link>> {
let conn: &SqliteConnection = &pool.get().unwrap();
pub fn select(filters: SelectFilters) -> QueryResult<Vec<Link>> {
let conn: &SqliteConnection = &POOL.get().unwrap();
let mut query = links.into_boxed();
common_select!(query, filters);
query.load::<Link>(conn)
}
find!(links, Link);
/// REPLACE a link entry
pub fn replace(r_id: i32, r_forward: &str, pool: Data<Pool>) -> QueryResult<Link> {
let conn: &SqliteConnection = &pool.get().unwrap();
pub fn replace(r_id: i32, r_forward: &str) -> QueryResult<Link> {
let conn: &SqliteConnection = &POOL.get().unwrap();
let new_link = NewLink {
id: r_id,
forward: r_forward,
@ -146,42 +140,34 @@ pub mod links {
diesel::replace_into(table)
.values(&new_link)
.execute(conn)?;
find(r_id, pool)
find(r_id)
}
delete!(links);
}
/// Queries affecting the `texts` table
pub mod texts {
use crate::{
globals::POOL,
models::texts::*,
queries::SelectFilters,
schema::texts::{dsl::*, table},
Pool,
};
use actix_web::web::Data;
use diesel::{prelude::*, result::QueryResult};
find!(texts, Text);
delete!(texts);
/// SELECT multiple text entries
pub fn select(filters: SelectFilters, pool: Data<Pool>) -> QueryResult<Vec<Text>> {
let conn: &SqliteConnection = &pool.get().unwrap();
pub fn select(filters: SelectFilters) -> QueryResult<Vec<Text>> {
let conn: &SqliteConnection = &POOL.get().unwrap();
let mut query = texts.into_boxed();
common_select!(query, filters);
query.load::<Text>(conn)
}
find!(texts, Text);
/// REPLACE a text entry
pub fn replace(
r_id: i32,
r_contents: &str,
r_highlight: bool,
pool: Data<Pool>,
) -> QueryResult<Text> {
let conn: &SqliteConnection = &pool.get().unwrap();
pub fn replace(r_id: i32, r_contents: &str, r_highlight: bool) -> QueryResult<Text> {
let conn: &SqliteConnection = &POOL.get().unwrap();
let new_text = NewText {
id: r_id,
contents: r_contents,
@ -190,9 +176,6 @@ pub mod texts {
diesel::replace_into(table)
.values(&new_text)
.execute(conn)?;
find(r_id, pool)
find(r_id)
}
delete!(texts);
}

View File

@ -1,9 +1,11 @@
//! Actix route handlers
use crate::setup::{self, Config};
use crate::{
globals::{CONFIG, EMPTY_HASH, PASSWORD_HASH},
setup,
};
use actix_identity::Identity;
use actix_web::{error::BlockingError, web, Error, HttpRequest, HttpResponse, Responder};
use base64;
use chrono::{DateTime, NaiveDateTime, Utc};
use diesel;
use serde::Serialize;
@ -22,21 +24,13 @@ fn parse_id(id: &str) -> Result<i32, HttpResponse> {
}
}
lazy_static! {
static ref EMPTY_HASH: Vec<u8> = setup::hash("");
}
/// Authenticates a user
async fn auth(
identity: Identity,
request: HttpRequest,
password_hash: &[u8],
) -> Result<(), HttpResponse> {
async fn auth(identity: Identity, request: HttpRequest) -> Result<(), HttpResponse> {
if identity.identity().is_some() {
return Ok(());
}
if password_hash == (&*EMPTY_HASH).as_slice() {
if *PASSWORD_HASH == *EMPTY_HASH {
identity.remember("guest".into());
return Ok(());
}
@ -67,8 +61,8 @@ async fn auth(
Err(_) => return Err(HttpResponse::BadRequest().body("Invalid Authorization header")),
};
let infallible_hash = move || -> Result<Vec<u8>, Infallible> { Ok(setup::hash(password)) };
if web::block(infallible_hash).await.unwrap().as_slice() == password_hash {
let infallible_hash = move || -> Result<Vec<u8>, Infallible> { Ok(setup::hash(&password)) };
if web::block(infallible_hash).await.unwrap() == *PASSWORD_HASH {
match String::from_utf8(user.to_vec()) {
Ok(u) => {
identity.remember(u);
@ -133,14 +127,12 @@ macro_rules! select {
pub async fn select(
request: HttpRequest,
query: actix_web::web::Query<SelectQuery>,
pool: actix_web::web::Data<Pool>,
identity: actix_identity::Identity,
password_hash: actix_web::web::Data<Vec<u8>>,
) -> Result<actix_web::HttpResponse, actix_web::Error> {
crate::routes::auth(identity, request, &password_hash).await?;
crate::routes::auth(identity, request).await?;
let filters = crate::queries::SelectFilters::from(query.into_inner());
match actix_web::web::block(move || crate::queries::$m::select(filters, pool)).await {
match actix_web::web::block(move || crate::queries::$m::select(filters)).await {
Ok(x) => Ok(actix_web::HttpResponse::Ok().json(x)),
Err(_) => Err(actix_web::HttpResponse::InternalServerError()
.body("Internal server error")
@ -156,14 +148,12 @@ macro_rules! delete {
pub async fn delete(
request: HttpRequest,
path: actix_web::web::Path<String>,
pool: actix_web::web::Data<Pool>,
identity: actix_identity::Identity,
password_hash: actix_web::web::Data<Vec<u8>>,
) -> Result<actix_web::HttpResponse, actix_web::Error> {
crate::routes::auth(identity, request, &password_hash).await?;
crate::routes::auth(identity, request).await?;
let id = crate::routes::parse_id(&path)?;
match actix_web::web::block(move || crate::queries::$m::delete(id, pool)).await {
match actix_web::web::block(move || crate::queries::$m::delete(id)).await {
Ok(()) => Ok(actix_web::HttpResponse::NoContent().body("Deleted")),
Err(e) => crate::routes::match_find_error(e),
}
@ -176,13 +166,12 @@ macro_rules! random_id {
($m:ident) => {
use rand::distributions::Distribution;
pub async fn random_id(pool: &actix_web::web::Data<Pool>) -> Result<i32, actix_web::Error> {
pub async fn random_id() -> Result<i32, actix_web::Error> {
let mut rng = rand::thread_rng();
let distribution = rand::distributions::Uniform::from(0..i32::max_value());
loop {
let id = distribution.sample(&mut rng);
let pool = pool.clone();
match actix_web::web::block(move || crate::queries::$m::find(id, pool)).await {
match actix_web::web::block(move || crate::queries::$m::find(id)).await {
Ok(_) => continue,
Err(e) => match e {
actix_web::error::BlockingError::Error(e) => match e {
@ -223,12 +212,8 @@ static HIGHLIGHT_CONTENTS: &str = include_str!("../resources/highlight.html");
const HIGHLIGHT_LANGUAGE: &str = r#"<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.15.10/languages/{{ language }}.min.js"></script>"#;
/// Index page letting users upload via a UI
pub async fn index(
request: HttpRequest,
identity: Identity,
password_hash: web::Data<Vec<u8>>,
) -> impl Responder {
if let Err(response) = auth(identity, request, &password_hash).await {
pub async fn index(request: HttpRequest, identity: Identity) -> impl Responder {
if let Err(response) = auth(identity, request).await {
return response;
}
@ -242,21 +227,15 @@ pub async fn index(
INDEX_CONTENTS.to_owned()
}
};
HttpResponse::Ok()
.header("Content-Type", "text/html")
.body(contents)
}
/// GET the config info
pub async fn get_config(
request: HttpRequest,
config: web::Data<Config>,
identity: Identity,
password_hash: web::Data<Vec<u8>>,
) -> impl Responder {
match auth(identity, request, &password_hash).await {
Ok(_) => HttpResponse::Ok().json(config.get_ref()),
pub async fn get_config(request: HttpRequest, identity: Identity) -> impl Responder {
match auth(identity, request).await {
Ok(_) => HttpResponse::Ok().json(&*CONFIG),
Err(response) => response,
}
}
@ -276,10 +255,9 @@ pub async fn logout(identity: Identity) -> impl Responder {
pub mod files {
use crate::routes::match_replace_result;
use crate::{
globals::CONFIG,
queries::{self, SelectQuery},
routes::{auth, match_find_error, parse_id},
setup::Config,
Pool,
};
use actix_files::NamedFile;
use actix_identity::Identity;
@ -298,15 +276,11 @@ pub mod files {
random_id!(files);
/// GET a file entry and statically serve it
pub async fn get(
path: web::Path<String>,
pool: web::Data<Pool>,
config: web::Data<Config>,
) -> Result<NamedFile, Error> {
pub async fn get(path: web::Path<String>) -> Result<NamedFile, Error> {
let id = parse_id(&path)?;
match web::block(move || queries::files::find(id, pool)).await {
match web::block(move || queries::files::find(id)).await {
Ok(file) => {
let mut path = config.files_dir.clone();
let mut path = CONFIG.files_dir.clone();
path.push(file.filepath);
match NamedFile::open(&path) {
Ok(nf) => Ok(nf),
@ -318,13 +292,8 @@ pub mod files {
}
/// Common code for PUT and POST routes
async fn put_post(
id: i32,
mut body: Multipart,
pool: web::Data<Pool>,
config: web::Data<Config>,
) -> Result<HttpResponse, Error> {
let mut path = config.files_dir.clone();
async fn put_post(id: i32, mut body: Multipart) -> Result<HttpResponse, Error> {
let mut path = CONFIG.files_dir.clone();
let mut relative_path = PathBuf::new();
let dir_path = path.clone();
if web::block(move || fs::create_dir_all(dir_path))
@ -356,7 +325,11 @@ pub mod files {
Some(n) => n,
None => return Err(HttpResponse::BadRequest().body("Missing filename").into()),
};
let filename = format!("{:x}.{}", Utc::now().timestamp(), filename);
let filename = format!(
"{}.{}",
radix_fmt::radix_36(Utc::now().timestamp()),
filename
);
path.push(&filename);
relative_path.push(&filename);
let relative_path = match path.to_str() {
@ -402,7 +375,7 @@ pub mod files {
}
match_replace_result(
web::block(move || queries::files::replace(id, &relative_path, pool)).await,
web::block(move || queries::files::replace(id, &relative_path)).await,
id,
)
}
@ -412,28 +385,22 @@ pub mod files {
request: HttpRequest,
path: web::Path<String>,
body: Multipart,
pool: web::Data<Pool>,
config: web::Data<Config>,
identity: Identity,
password_hash: web::Data<Vec<u8>>,
) -> Result<HttpResponse, Error> {
auth(identity, request, &password_hash).await?;
auth(identity, request).await?;
let id = parse_id(&path)?;
put_post(id, body, pool, config).await
put_post(id, body).await
}
/// POST a new file entry using a multipart body
pub async fn post(
request: HttpRequest,
body: Multipart,
pool: web::Data<Pool>,
config: web::Data<Config>,
identity: Identity,
password_hash: web::Data<Vec<u8>>,
) -> Result<HttpResponse, Error> {
auth(identity, request, &password_hash).await?;
let id = random_id(&pool).await?;
put_post(id, body, pool, config).await
auth(identity, request).await?;
let id = random_id().await?;
put_post(id, body).await
}
}
@ -443,7 +410,6 @@ pub mod links {
routes::{
auth, match_find_error, match_replace_result, parse_id, timestamp_to_last_modified,
},
Pool,
};
use actix_identity::Identity;
use actix_web::{web, Error, HttpRequest, HttpResponse};
@ -453,12 +419,9 @@ pub mod links {
random_id!(links);
/// GET a link entry and redirect to it
pub async fn get(
path: web::Path<String>,
pool: web::Data<Pool>,
) -> Result<HttpResponse, Error> {
pub async fn get(path: web::Path<String>) -> Result<HttpResponse, Error> {
let id = parse_id(&path)?;
match web::block(move || queries::links::find(id, pool)).await {
match web::block(move || queries::links::find(id)).await {
Ok(link) => Ok(HttpResponse::Found()
.header("Location", link.forward)
.header("Last-Modified", timestamp_to_last_modified(link.created))
@ -478,14 +441,12 @@ pub mod links {
request: HttpRequest,
path: web::Path<String>,
body: web::Json<PutPostLink>,
pool: web::Data<Pool>,
identity: Identity,
password_hash: web::Data<Vec<u8>>,
) -> Result<HttpResponse, Error> {
auth(identity, request, &password_hash).await?;
auth(identity, request).await?;
let id = parse_id(&path)?;
match_replace_result(
web::block(move || queries::links::replace(id, &body.forward, pool)).await,
web::block(move || queries::links::replace(id, &body.forward)).await,
id,
)
}
@ -494,14 +455,12 @@ pub mod links {
pub async fn post(
request: HttpRequest,
body: web::Json<PutPostLink>,
pool: web::Data<Pool>,
identity: Identity,
password_hash: web::Data<Vec<u8>>,
) -> Result<HttpResponse, Error> {
auth(identity, request, &password_hash).await?;
let id = random_id(&pool).await?;
auth(identity, request).await?;
let id = random_id().await?;
match_replace_result(
web::block(move || queries::links::replace(id, &body.forward, pool)).await,
web::block(move || queries::links::replace(id, &body.forward)).await,
id,
)
}
@ -509,16 +468,15 @@ pub mod links {
pub mod texts {
use crate::routes::escape_html;
use crate::{
globals::CONFIG,
routes::{HIGHLIGHT_CONTENTS, HIGHLIGHT_LANGUAGE},
};
use crate::{
queries::{self, SelectQuery},
routes::{
auth, match_find_error, match_replace_result, parse_id, timestamp_to_last_modified,
},
Pool,
};
use crate::{
routes::{HIGHLIGHT_CONTENTS, HIGHLIGHT_LANGUAGE},
setup::Config,
};
use actix_identity::Identity;
use actix_web::{web, Error, HttpRequest, HttpResponse};
@ -528,17 +486,13 @@ pub mod texts {
random_id!(texts);
/// GET a text entry and display it
pub async fn get(
config: web::Data<Config>,
path: web::Path<String>,
pool: web::Data<Pool>,
) -> Result<HttpResponse, Error> {
pub async fn get(path: web::Path<String>) -> Result<HttpResponse, Error> {
let id = parse_id(&path)?;
match web::block(move || queries::texts::find(id, pool)).await {
match web::block(move || queries::texts::find(id)).await {
Ok(text) => {
let last_modified = timestamp_to_last_modified(text.created);
if text.highlight {
let languages: Vec<String> = config
let languages: Vec<String> = CONFIG
.highlight
.languages
.iter()
@ -547,7 +501,7 @@ pub mod texts {
let languages = languages.join("\n");
let contents = HIGHLIGHT_CONTENTS
.replace("{{ title }}", &path)
.replace("{{ theme }}", &config.highlight.theme)
.replace("{{ theme }}", &CONFIG.highlight.theme)
.replace("{{ contents }}", &escape_html(&text.contents))
.replace("{{ languages }}", &languages);
@ -577,15 +531,12 @@ pub mod texts {
request: HttpRequest,
path: web::Path<String>,
body: web::Json<PutPostText>,
pool: web::Data<Pool>,
identity: Identity,
password_hash: web::Data<Vec<u8>>,
) -> Result<HttpResponse, Error> {
auth(identity, request, &password_hash).await?;
auth(identity, request).await?;
let id = parse_id(&path)?;
match_replace_result(
web::block(move || queries::texts::replace(id, &body.contents, body.highlight, pool))
.await,
web::block(move || queries::texts::replace(id, &body.contents, body.highlight)).await,
id,
)
}
@ -594,15 +545,12 @@ pub mod texts {
pub async fn post(
request: HttpRequest,
body: web::Json<PutPostText>,
pool: web::Data<Pool>,
identity: Identity,
password_hash: web::Data<Vec<u8>>,
) -> Result<HttpResponse, Error> {
auth(identity, request, &password_hash).await?;
let id = random_id(&pool).await?;
auth(identity, request).await?;
let id = random_id().await?;
match_replace_result(
web::block(move || queries::texts::replace(id, &body.contents, body.highlight, pool))
.await,
web::block(move || queries::texts::replace(id, &body.contents, body.highlight)).await,
id,
)
}

View File

@ -1,8 +1,7 @@
//! Utilities used during the initial setup
use crate::Pool;
use crate::{globals::KEY, Pool};
use actix_web::middleware::Logger;
use blake2::{Blake2b, Digest};
use diesel::{
r2d2::{self, ConnectionManager},
sqlite::SqliteConnection,
@ -51,10 +50,8 @@ pub fn get_password_path() -> PathBuf {
}
/// Returns the BLAKE2b digest of the input string
pub fn hash<T: AsRef<[u8]>>(input: T) -> Vec<u8> {
let mut hasher = Blake2b::new();
hasher.input(input);
hasher.result().to_vec()
pub fn hash(input: &[u8]) -> Vec<u8> {
blake3::keyed_hash(KEY, input).as_bytes().to_vec()
}
/// Returns an environment variable and panic if it isn't found
@ -294,7 +291,7 @@ pub fn init() -> Config {
}
}
let password_hash = hash(&password);
let password_hash = hash(password.as_bytes());
fs::write(&password_path, password_hash.as_slice()).unwrap_or_else(|e| {
eprintln!("Can't write password: {}", e);
process::exit(1);