initial db layer work for authentication (#26)

This commit is contained in:
Scott Lamb 2018-11-01 23:25:06 -07:00
parent aa81eae65a
commit 75f233da79
5 changed files with 1226 additions and 0 deletions

282
Cargo.lock generated
View File

@ -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)" = "<none>"
"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)" = "<none>"
@ -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"

View File

@ -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" }

897
db/auth.rs Normal file
View File

@ -0,0 +1,897 @@
// This file is part of Moonfire NVR, a security camera digital video recorder.
// Copyright (C) 2018 Scott Lamb <slamb@slamb.org>
//
// 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 <http://www.gnu.org/licenses/>.
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<String>,
pub password_id: i32,
pub password_failure_count: i64,
pub unix_uid: Option<i32>,
/// 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<i32>,
pub username: String,
pub flags: i32,
set_password_hash: Option<Option<String>>,
pub unix_uid: Option<i32>,
}
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<i64>,
pub user_agent: Option<Vec<u8>>,
pub addr: Option<IpAddr>,
}
impl Request {
fn addr_buf(&self) -> Option<IpAddrBuf> {
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<IpAddr>);
impl rusqlite::types::FromSql for FromSqlIpAddr {
fn column_result(value: rusqlite::types::ValueRef) -> rusqlite::types::FromSqlResult<Self> {
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<u8>,
description: Option<String>,
creation_password_id: Option<i32>,
creation: Request,
revocation: Request,
revocation_reason: Option<i32>, // see RevocationReason enum
revocation_reason_detail: Option<String>,
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<i32, User>,
users_by_name: BTreeMap<String, i32>,
/// 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<SessionHash, Session>,
}
impl State {
pub fn init(conn: &Connection) -> Result<Self, Error> {
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<i32, User> { &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<u8>, 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<u8>,
creation_password_id: Option<i32>, flags: i32,
sessions: &'s mut FnvHashMap<SessionHash, Session>)
-> 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<String>, 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<Session, Error> {
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");
}
}

View File

@ -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<i32, SampleFileDir>,
cameras_by_id: BTreeMap<i32, Camera>,
streams_by_id: BTreeMap<i32, Stream>,
@ -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<i32, User> { 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<u8>, 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<String>,
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<C: Clocks + Clone> Database<C> {
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(),

View File

@ -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;