diff --git a/Cargo.lock b/Cargo.lock index f8837a1..f0ada55 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -16,6 +16,15 @@ name = "arc-swap" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "argon2rs" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "blake2-rfc 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)", + "scoped_threadpool 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "array-macro" version = "1.0.2" @@ -69,6 +78,15 @@ name = "bitflags" version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "blake2-rfc" +version = "0.2.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "arrayvec 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", + "constant_time_eq 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "build_const" version = "0.2.1" @@ -88,6 +106,14 @@ dependencies = [ "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "cargon" +version = "0.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "gcc 0.3.55 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "cc" version = "1.0.22" @@ -116,6 +142,11 @@ dependencies = [ "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "constant_time_eq" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "core-foundation" version = "0.2.3" @@ -153,6 +184,15 @@ dependencies = [ "smallvec 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "crossbeam-deque" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "crossbeam-epoch 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-utils 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "crossbeam-deque" version = "0.6.1" @@ -162,6 +202,20 @@ dependencies = [ "crossbeam-utils 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "crossbeam-epoch" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "arrayvec 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-utils 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "nodrop 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", + "scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "crossbeam-epoch" version = "0.5.2" @@ -175,6 +229,14 @@ dependencies = [ "scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "crossbeam-utils" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cfg-if 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "crossbeam-utils" version = "0.5.0" @@ -202,6 +264,11 @@ dependencies = [ "xi-unicode 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "data-encoding" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "docopt" version = "1.0.1" @@ -219,6 +286,11 @@ name = "dtoa" version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "either" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "encoding_rs" version = "0.8.6" @@ -255,6 +327,14 @@ dependencies = [ "num-traits 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "error-chain" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "backtrace 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "failure" version = "0.1.2" @@ -330,6 +410,11 @@ dependencies = [ "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "gcc" +version = "0.3.55" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "h2" version = "0.1.12" @@ -474,6 +559,14 @@ dependencies = [ "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "itertools" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "either 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "itoa" version = "0.4.2" @@ -526,6 +619,29 @@ dependencies = [ "crc 1.8.1 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "libpasta" +version = "0.1.0-rc0" +source = "git+https://github.com/scottlamb/libpasta?branch=pr-default-ring#074ce9d815b1d5e9639b3a8b4b1be5051fe5f074" +dependencies = [ + "argon2rs 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", + "cargon 0.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "data-encoding 2.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", + "itertools 0.7.8 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", + "ring 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)", + "ring-pwhash 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rpassword 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rust-crypto 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.75 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.75 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_mcf 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_yaml 0.7.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "libsqlite3-sys" version = "0.9.3" @@ -541,6 +657,11 @@ name = "linked-hash-map" version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "linked-hash-map" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "lock_api" version = "0.1.3" @@ -680,10 +801,12 @@ dependencies = [ name = "moonfire-db" version = "0.0.1" dependencies = [ + "blake2-rfc 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)", + "libpasta 0.1.0-rc0 (git+https://github.com/scottlamb/libpasta?branch=pr-default-ring)", "log 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", "lru-cache 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "moonfire-base 0.0.1", @@ -997,6 +1120,16 @@ dependencies = [ "proc-macro2 0.4.13 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "rand" +version = "0.3.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "rand" version = "0.4.3" @@ -1024,6 +1157,25 @@ name = "rand_core" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "rayon" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rayon-core 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rayon-core" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "crossbeam-deque 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)", + "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "redox_syscall" version = "0.1.40" @@ -1099,6 +1251,38 @@ dependencies = [ "uuid 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "ring" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "gcc 0.3.55 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)", + "rayon 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)", + "untrusted 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "ring-pwhash" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "data-encoding 2.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)", + "ring 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rpassword" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "rusqlite" version = "0.14.0" @@ -1110,11 +1294,28 @@ dependencies = [ "time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "rust-crypto" +version = "0.2.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "gcc 0.3.55 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", + "time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "rustc-demangle" version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "rustc-serialize" +version = "0.3.24" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "rustc_version" version = "0.2.3" @@ -1147,6 +1348,11 @@ name = "scoped-tls" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "scoped_threadpool" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "scopeguard" version = "0.3.3" @@ -1190,6 +1396,14 @@ name = "serde" version = "1.0.75" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "serde_bytes" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "serde 1.0.75 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "serde_derive" version = "1.0.75" @@ -1205,11 +1419,27 @@ name = "serde_json" version = "1.0.26" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ + "indexmap 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "itoa 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "ryu 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.75 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "serde_mcf" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "data-encoding 2.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.75 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_bytes 0.10.4 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.75 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.26 (registry+https://github.com/rust-lang/crates.io-index)", + "toml 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "serde_urlencoded" version = "0.5.3" @@ -1221,6 +1451,17 @@ dependencies = [ "url 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "serde_yaml" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "dtoa 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", + "linked-hash-map 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.75 (registry+https://github.com/rust-lang/crates.io-index)", + "yaml-rust 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "signal-hook" version = "0.1.4" @@ -1600,6 +1841,11 @@ dependencies = [ "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "untrusted" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "url" version = "1.7.1" @@ -1703,10 +1949,19 @@ name = "xi-unicode" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "yaml-rust" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "linked-hash-map 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + [metadata] "checksum adler32 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7e522997b529f05601e05166c07ed17789691f562762c7f3b987263d2dedee5c" "checksum aho-corasick 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c1c6d463cbe7ed28720b5b489e7c083eeb8f90d08be2a0d6bb9e1ffea9ce1afa" "checksum arc-swap 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f753d9b7c861f9f426fdb10479e35ffef7eaa4359d7c3595610645459df8849a" +"checksum argon2rs 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "3f67b0b6a86dae6e67ff4ca2b6201396074996379fba2b92ff649126f37cb392" "checksum array-macro 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "8b1b1a00de235e9f2cc0e650423dc249d875c116a5934188c08fdd0c02d840ef" "checksum arrayvec 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)" = "a1e964f9e24d588183fcb43503abda40d288c8657dfc27311516ce2f05675aef" "checksum backtrace 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "89a47830402e9981c5c41223151efcced65a0510c13097c769cede7efb34782a" @@ -1714,27 +1969,36 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum base64 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)" = "85415d2594767338a74a30c1d370b2f3262ec1b4ed2d7bba5b3faf4de40467d9" "checksum bitflags 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4efd02e230a02e18f92fc2735f44597385ed02ad8f831e7c1c1156ee5e1ab3a5" "checksum bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "228047a76f468627ca71776ecdebd732a3423081fcf5125585bcd7c49886ce12" +"checksum blake2-rfc 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)" = "5d6d530bdd2d52966a6d03b7a964add7ae1a288d25214066fd4b600f0f796400" "checksum build_const 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "39092a32794787acd8525ee150305ff051b0aa6cc2abaf193924f5ab05425f39" "checksum byteorder 1.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8389c509ec62b9fe8eca58c502a0acaf017737355615243496cde4994f8fa4f9" "checksum bytes 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)" = "e178b8e0e239e844b083d5a0d4a156b2654e67f9f80144d48398fcd736a24fb8" +"checksum cargon 0.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "828332c08f2453409faf99af40e4a9e26c9b28790a9445c135e34c7996a25fb3" "checksum cc 1.0.22 (registry+https://github.com/rust-lang/crates.io-index)" = "4a6007c146fdd28d4512a794b07ffe9d8e89e6bf86e2e0c4ddff2e1fb54a0007" "checksum cfg-if 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "0c4e7bb64a8ebb0d856483e1e682ea3422f883c5f5615a90d51a2c82fe87fdd3" "checksum chrono 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e48d85528df61dc964aa43c5f6ca681a19cfa74939b2348d204bd08a981f2fb0" "checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" +"checksum constant_time_eq 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8ff012e225ce166d4422e0e78419d901719760f62ae2b7969ca6b564d1b54a9e" "checksum core-foundation 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "25bfd746d203017f7d5cbd31ee5d8e17f94b6521c7af77ece6c9e4b2d4b16c67" "checksum core-foundation-sys 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "065a5d7ffdcbc8fa145d6f0746f3555025b9097a9e9cda59f7467abae670c78d" "checksum crc 1.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d663548de7f5cca343f1e0a48d14dcfb0e9eb4e079ec58883b7251539fa10aeb" "checksum crossbeam-channel 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "6c0a94250b0278d7fc5a894c3d276b11ea164edc8bf8feb10ca1ea517b44a649" +"checksum crossbeam-deque 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f739f8c5363aca78cfb059edf753d8f0d36908c348f3d8d1503f03d8b75d9cf3" "checksum crossbeam-deque 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3486aefc4c0487b9cb52372c97df0a48b8c249514af1ee99703bf70d2f2ceda1" +"checksum crossbeam-epoch 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "927121f5407de9956180ff5e936fe3cf4324279280001cd56b669d28ee7e9150" "checksum crossbeam-epoch 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "30fecfcac6abfef8771151f8be4abc9e4edc112c2bcb233314cafde2680536e9" +"checksum crossbeam-utils 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2760899e32a1d58d5abb31129f8fae5de75220bc2176e77ff7c627ae45c918d9" "checksum crossbeam-utils 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "677d453a17e8bd2b913fa38e8b9cf04bcdbb5be790aa294f2389661d72036015" "checksum cursive 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e7024f124e4645e285879af7b54ea466dabfed91d16c3d8049df7a4e4c36d8bd" +"checksum data-encoding 2.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "67df0571a74bf0d97fb8b2ed22abdd9a48475c96bd327db968b7d9cace99655e" "checksum docopt 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d60c92df70dfaaabecc14b409fd79f55ba0f247780529db1d73bfa601e1d3ac0" "checksum dtoa 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6d301140eb411af13d3115f9a562c85cc6b541ade9dfa314132244aaee7489dd" +"checksum either 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3be565ca5c557d7f59e7cfcf1844f9e3033650c929c6566f511e8005f205c1d0" "checksum encoding_rs 0.8.6 (registry+https://github.com/rust-lang/crates.io-index)" = "2a91912d6f37c6a8fef8a2316a862542d036f13c923ad518b5aca7bcaac7544c" "checksum enum-map 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "caa1769f019df7ccd8f9a741d2d608309688d0f1bd8a8747c14ac993660c761c" "checksum enum-map-derive 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f915c8ef505ce27b6fa51515463938aa2e9135081fefc93aef786539a646a365" "checksum enumset 0.3.11 (registry+https://github.com/rust-lang/crates.io-index)" = "81193cae36d896445dae43f89be4fd6a171aad6bd674acb7e7074d50bbce6940" +"checksum error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ff511d5dc435d703f4971bc399647c9bc38e20cb41452e3b9feb4765419ed3f3" "checksum failure 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7efb22686e4a466b1ec1a15c2898f91fa9cb340452496dca654032de20ff95b9" "checksum failure_derive 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "946d0e98a50d9831f5d589038d2ca7f8f455b1c21028c0db0e84116a12696426" "checksum flate2 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "37847f133aae7acf82bb9577ccd8bda241df836787642654286e79679826a54b" @@ -1745,6 +2009,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" "checksum futures 0.1.23 (registry+https://github.com/rust-lang/crates.io-index)" = "884dbe32a6ae4cd7da5c6db9b78114449df9953b8d490c9d7e1b51720b922c62" "checksum futures-cpupool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "ab90cde24b3319636588d0c35fe03b1333857621051837ed769faefb4c2162e4" +"checksum gcc 0.3.55 (registry+https://github.com/rust-lang/crates.io-index)" = "8f5f3913fa0bfe7ee1fd8248b6b9f42a5af4b9d65ec2dd2c3c26132b950ecfc2" "checksum h2 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "a27e7ed946e8335bdf9a191bc1b9b14a03ba822d013d2f58437f4fabcbd7fc2c" "checksum http 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "dca621d0fa606a5ff2850b6e337b57ad6137ee4d67e940449643ff45af6874c6" "checksum http-serve 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "393ee8e71920168e84fa80efcd300bf90435118eb037f674aae92e28f82ec5ef" @@ -1756,6 +2021,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum idna 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "38f09e0f0b1fb55fdee1f17470ad800da77af5186a1a76c026b679358b7e844e" "checksum indexmap 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "08173ba1e906efb6538785a8844dd496f5d34f0a2d88038e95195172fc667220" "checksum iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dbe6e417e7d0975db6512b90796e8ce223145ac4e33c377e4a42882a0e88bb08" +"checksum itertools 0.7.8 (registry+https://github.com/rust-lang/crates.io-index)" = "f58856976b776fedd95533137617a02fb25719f40e7d9b01c7043cd65474f450" "checksum itoa 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "5adb58558dcd1d786b5f0bd15f3226ee23486e24b7b58304b60f64dc68e62606" "checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" "checksum language-tags 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a91d884b6667cd606bb5a69aa0c99ba811a115fc68915e7056ec08a46e93199a" @@ -1764,8 +2030,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum lazycell 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a6f08839bc70ef4a3fe1d566d5350f519c5912ea86be0df1740a7d247c7fc0ef" "checksum libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)" = "76e3a3ef172f1a0b9a9ff0dd1491ae5e6c948b94479a3021819ba7d860c8645d" "checksum libflate 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "7d4b4c7aff5bac19b956f693d0ea0eade8066deb092186ae954fa6ba14daab98" +"checksum libpasta 0.1.0-rc0 (git+https://github.com/scottlamb/libpasta?branch=pr-default-ring)" = "" "checksum libsqlite3-sys 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d3711dfd91a1081d2458ad2d06ea30a8755256e74038be2ad927d94e1c955ca8" "checksum linked-hash-map 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7860ec297f7008ff7a1e3382d7f7e1dcd69efc94751a2284bafc3d013c2aa939" +"checksum linked-hash-map 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "70fb39025bc7cdd76305867c4eccf2f2dcf6e9a57f5b21a93e1c2d86cd03ec9e" "checksum lock_api 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "949826a5ccf18c1b3a7c3d57692778d21768b79e46eb9dd07bfc4c2160036c54" "checksum log 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "cba860f648db8e6f269df990180c2217f333472b4a6e901e97446858487971e2" "checksum lru-cache 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4d06ff7ff06f729ce5f4e227876cb88d10bc59cd4ae1e09fbb2bde15c850dc21" @@ -1808,9 +2076,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum proc-macro2 0.4.13 (registry+https://github.com/rust-lang/crates.io-index)" = "ee5697238f0d893c7f0ecc59c0999f18d2af85e424de441178bcacc9f9e6cf67" "checksum protobuf 2.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "128a4f37a2df739a567a8685b17f54aa19b9c3c4a6a5b8731e97a419b3db451c" "checksum quote 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)" = "dd636425967c33af890042c483632d33fa7a18f19ad1d7ea72e8998c6ef8dea5" +"checksum rand 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)" = "15a732abf9d20f0ad8eeb6f909bf6868722d9a06e1e50802b6a70351f40b4eb1" "checksum rand 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8356f47b32624fef5b3301c1be97e5944ecdd595409cc5da11d05f211db6cfbd" "checksum rand 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e464cd887e869cddcae8792a4ee31d23c7edd516700695608f5b98c67ee0131c" "checksum rand_core 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "edecf0f94da5551fc9b492093e30b041a891657db7940ee221f9d2f66e82eef2" +"checksum rayon 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b614fe08b6665cb9a231d07ac1364b0ef3cb3698f1239ee0c4c3a88a524f54c8" +"checksum rayon-core 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b055d1e92aba6877574d8fe604a63c8b5df60f60e5982bf7ccbb1338ea527356" "checksum redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)" = "c214e91d3ecf43e9a4e41e578973adeb14b474f2bee858742d127af75a0112b1" "checksum reexport-proc-macro 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "438fe63770eda15baf98e30b4d27ada49b932866307fa04fec24d9043fe63324" "checksum reffers 0.4.2 (git+https://github.com/diwic/reffers-rs)" = "" @@ -1819,22 +2090,31 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum relay 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1576e382688d7e9deecea24417e350d3062d97e32e45d70b1cde65994ff1489a" "checksum remove_dir_all 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3488ba1b9a2084d38645c4c08276a1752dcbf2c7130d74f1569681ad5d2799c5" "checksum reqwest 0.8.8 (registry+https://github.com/rust-lang/crates.io-index)" = "738769ec83daf6c1929dc9dae7d69ed3779b55ae5c356e989dcd3aa677d8486e" +"checksum ring 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)" = "6f7d28b30a72c01b458428e0ae988d4149c20d902346902be881e3edc4bb325c" +"checksum ring-pwhash 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "394374d86779b376a2a0ff4fa4d080f3993420d3a2c2342492df9852ff78c053" +"checksum rpassword 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d127299b02abda51634f14025aec43ae87a7aa7a95202b6a868ec852607d1451" "checksum rusqlite 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c9d9118f1ce84d8d0b67f9779936432fb42bb620cef2122409d786892cce9a3c" +"checksum rust-crypto 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)" = "f76d05d3993fd5f4af9434e8e436db163a12a9d40e1a58a726f27a01dfd12a2a" "checksum rustc-demangle 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "bcfe5b13211b4d78e5c2cadfebd7769197d95c639c35a50057eb4c05de811395" +"checksum rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)" = "dcf128d1287d2ea9d80910b5f1120d0b8eede3fbf1abe91c40d39ea7d51e6fda" "checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" "checksum ryu 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e7c066b8e2923f05d4718a06d2622f189ff362bc642bfade6c6629f0440f3827" "checksum safemem 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e27a8b19b835f7aea908818e871f5cc3a5a186550c30773be987e155e8163d8f" "checksum schannel 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "dc1fabf2a7b6483a141426e1afd09ad543520a77ac49bd03c286e7696ccfd77f" "checksum scoped-tls 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "332ffa32bf586782a3efaeb58f127980944bbc8c4d6913a86107ac2a5ab24b28" +"checksum scoped_threadpool 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "1d51f5df5af43ab3f1360b429fa5e0152ac5ce8c0bd6485cae490332e96846a8" "checksum scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "94258f53601af11e6a49f722422f6e3425c52b06245a5cf9bc09908b174f5e27" "checksum security-framework 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "dfa44ee9c54ce5eecc9de7d5acbad112ee58755239381f687e564004ba4a2332" "checksum security-framework-sys 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "5421621e836278a0b139268f36eee0dc7e389b784dc3f79d8f11aabadf41bead" "checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" "checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" "checksum serde 1.0.75 (registry+https://github.com/rust-lang/crates.io-index)" = "22d340507cea0b7e6632900a176101fea959c7065d93ba555072da90aaaafc87" +"checksum serde_bytes 0.10.4 (registry+https://github.com/rust-lang/crates.io-index)" = "adb6e51a6b3696b301bc221d785f898b4457c619b51d7ce195a6d20baecb37b3" "checksum serde_derive 1.0.75 (registry+https://github.com/rust-lang/crates.io-index)" = "234fc8b737737b148ccd625175fc6390f5e4dacfdaa543cb93a3430d984a9119" "checksum serde_json 1.0.26 (registry+https://github.com/rust-lang/crates.io-index)" = "44dd2cfde475037451fa99b7e5df77aa3cfd1536575fa8e7a538ab36dcde49ae" +"checksum serde_mcf 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6a8e71f1e2ddef2fb0451a9fcf2d975d05aac7fb6e452de01da13bff1b4c46cd" "checksum serde_urlencoded 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "aaed41d9fb1e2f587201b863356590c90c1157495d811430a0c0325fe8169650" +"checksum serde_yaml 0.7.5 (registry+https://github.com/rust-lang/crates.io-index)" = "ef8099d3df28273c99a1728190c7a9f19d444c941044f64adf986bee7ec53051" "checksum signal-hook 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "bfc9a251608ddaef559cd5b08b539cbda8c36d0efe0506f9a864765d75dbd665" "checksum siphasher 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "0b8de496cf83d4ed58b6be86c3a275b8602f6ffe98d3024a869e124147a9a3ac" "checksum slab 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5f9776d6b986f77b35c6cf846c11ad986ff128fe0b2b63a3628e3755e8d3102d" @@ -1876,6 +2156,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "882386231c45df4700b275c7ff55b6f3698780a650026380e72dabe76fa46526" "checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" "checksum unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "382810877fe448991dfc7f0dd6e3ae5d58088fd0ea5e35189655f84e6814fa56" +"checksum untrusted 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f392d7819dbe58833e26872f5f6f0d68b7bbbe90fc3667e98731c4a15ad9a7ae" "checksum url 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2a321979c09843d272956e73700d12c4e7d3d92b2ee112b31548aef0d4efc5a6" "checksum utf8-ranges 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "662fab6525a98beff2921d7f61a39e7d59e0b425ebc7d0d9e66d316e55124122" "checksum uuid 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e1436e58182935dcd9ce0add9ea0b558e8a87befe01c1a301e6020aeb0876363" @@ -1891,3 +2172,4 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" "checksum ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d59cefebd0c892fa2dd6de581e937301d8552cb44489cdff035c6187cb63fa5e" "checksum xi-unicode 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "12ea8eda4b1eb72f02d148402e23832d56a33f55d8c1b2d5bcdde91d79d47cb1" +"checksum yaml-rust 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "95acf0db5515d07da9965ec0e0ba6cc2d825e2caeb7303b66ca441729801254e" diff --git a/db/Cargo.toml b/db/Cargo.toml index 35f3469..b6960eb 100644 --- a/db/Cargo.toml +++ b/db/Cargo.toml @@ -11,10 +11,12 @@ nightly = [] path = "lib.rs" [dependencies] +blake2-rfc = "0.2.18" failure = "0.1.1" fnv = "1.0" lazy_static = "1.0" libc = "0.2" +libpasta = { git = "https://github.com/scottlamb/libpasta", branch = "pr-default-ring" } log = "0.4" lru-cache = "0.1" moonfire-base = { path = "../base" } diff --git a/db/auth.rs b/db/auth.rs new file mode 100644 index 0000000..18e879c --- /dev/null +++ b/db/auth.rs @@ -0,0 +1,897 @@ +// This file is part of Moonfire NVR, a security camera digital video recorder. +// Copyright (C) 2018 Scott Lamb +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// In addition, as a special exception, the copyright holders give +// permission to link the code of portions of this program with the +// OpenSSL library under certain conditions as described in each +// individual source file, and distribute linked combinations including +// the two. +// +// You must obey the GNU General Public License in all respects for all +// of the code used other than OpenSSL. If you modify file(s) with this +// exception, you may extend this exception to your version of the +// file(s), but you are not obligated to do so. If you do not wish to do +// so, delete this exception statement from your version. If you delete +// this exception statement from all source files in the program, then +// also delete it here. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +use base::strutil; +use blake2_rfc::blake2b::blake2b; +use failure::Error; +use fnv::FnvHashMap; +use libpasta; +use rusqlite::{Connection, Transaction}; +use std::collections::BTreeMap; +use std::fmt; +use std::net::IpAddr; + +lazy_static! { + static ref PASTA_CONFIG: libpasta::Config = if cfg!(test) { + // In test builds, use bcrypt with the cost turned down. Password hash functions are + // designed to be slow; when run un-optimized, they're unpleasantly slow with default + // settings. Security doesn't matter for cfg(test). + libpasta::Config::with_primitive(libpasta::primitives::Bcrypt::new(2)) + } else { + libpasta::Config::default() + }; +} + +enum UserFlags { + Disabled = 1, +} + +#[derive(Debug)] +pub struct User { + pub id: i32, + pub username: String, + pub flags: i32, + password_hash: Option, + pub password_id: i32, + pub password_failure_count: i64, + pub unix_uid: Option, + + /// True iff this `User` has changed since the last flush. + /// Only a couple things are flushed lazily: `password_failure_count` and (on upgrade to a new + /// algorithm) `password_hash`. + dirty: bool, +} + +impl User { + pub fn change(&self) -> UserChange { + UserChange { + id: Some(self.id), + username: self.username.to_string(), + flags: self.flags, + set_password_hash: None, + unix_uid: self.unix_uid, + } + } + + pub fn has_password(&self) -> bool { self.password_hash.is_some() } + fn disabled(&self) -> bool { (self.flags & UserFlags::Disabled as i32) != 0 } +} + +/// A change to a user. +/// +/// * an insertion returned via `UserChange::add_user`. +/// * an update returned via `User::change`. +/// +/// Apply via `DatabaseGuard::apply_user_change` (which internally calls `auth::State::apply`). +#[derive(Clone, Debug)] +pub struct UserChange { + id: Option, + pub username: String, + pub flags: i32, + set_password_hash: Option>, + pub unix_uid: Option, +} + +impl UserChange { + pub fn add_user(username: String) -> Self { + UserChange { + id: None, + username, + flags: 0, + set_password_hash: None, + unix_uid: None, + } + } + + pub fn set_password(&mut self, pwd: String) { + self.set_password_hash = Some(Some(PASTA_CONFIG.hash_password(&pwd))); + } + + pub fn clear_password(&mut self) { + self.set_password_hash = Some(None); + } + + pub fn disable(&mut self) { + self.flags |= UserFlags::Disabled as i32; + } +} + +#[derive(Clone, Debug, Default)] +pub struct Request { + pub when_sec: Option, + pub user_agent: Option>, + pub addr: Option, +} + +impl Request { + fn addr_buf(&self) -> Option { + match self.addr { + None => None, + Some(IpAddr::V4(ref a)) => Some(IpAddrBuf::V4(a.octets())), + Some(IpAddr::V6(ref a)) => Some(IpAddrBuf::V6(a.octets())), + } + } +} + +enum IpAddrBuf { + V4([u8; 4]), + V6([u8; 16]), +} + +impl AsRef<[u8]> for IpAddrBuf { + fn as_ref(&self) -> &[u8] { + match *self { + IpAddrBuf::V4(ref s) => &s[..], + IpAddrBuf::V6(ref s) => &s[..], + } + } +} + +pub struct FromSqlIpAddr(Option); + +impl rusqlite::types::FromSql for FromSqlIpAddr { + fn column_result(value: rusqlite::types::ValueRef) -> rusqlite::types::FromSqlResult { + use rusqlite::types::ValueRef; + match value { + ValueRef::Null => Ok(FromSqlIpAddr(None)), + ValueRef::Blob(ref b) => { + match b.len() { + 4 => { + let mut buf = [0u8; 4]; + buf.copy_from_slice(b); + Ok(FromSqlIpAddr(Some(buf.into()))) + }, + 16 => { + let mut buf = [0u8; 16]; + buf.copy_from_slice(b); + Ok(FromSqlIpAddr(Some(buf.into()))) + }, + _ => Err(rusqlite::types::FromSqlError::InvalidType), + } + }, + _ => Err(rusqlite::types::FromSqlError::InvalidType), + } + } +} + +pub enum SessionFlags { + HttpOnly = 1, + Secure = 2, + SameSite = 4, +} + +#[derive(Copy, Clone)] +pub enum RevocationReason { + LoggedOut = 1, +} + +#[derive(Debug, Default)] +pub struct Session { + user_id: i32, + flags: i32, // bitmask of SessionFlags enum values + domain: Vec, + description: Option, + + creation_password_id: Option, + creation: Request, + + revocation: Request, + revocation_reason: Option, // see RevocationReason enum + revocation_reason_detail: Option, + + last_use: Request, + use_count: i32, + dirty: bool, +} + +/// A raw session id (not base64-encoded). Sensitive. Never stored in the database. +pub struct RawSessionId([u8; 48]); + +impl RawSessionId { + pub fn new() -> Self { RawSessionId([0u8; 48]) } + + fn hash(&self) -> SessionHash { + let r = blake2b(32, &[], &self.0[..]); + let mut h = SessionHash([0u8; 32]); + h.0.copy_from_slice(r.as_bytes()); + h + } +} + +impl AsRef<[u8]> for RawSessionId { + fn as_ref(&self) -> &[u8] { &self.0[..] } +} + +impl AsMut<[u8]> for RawSessionId { + fn as_mut(&mut self) -> &mut [u8] { &mut self.0[..] } +} + +impl fmt::Debug for RawSessionId { + fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { + write!(f, "RawSessionId(\"{}\")", &strutil::hex(&self.0[..])) + } +} + +/// Blake2b-256 of the raw (not base64-encoded) 48-byte session id. +#[derive(Copy, Clone, PartialEq, Eq, Hash)] +pub struct SessionHash([u8; 32]); + +impl fmt::Debug for SessionHash { + fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { + write!(f, "SessionHash(\"{}\")", &strutil::hex(&self.0[..])) + } +} + +pub(crate) struct State { + users_by_id: BTreeMap, + users_by_name: BTreeMap, + + /// Some of the sessions stored in the database. + /// Guaranteed to contain all "dirty" sessions (ones with unflushed changes); may contain + /// others. + /// + /// TODO: Add eviction of clean sessions. Keep a linked hash set of clean session hashes and + /// evict the oldest when its size exceeds a threshold. Or just evict everything on every flush + /// (and accept more frequent database accesses). + sessions: FnvHashMap, +} + +impl State { + pub fn init(conn: &Connection) -> Result { + let mut state = State { + users_by_id: BTreeMap::new(), + users_by_name: BTreeMap::new(), + sessions: FnvHashMap::default(), + }; + let mut stmt = conn.prepare(r#" + select + id, + username, + flags, + password_hash, + password_id, + password_failure_count, + unix_uid + from + user + "#)?; + let mut rows = stmt.query(&[])?; + while let Some(row) = rows.next() { + let row = row?; + let id = row.get_checked(0)?; + let name: String = row.get_checked(1)?; + state.users_by_id.insert(id, User { + id, + username: name.clone(), + flags: row.get_checked(2)?, + password_hash: row.get_checked(3)?, + password_id: row.get_checked(4)?, + password_failure_count: row.get_checked(5)?, + unix_uid: row.get_checked(6)?, + dirty: false, + }); + state.users_by_name.insert(name, id); + } + Ok(state) + } + + pub fn apply(&mut self, conn: &Connection, change: UserChange) -> Result<&User, Error> { + if let Some(id) = change.id { + self.update_user(conn, id, change) + } else { + self.add_user(conn, change) + } + } + + pub fn users_by_id(&self) -> &BTreeMap { &self.users_by_id } + + fn update_user(&mut self, conn: &Connection, id: i32, change: UserChange) + -> Result<&User, Error> { + let mut stmt = conn.prepare_cached(r#" + update user + set + username = :username, + password_hash = :password_hash, + password_id = :password_id, + password_failure_count = :password_failure_count, + flags = :flags, + unix_uid = :unix_uid + where + id = :id + "#)?; + let e = self.users_by_id.entry(id); + let e = match e { + ::std::collections::btree_map::Entry::Vacant(_) => panic!("missing uid {}!", id), + ::std::collections::btree_map::Entry::Occupied(e) => e, + }; + { + let (phash, pid, pcount) = match change.set_password_hash.as_ref() { + None => { + let u = e.get(); + (&u.password_hash, u.password_id, u.password_failure_count) + }, + Some(h) => (h, e.get().password_id + 1, 0), + }; + stmt.execute_named(&[ + (":username", &&change.username[..]), + (":password_hash", phash), + (":password_id", &pid), + (":password_failure_count", &pcount), + (":flags", &change.flags), + (":unix_uid", &change.unix_uid), + (":id", &id), + ])?; + } + let u = e.into_mut(); + u.username = change.username; + if let Some(h) = change.set_password_hash { + u.password_hash = h; + u.password_id += 1; + u.password_failure_count = 0; + } + u.flags = change.flags; + u.unix_uid = change.unix_uid; + Ok(u) + } + + fn add_user(&mut self, conn: &Connection, change: UserChange) -> Result<&User, Error> { + let mut stmt = conn.prepare_cached(r#" + insert into user (username, password_hash, flags, unix_uid) + values (:username, :password_hash, :flags, :unix_uid) + "#)?; + let password_hash = change.set_password_hash.unwrap_or(None); + stmt.execute_named(&[ + (":username", &&change.username[..]), + (":password_hash", &password_hash), + (":flags", &change.flags), + (":unix_uid", &change.unix_uid), + ])?; + let id = conn.last_insert_rowid() as i32; + self.users_by_name.insert(change.username.clone(), id); + let e = self.users_by_id.entry(id); + let e = match e { + ::std::collections::btree_map::Entry::Vacant(e) => e, + ::std::collections::btree_map::Entry::Occupied(_) => panic!("uid {} conflict!", id), + }; + Ok(e.insert(User { + id, + username: change.username, + flags: change.flags, + password_hash, + password_id: 0, + password_failure_count: 0, + unix_uid: change.unix_uid, + dirty: false, + })) + } + + pub fn delete_user(&mut self, conn: &mut Connection, id: i32) -> Result<(), Error> { + let tx = conn.transaction()?; + tx.execute("delete from user_session where user_id = ?", &[&id])?; + { + let mut user_stmt = tx.prepare_cached("delete from user where id = ?")?; + if user_stmt.execute(&[&id])? != 1 { + bail!("user {} not found", id); + } + } + tx.commit()?; + let name = self.users_by_id.remove(&id).unwrap().username; + self.users_by_name.remove(&name).unwrap(); + self.sessions.retain(|_k, ref mut v| v.user_id != id); + Ok(()) + } + + pub fn login_by_password(&mut self, conn: &Connection, req: Request, username: &str, + password: String, domain: Vec, session_flags: i32) + -> Result<(RawSessionId, &Session), Error> { + let id = match self.users_by_name.get(username) { + None => bail!("no such user {:?}", username), + Some(&id) => id, + }; + let u = self.users_by_id.get_mut(&id).expect("users_by_name implies users_by_id"); + if u.disabled() { + bail!("user {:?} is disabled", username); + } + let new_hash = { + let hash = match u.password_hash.as_ref() { + None => bail!("no password set for user {:?}", username), + Some(h) => h, + }; + match PASTA_CONFIG.verify_password_update_hash(hash, &password) { + libpasta::HashUpdate::Failed => { + u.dirty = true; + u.password_failure_count += 1; + bail!("incorrect password for user {:?}", username); + }, + libpasta::HashUpdate::Verified(new_pwd) => new_pwd, + } + }; + if let Some(h) = new_hash { + u.password_hash = Some(h); + u.dirty = true; + } + let password_id = u.password_id; + State::make_session(conn, req, u, domain, Some(password_id), session_flags, + &mut self.sessions) + } + + fn make_session<'s>(conn: &Connection, creation: Request, user: &mut User, domain: Vec, + creation_password_id: Option, flags: i32, + sessions: &'s mut FnvHashMap) + -> Result<(RawSessionId, &'s Session), Error> { + let mut session_id = RawSessionId::new(); + ::openssl::rand::rand_bytes(&mut session_id.0).unwrap(); + let mut seed = [0u8; 32]; + ::openssl::rand::rand_bytes(&mut seed).unwrap(); + let hash = session_id.hash(); + let mut stmt = conn.prepare_cached(r#" + insert into user_session (session_id_hash, user_id, seed, flags, domain, + creation_password_id, creation_time_sec, + creation_user_agent, creation_peer_addr) + values (:session_id_hash, :user_id, :seed, :flags, :domain, + :creation_password_id, :creation_time_sec, + :creation_user_agent, :creation_peer_addr) + "#)?; + let addr = creation.addr_buf(); + let addr: Option<&[u8]> = addr.as_ref().map(|a| a.as_ref()); + stmt.execute_named(&[ + (":session_id_hash", &&hash.0[..]), + (":user_id", &user.id), + (":seed", &&seed[..]), + (":flags", &flags), + (":domain", &domain), + (":creation_password_id", &creation_password_id), + (":creation_time_sec", &creation.when_sec), + (":creation_user_agent", &creation.user_agent), + (":creation_peer_addr", &addr), + ])?; + let e = match sessions.entry(hash) { + ::std::collections::hash_map::Entry::Occupied(_) => panic!("duplicate session hash!"), + ::std::collections::hash_map::Entry::Vacant(e) => e, + }; + let session = e.insert(Session { + user_id: user.id, + flags, + domain, + creation_password_id, + creation, + ..Default::default() + }); + Ok((session_id, session)) + } + + pub fn authenticate_session(&mut self, conn: &Connection, req: Request, + session: &RawSessionId) -> Result<(SessionHash, &User), Error> { + let hash = session.hash(); + let s = match self.sessions.entry(hash) { + ::std::collections::hash_map::Entry::Occupied(e) => e.into_mut(), + ::std::collections::hash_map::Entry::Vacant(e) => e.insert(lookup_session(conn, hash)?), + }; + let u = match self.users_by_id.get(&s.user_id) { + None => bail!("session references nonexistent user!"), + Some(u) => u, + }; + if let Some(r) = s.revocation_reason { + bail!("session is no longer valid (reason={})", r); + } + s.last_use = req; + s.use_count += 1; + s.dirty = true; + if u.disabled() { + bail!("user {:?} is disabled", &u.username); + } + Ok((hash, u)) + } + + pub fn revoke_session(&mut self, conn: &Connection, reason: RevocationReason, + detail: Option, req: Request, hash: SessionHash) + -> Result<(), Error> { + let s = match self.sessions.entry(hash) { + ::std::collections::hash_map::Entry::Occupied(e) => e.into_mut(), + ::std::collections::hash_map::Entry::Vacant(e) => e.insert(lookup_session(conn, hash)?), + }; + if s.revocation_reason.is_none() { + let mut stmt = conn.prepare(r#" + update user_session + set + revocation_time_sec = ?, + revocation_user_agent = ?, + revocation_peer_addr = ?, + revocation_reason = ?, + revocation_reason_detail = ? + where + session_id_hash = ? + "#)?; + let addr = req.addr_buf(); + let addr: Option<&[u8]> = addr.as_ref().map(|a| a.as_ref()); + stmt.execute(&[ + &req.when_sec, + &req.user_agent, + &addr, + &(reason as i32), + &detail, + &&hash.0[..], + ])?; + s.revocation = req; + s.revocation_reason = Some(reason as i32); + } + Ok(()) + } + + pub fn flush(&mut self, tx: &Transaction) -> Result<(), Error> { + let mut u_stmt = tx.prepare(r#" + update user + set + password_failure_count = :password_failure_count, + password_hash = :password_hash + where + id = :id + "#)?; + let mut s_stmt = tx.prepare(r#" + update user_session + set + last_use_time_sec = :last_use_time_sec, + last_use_user_agent = :last_use_user_agent, + last_use_peer_addr = :last_use_peer_addr, + use_count = :use_count + where + session_id_hash = :hash + "#)?; + for (&id, u) in &self.users_by_id { + if !u.dirty { + continue; + } + info!("flushing user with hash: {}", u.password_hash.as_ref().unwrap()); + u_stmt.execute_named(&[ + (":password_failure_count", &u.password_failure_count), + (":password_hash", &u.password_hash), + (":id", &id), + ])?; + } + for (_, s) in &self.sessions { + if !s.dirty { + continue; + } + let addr = s.last_use.addr_buf(); + let addr: Option<&[u8]> = addr.as_ref().map(|a| a.as_ref()); + s_stmt.execute_named(&[ + (":last_use_time_sec", &s.last_use.when_sec), + (":last_use_user_agent", &s.last_use.user_agent), + (":last_use_peer_addr", &addr), + (":use_count", &s.use_count), + ])?; + } + Ok(()) + } + + pub fn post_flush(&mut self) { + for (_, u) in &mut self.users_by_id { + u.dirty = false; + } + for (_, s) in &mut self.sessions { + s.dirty = false; + } + } +} + +fn lookup_session(conn: &Connection, hash: SessionHash) -> Result { + let mut stmt = conn.prepare_cached(r#" + select + user_id, + flags, + domain, + description, + creation_password_id, + creation_time_sec, + creation_user_agent, + creation_peer_addr, + revocation_time_sec, + revocation_user_agent, + revocation_peer_addr, + revocation_reason, + revocation_reason_detail, + last_use_time_sec, + last_use_user_agent, + last_use_peer_addr, + use_count + from + user_session + where + session_id_hash = ? + "#)?; + let mut rows = stmt.query(&[&&hash.0[..]])?; + let row = match rows.next() { + None => bail!("no such session"), + Some(Err(e)) => return Err(e.into()), + Some(Ok(r)) => r, + }; + let creation_addr: FromSqlIpAddr = row.get_checked(7)?; + let revocation_addr: FromSqlIpAddr = row.get_checked(10)?; + let last_use_addr: FromSqlIpAddr = row.get_checked(15)?; + Ok(Session { + user_id: row.get_checked(0)?, + flags: row.get_checked(1)?, + domain: row.get_checked(2)?, + description: row.get_checked(3)?, + creation_password_id: row.get_checked(4)?, + creation: Request { + when_sec: row.get_checked(5)?, + user_agent: row.get_checked(6)?, + addr: creation_addr.0, + }, + revocation: Request { + when_sec: row.get_checked(8)?, + user_agent: row.get_checked(9)?, + addr: revocation_addr.0, + }, + revocation_reason: row.get_checked(11)?, + revocation_reason_detail: row.get_checked(12)?, + last_use: Request { + when_sec: row.get_checked(13)?, + user_agent: row.get_checked(14)?, + addr: last_use_addr.0, + }, + use_count: row.get_checked(16)?, + dirty: false, + }) +} + +#[cfg(test)] +mod tests { + use db; + use rusqlite::Connection; + use super::*; + use testutil; + + #[test] + fn open_empty_db() { + testutil::init(); + let mut conn = Connection::open_in_memory().unwrap(); + db::init(&mut conn).unwrap(); + State::init(&conn).unwrap(); + } + + #[test] + fn create_login_use_logout() { + testutil::init(); + let mut conn = Connection::open_in_memory().unwrap(); + db::init(&mut conn).unwrap(); + let mut state = State::init(&conn).unwrap(); + let req = Request { + when_sec: Some(42), + addr: Some(::std::net::IpAddr::V4(::std::net::Ipv4Addr::new(127, 0, 0, 1))), + user_agent: Some(b"some ua".to_vec()), + }; + let (uid, mut c) = { + let u = state.apply(&conn, UserChange::add_user("slamb".to_owned())).unwrap(); + (u.id, u.change()) + }; + let e = state.login_by_password(&conn, req.clone(), "slamb", "hunter2".to_owned(), + b"nvr.example.com".to_vec(), 0).unwrap_err(); + assert_eq!(format!("{}", e), "no password set for user \"slamb\""); + c.set_password("hunter2".to_owned()); + state.apply(&conn, c).unwrap(); + let e = state.login_by_password(&conn, req.clone(), "slamb", + "hunter3".to_owned(), + b"nvr.example.com".to_vec(), 0).unwrap_err(); + assert_eq!(format!("{}", e), "incorrect password for user \"slamb\""); + let sid = { + let (sid, s) = state.login_by_password(&conn, req.clone(), "slamb", + "hunter2".to_owned(), + b"nvr.example.com".to_vec(), 0).unwrap(); + assert_eq!(s.user_id, uid); + sid + }; + let sid_hash = { + let (sid_hash, u) = state.authenticate_session(&conn, req.clone(), &sid).unwrap(); + assert_eq!(u.id, uid); + sid_hash + }; + state.revoke_session(&conn, RevocationReason::LoggedOut, None, req.clone(), + sid_hash).unwrap(); + let e = state.authenticate_session(&conn, req.clone(), &sid).unwrap_err(); + assert_eq!(format!("{}", e), "session is no longer valid (reason=1)"); + + // Everything should persist across reload. + drop(state); + let mut state = State::init(&conn).unwrap(); + let e = state.authenticate_session(&conn, req, &sid).unwrap_err(); + assert_eq!(format!("{}", e), "session is no longer valid (reason=1)"); + } + + #[test] + fn revoke_not_in_cache() { + testutil::init(); + let mut conn = Connection::open_in_memory().unwrap(); + db::init(&mut conn).unwrap(); + let mut state = State::init(&conn).unwrap(); + let req = Request { + when_sec: Some(42), + addr: Some(::std::net::IpAddr::V4(::std::net::Ipv4Addr::new(127, 0, 0, 1))), + user_agent: Some(b"some ua".to_vec()), + }; + { + let mut c = UserChange::add_user("slamb".to_owned()); + c.set_password("hunter2".to_owned()); + state.apply(&conn, c).unwrap(); + }; + let sid = { + let (sid, _s) = state.login_by_password(&conn, req.clone(), "slamb", + "hunter2".to_owned(), + b"nvr.example.com".to_vec(), 0).unwrap(); + sid + }; + state.authenticate_session(&conn, req.clone(), &sid).unwrap(); + + // Reload. + drop(state); + let mut state = State::init(&conn).unwrap(); + state.revoke_session(&conn, RevocationReason::LoggedOut, None, req.clone(), + sid.hash()).unwrap(); + let e = state.authenticate_session(&conn, req, &sid).unwrap_err(); + assert_eq!(format!("{}", e), "session is no longer valid (reason=1)"); + } + + #[test] + fn upgrade_hash() { + // This hash is generated with cost=1 vs the cost=2 of PASTA_CONFIG. + let insecure_hash = + libpasta::Config::with_primitive(libpasta::primitives::Bcrypt::new(1)) + .hash_password("hunter2"); + testutil::init(); + let mut conn = Connection::open_in_memory().unwrap(); + db::init(&mut conn).unwrap(); + let mut state = State::init(&conn).unwrap(); + let mut change = UserChange::add_user("slamb".to_owned()); + + // hunter2, in insecure MD5. + change.set_password_hash = Some(Some(insecure_hash.clone())); + let uid = { + let u = state.apply(&conn, change).unwrap(); + assert_eq!(&insecure_hash, u.password_hash.as_ref().unwrap()); + u.id + }; + + let req = Request { + when_sec: Some(42), + addr: Some(::std::net::IpAddr::V4(::std::net::Ipv4Addr::new(127, 0, 0, 1))), + user_agent: Some(b"some ua".to_vec()), + }; + state.login_by_password(&conn, req.clone(), "slamb", "hunter2".to_owned(), + b"nvr.example.com".to_vec(), 0).unwrap(); + let new_hash = { + // Password should have been automatically upgraded. + let u = state.users_by_id().get(&uid).unwrap(); + assert!(u.dirty); + assert_ne!(u.password_hash.as_ref().unwrap(), &insecure_hash); + u.password_hash.as_ref().unwrap().clone() + }; + + { + let tx = conn.transaction().unwrap(); + state.flush(&tx).unwrap(); + tx.commit().unwrap(); + } + + // On reload, the new hash should still be visible. + drop(state); + let mut state = State::init(&conn).unwrap(); + { + let u = state.users_by_id().get(&uid).unwrap(); + assert!(!u.dirty); + assert_eq!(u.password_hash.as_ref().unwrap(), &new_hash); + } + + // Login should still work. + state.login_by_password(&conn, req.clone(), "slamb", "hunter2".to_owned(), + b"nvr.example.com".to_vec(), 0).unwrap(); + } + + #[test] + fn disable() { + testutil::init(); + let mut conn = Connection::open_in_memory().unwrap(); + db::init(&mut conn).unwrap(); + let mut state = State::init(&conn).unwrap(); + let req = Request { + when_sec: Some(42), + addr: Some(::std::net::IpAddr::V4(::std::net::Ipv4Addr::new(127, 0, 0, 1))), + user_agent: Some(b"some ua".to_vec()), + }; + let uid = { + let mut c = UserChange::add_user("slamb".to_owned()); + c.set_password("hunter2".to_owned()); + state.apply(&conn, c).unwrap().id + }; + + // Get a session for later. + let sid = state.login_by_password(&conn, req.clone(), "slamb", + "hunter2".to_owned(), + b"nvr.example.com".to_vec(), 0).unwrap().0; + + // Disable the user. + { + let mut c = state.users_by_id().get(&uid).unwrap().change(); + c.disable(); + state.apply(&conn, c).unwrap(); + } + + // Fresh logins shouldn't work. + let e = state.login_by_password(&conn, req.clone(), "slamb", + "hunter2".to_owned(), + b"nvr.example.com".to_vec(), 0).unwrap_err(); + assert_eq!(format!("{}", e), "user \"slamb\" is disabled"); + + // Authenticating existing sessions shouldn't work either. + let e = state.authenticate_session(&conn, req.clone(), &sid).unwrap_err(); + assert_eq!(format!("{}", e), "user \"slamb\" is disabled"); + + // The user should still be disabled after reload. + drop(state); + let mut state = State::init(&conn).unwrap(); + let e = state.authenticate_session(&conn, req, &sid).unwrap_err(); + assert_eq!(format!("{}", e), "user \"slamb\" is disabled"); + } + + #[test] + fn delete() { + testutil::init(); + let mut conn = Connection::open_in_memory().unwrap(); + db::init(&mut conn).unwrap(); + let mut state = State::init(&conn).unwrap(); + let req = Request { + when_sec: Some(42), + addr: Some(::std::net::IpAddr::V4(::std::net::Ipv4Addr::new(127, 0, 0, 1))), + user_agent: Some(b"some ua".to_vec()), + }; + let uid = { + let mut c = UserChange::add_user("slamb".to_owned()); + c.set_password("hunter2".to_owned()); + state.apply(&conn, c).unwrap().id + }; + + // Get a session for later. + let sid = state.login_by_password(&conn, req.clone(), "slamb", + "hunter2".to_owned(), + b"nvr.example.com".to_vec(), 0).unwrap().0; + + state.delete_user(&mut conn, uid).unwrap(); + assert!(state.users_by_id().get(&uid).is_none()); + let e = state.authenticate_session(&conn, req.clone(), &sid).unwrap_err(); + assert_eq!(format!("{}", e), "no such session"); + + // The user should still be deleted after reload. + drop(state); + let mut state = State::init(&conn).unwrap(); + assert!(state.users_by_id().get(&uid).is_none()); + let e = state.authenticate_session(&conn, req.clone(), &sid).unwrap_err(); + assert_eq!(format!("{}", e), "no such session"); + } +} diff --git a/db/db.rs b/db/db.rs index a18adfe..d981c00 100644 --- a/db/db.rs +++ b/db/db.rs @@ -52,6 +52,7 @@ //! A list of mutations is built up in-memory and occasionally flushed to reduce SSD write //! cycles. +use auth; use base::clock::{self, Clocks}; use dir; use failure::Error; @@ -301,6 +302,12 @@ impl SampleFileDir { } } +pub use auth::Request; +pub use auth::RawSessionId; +pub use auth::Session; +pub use auth::User; +pub use auth::UserChange; + /// In-memory state about a camera. #[derive(Debug)] pub struct Camera { @@ -559,6 +566,8 @@ pub struct LockedDatabase { /// mode). open_monotonic: recording::Time, + auth: auth::State, + sample_file_dirs_by_id: BTreeMap, cameras_by_id: BTreeMap, streams_by_id: BTreeMap, @@ -855,6 +864,7 @@ impl LockedDatabase { bail!("unable to find current open {}", o.id); } } + self.auth.flush(&tx)?; tx.commit()?; // Process delete_garbage. @@ -898,6 +908,7 @@ impl LockedDatabase { // Fix the range. s.range = new_range; } + self.auth.post_flush(); info!("Flush (why: {}): added {} recordings, deleted {}, marked {} files GCed.", reason, added, deleted, gced); for cb in &self.on_flush { @@ -1663,12 +1674,41 @@ impl LockedDatabase { } Ok(()) } + + // ---- auth ---- + + pub fn users_by_id(&self) -> &BTreeMap { self.auth.users_by_id() } + + pub fn apply_user_change(&mut self, change: UserChange) -> Result<&User, Error> { + self.auth.apply(&self.conn, change) + } + + pub fn delete_user(&mut self, id: i32) -> Result<(), Error> { + self.auth.delete_user(&mut self.conn, id) + } + + pub fn login_by_password(&mut self, req: auth::Request, username: &str, password: String, + domain: Vec, session_flags: i32) + -> Result<(RawSessionId, &Session), Error> { + self.auth.login_by_password(&self.conn, req, username, password, domain, session_flags) + } + + pub fn authenticate_session(&mut self, req: auth::Request, sid: &auth::RawSessionId) + -> Result<(auth::SessionHash, &User), Error> { + self.auth.authenticate_session(&self.conn, req, sid) + } + + pub fn revoke_session(&mut self, reason: auth::RevocationReason, detail: Option, + req: auth::Request, hash: auth::SessionHash) -> Result<(), Error> { + self.auth.revoke_session(&self.conn, reason, detail, req, hash) + } } /// Initializes a database. /// Note this doesn't set journal options, so that it can be used on in-memory databases for /// test code. pub fn init(conn: &mut rusqlite::Connection) -> Result<(), Error> { + conn.execute("pragma foreign_keys = on", &[])?; let tx = conn.transaction()?; tx.execute_batch(include_str!("schema.sql"))?; { @@ -1764,12 +1804,14 @@ impl Database { uuid, }) } else { None }; + let auth = auth::State::init(&conn)?; let db = Database { db: Some(Mutex::new(LockedDatabase { conn, uuid, open, open_monotonic, + auth, sample_file_dirs_by_id: BTreeMap::new(), cameras_by_id: BTreeMap::new(), cameras_by_uuid: BTreeMap::new(), diff --git a/db/lib.rs b/db/lib.rs index b5fa8e4..4cec967 100644 --- a/db/lib.rs +++ b/db/lib.rs @@ -30,10 +30,12 @@ #![cfg_attr(all(feature="nightly", test), feature(test))] +extern crate blake2_rfc; #[macro_use] extern crate failure; extern crate fnv; #[macro_use] extern crate lazy_static; extern crate libc; +extern crate libpasta; #[macro_use] extern crate log; extern crate lru_cache; extern crate moonfire_base as base; @@ -47,6 +49,7 @@ extern crate tempdir; extern crate time; extern crate uuid; +pub mod auth; pub mod check; mod coding; pub mod db;