Merge pull request #464 from meilisearch/simplify-keys

Simplify keys & add launcher resume
This commit is contained in:
Clément Renault 2020-02-17 13:59:41 +01:00 committed by GitHub
commit 8e6560d102
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
19 changed files with 274 additions and 368 deletions

76
Cargo.lock generated
View File

@ -153,6 +153,25 @@ name = "bitflags"
version = "1.2.1" version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "block-buffer"
version = "0.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"block-padding 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
"byte-tools 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
"byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
"generic-array 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "block-padding"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"byte-tools 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]] [[package]]
name = "broadcaster" name = "broadcaster"
version = "0.2.6" version = "0.2.6"
@ -182,6 +201,11 @@ name = "bumpalo"
version = "2.6.0" version = "2.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "byte-tools"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]] [[package]]
name = "byteorder" name = "byteorder"
version = "1.3.2" version = "1.3.2"
@ -414,6 +438,14 @@ name = "deunicode"
version = "1.0.0" version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "digest"
version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"generic-array 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]] [[package]]
name = "discard" name = "discard"
version = "1.0.4" version = "1.0.4"
@ -470,6 +502,11 @@ dependencies = [
"synstructure 0.12.2 (registry+https://github.com/rust-lang/crates.io-index)", "synstructure 0.12.2 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]]
name = "fake-simd"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]] [[package]]
name = "fnv" name = "fnv"
version = "1.0.6" version = "1.0.6"
@ -640,6 +677,14 @@ dependencies = [
"slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]]
name = "generic-array"
version = "0.12.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"typenum 1.11.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]] [[package]]
name = "getopts" name = "getopts"
version = "0.2.21" version = "0.2.21"
@ -1043,6 +1088,7 @@ dependencies = [
"serde 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_json 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_qs 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "serde_qs 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
"sha2 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
"siphasher 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "siphasher 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
"structopt 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", "structopt 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
"sysinfo 0.9.6 (registry+https://github.com/rust-lang/crates.io-index)", "sysinfo 0.9.6 (registry+https://github.com/rust-lang/crates.io-index)",
@ -1202,6 +1248,11 @@ name = "once_cell"
version = "1.2.0" version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "opaque-debug"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]] [[package]]
name = "ordered-float" name = "ordered-float"
version = "1.0.2" version = "1.0.2"
@ -1649,6 +1700,17 @@ name = "sha1"
version = "0.6.0" version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "sha2"
version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"block-buffer 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)",
"digest 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
"fake-simd 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"opaque-debug 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]] [[package]]
name = "siphasher" name = "siphasher"
version = "0.3.1" version = "0.3.1"
@ -2043,6 +2105,11 @@ name = "try-lock"
version = "0.2.2" version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "typenum"
version = "1.11.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]] [[package]]
name = "unicode-bidi" name = "unicode-bidi"
version = "0.3.4" version = "0.3.4"
@ -2377,9 +2444,12 @@ dependencies = [
"checksum base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0b25d992356d2eb0ed82172f5248873db5560c4721f564b13cb5193bda5e668e" "checksum base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0b25d992356d2eb0ed82172f5248873db5560c4721f564b13cb5193bda5e668e"
"checksum bincode 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b8ab639324e3ee8774d296864fbc0dbbb256cf1a41c490b94cba90c082915f92" "checksum bincode 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b8ab639324e3ee8774d296864fbc0dbbb256cf1a41c490b94cba90c082915f92"
"checksum bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" "checksum bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
"checksum block-buffer 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c0940dc441f31689269e10ac70eb1002a3a1d3ad1390e030043662eb7fe4688b"
"checksum block-padding 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "fa79dedbb091f449f1f39e53edf88d5dbe95f895dae6135a8d7b881fb5af73f5"
"checksum broadcaster 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "07a1446420a56f1030271649ba0da46d23239b3a68c73591cea5247f15a788a0" "checksum broadcaster 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "07a1446420a56f1030271649ba0da46d23239b3a68c73591cea5247f15a788a0"
"checksum bstr 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "8d6c2c5b58ab920a4f5aeaaca34b4488074e8cc7596af94e6f8c6ff247c60245" "checksum bstr 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "8d6c2c5b58ab920a4f5aeaaca34b4488074e8cc7596af94e6f8c6ff247c60245"
"checksum bumpalo 2.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ad807f2fc2bf185eeb98ff3a901bd46dc5ad58163d0fa4577ba0d25674d71708" "checksum bumpalo 2.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ad807f2fc2bf185eeb98ff3a901bd46dc5ad58163d0fa4577ba0d25674d71708"
"checksum byte-tools 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7"
"checksum byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a7c3dd8985a7111efc5c80b44e23ecdd8c007de8ade3b96595387e812b957cf5" "checksum byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a7c3dd8985a7111efc5c80b44e23ecdd8c007de8ade3b96595387e812b957cf5"
"checksum bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)" = "206fdffcfa2df7cbe15601ef46c813fce0965eb3286db6b56c583b814b51c81c" "checksum bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)" = "206fdffcfa2df7cbe15601ef46c813fce0965eb3286db6b56c583b814b51c81c"
"checksum c2-chacha 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "214238caa1bf3a496ec3392968969cab8549f96ff30652c9e56885329315f6bb" "checksum c2-chacha 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "214238caa1bf3a496ec3392968969cab8549f96ff30652c9e56885329315f6bb"
@ -2406,6 +2476,7 @@ dependencies = [
"checksum csv-core 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "9b5cadb6b25c77aeff80ba701712494213f4a8418fcda2ee11b6560c3ad0bf4c" "checksum csv-core 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "9b5cadb6b25c77aeff80ba701712494213f4a8418fcda2ee11b6560c3ad0bf4c"
"checksum data-encoding 2.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f4f47ca1860a761136924ddd2422ba77b2ea54fe8cc75b9040804a0d9d32ad97" "checksum data-encoding 2.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f4f47ca1860a761136924ddd2422ba77b2ea54fe8cc75b9040804a0d9d32ad97"
"checksum deunicode 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ca8a0f5bbdedde60605d0719b998e282af68e2b1c50203110211fe4abe857560" "checksum deunicode 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ca8a0f5bbdedde60605d0719b998e282af68e2b1c50203110211fe4abe857560"
"checksum digest 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f3d0c8c8752312f9713efd397ff63acb9f85585afbf179282e720e7704954dd5"
"checksum discard 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "212d0f5754cb6769937f4501cc0e67f4f4483c8d2c3e1e922ee9edbe4ab4c7c0" "checksum discard 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "212d0f5754cb6769937f4501cc0e67f4f4483c8d2c3e1e922ee9edbe4ab4c7c0"
"checksum doc-comment 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "923dea538cea0aa3025e8685b20d6ee21ef99c4f77e954a30febbaac5ec73a97" "checksum doc-comment 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "923dea538cea0aa3025e8685b20d6ee21ef99c4f77e954a30febbaac5ec73a97"
"checksum either 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "bb1f6b1ce1c140482ea30ddd3335fc0024ac7ee112895426e0a629a6c20adfe3" "checksum either 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "bb1f6b1ce1c140482ea30ddd3335fc0024ac7ee112895426e0a629a6c20adfe3"
@ -2413,6 +2484,7 @@ dependencies = [
"checksum error-chain 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3ab49e9dcb602294bc42f9a7dfc9bc6e936fca4418ea300dbfb84fe16de0b7d9" "checksum error-chain 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3ab49e9dcb602294bc42f9a7dfc9bc6e936fca4418ea300dbfb84fe16de0b7d9"
"checksum failure 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "f8273f13c977665c5db7eb2b99ae520952fe5ac831ae4cd09d80c4c7042b5ed9" "checksum failure 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "f8273f13c977665c5db7eb2b99ae520952fe5ac831ae4cd09d80c4c7042b5ed9"
"checksum failure_derive 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0bc225b78e0391e4b8683440bf2e63c2deeeb2ce5189eab46e2b68c6d3725d08" "checksum failure_derive 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0bc225b78e0391e4b8683440bf2e63c2deeeb2ce5189eab46e2b68c6d3725d08"
"checksum fake-simd 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed"
"checksum fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "2fad85553e09a6f881f739c29f0b00b0f01357c743266d478b68951ce23285f3" "checksum fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "2fad85553e09a6f881f739c29f0b00b0f01357c743266d478b68951ce23285f3"
"checksum fs_extra 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5f2a4a2034423744d2cc7ca2068453168dcdb82c438419e639a26bd87839c674" "checksum fs_extra 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5f2a4a2034423744d2cc7ca2068453168dcdb82c438419e639a26bd87839c674"
"checksum fst 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "927fb434ff9f0115b215dc0efd2e4fbdd7448522a92a1aa37c77d6a2f8f1ebd6" "checksum fst 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "927fb434ff9f0115b215dc0efd2e4fbdd7448522a92a1aa37c77d6a2f8f1ebd6"
@ -2435,6 +2507,7 @@ dependencies = [
"checksum futures-timer 2.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a1de7508b218029b0f01662ed8f61b1c964b3ae99d6f25462d0f55a595109df6" "checksum futures-timer 2.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a1de7508b218029b0f01662ed8f61b1c964b3ae99d6f25462d0f55a595109df6"
"checksum futures-util 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c0d66274fb76985d3c62c886d1da7ac4c0903a8c9f754e8fe0f35a6a6cc39e76" "checksum futures-util 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c0d66274fb76985d3c62c886d1da7ac4c0903a8c9f754e8fe0f35a6a6cc39e76"
"checksum futures-util-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)" = "5ce968633c17e5f97936bd2797b6e38fb56cf16a7422319f7ec2e30d3c470e8d" "checksum futures-util-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)" = "5ce968633c17e5f97936bd2797b6e38fb56cf16a7422319f7ec2e30d3c470e8d"
"checksum generic-array 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c68f0274ae0e023facc3c97b2e00f076be70e254bc851d972503b328db79b2ec"
"checksum getopts 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)" = "14dbbfd5c71d70241ecf9e6f13737f7b5ce823821063188d7e46c41d371eebd5" "checksum getopts 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)" = "14dbbfd5c71d70241ecf9e6f13737f7b5ce823821063188d7e46c41d371eebd5"
"checksum getrandom 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "e7db7ca94ed4cd01190ceee0d8a8052f08a247aa1b469a7f68c6a3b71afcf407" "checksum getrandom 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "e7db7ca94ed4cd01190ceee0d8a8052f08a247aa1b469a7f68c6a3b71afcf407"
"checksum h2 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)" = "a5b34c246847f938a410a03c5458c7fee2274436675e76d8b903c08efc29c462" "checksum h2 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)" = "a5b34c246847f938a410a03c5458c7fee2274436675e76d8b903c08efc29c462"
@ -2484,6 +2557,7 @@ dependencies = [
"checksum num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "6ba9a427cfca2be13aa6f6403b0b7e7368fe982bfa16fccc450ce74c46cd9b32" "checksum num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "6ba9a427cfca2be13aa6f6403b0b7e7368fe982bfa16fccc450ce74c46cd9b32"
"checksum num_cpus 1.11.1 (registry+https://github.com/rust-lang/crates.io-index)" = "76dac5ed2a876980778b8b85f75a71b6cbf0db0b1232ee12f826bccb00d09d72" "checksum num_cpus 1.11.1 (registry+https://github.com/rust-lang/crates.io-index)" = "76dac5ed2a876980778b8b85f75a71b6cbf0db0b1232ee12f826bccb00d09d72"
"checksum once_cell 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "891f486f630e5c5a4916c7e16c4b24a53e78c860b646e9f8e005e4f16847bfed" "checksum once_cell 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "891f486f630e5c5a4916c7e16c4b24a53e78c860b646e9f8e005e4f16847bfed"
"checksum opaque-debug 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c"
"checksum ordered-float 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "18869315e81473c951eb56ad5558bbc56978562d3ecfb87abb7a1e944cea4518" "checksum ordered-float 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "18869315e81473c951eb56ad5558bbc56978562d3ecfb87abb7a1e944cea4518"
"checksum page_size 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f89ef58b3d32420dbd1a43d2f38ae92f6239ef12bb556ab09ca55445f5a67242" "checksum page_size 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f89ef58b3d32420dbd1a43d2f38ae92f6239ef12bb556ab09ca55445f5a67242"
"checksum parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f842b1982eb6c2fe34036a4fbfb06dd185a3f5c8edfaacdf7d1ea10b07de6252" "checksum parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f842b1982eb6c2fe34036a4fbfb06dd185a3f5c8edfaacdf7d1ea10b07de6252"
@ -2539,6 +2613,7 @@ dependencies = [
"checksum serde_json 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)" = "2f72eb2a68a7dc3f9a691bfda9305a1c017a6215e5a4545c258500d2099a37c2" "checksum serde_json 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)" = "2f72eb2a68a7dc3f9a691bfda9305a1c017a6215e5a4545c258500d2099a37c2"
"checksum serde_qs 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "36278a86e341c46a42b0413ac3aa781902af93f5f4b10af098c704f4b96d81d8" "checksum serde_qs 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "36278a86e341c46a42b0413ac3aa781902af93f5f4b10af098c704f4b96d81d8"
"checksum sha1 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2579985fda508104f7587689507983eadd6a6e84dd35d6d115361f530916fa0d" "checksum sha1 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2579985fda508104f7587689507983eadd6a6e84dd35d6d115361f530916fa0d"
"checksum sha2 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "27044adfd2e1f077f649f59deb9490d3941d674002f7d062870a60ebe9bd47a0"
"checksum siphasher 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "83da420ee8d1a89e640d0948c646c1c088758d3a3c538f943bfa97bdac17929d" "checksum siphasher 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "83da420ee8d1a89e640d0948c646c1c088758d3a3c538f943bfa97bdac17929d"
"checksum slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8" "checksum slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8"
"checksum slice-group-by 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "1f7474f0b646d228360ab62ed974744617bc869d959eac8403bfa3665931a7fb" "checksum slice-group-by 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "1f7474f0b646d228360ab62ed974744617bc869d959eac8403bfa3665931a7fb"
@ -2579,6 +2654,7 @@ dependencies = [
"checksum tokio-timer 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "f2106812d500ed25a4f38235b9cae8f78a09edf43203e16e59c3b769a342a60e" "checksum tokio-timer 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "f2106812d500ed25a4f38235b9cae8f78a09edf43203e16e59c3b769a342a60e"
"checksum toml 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)" = "01d1404644c8b12b16bfcffa4322403a91a451584daaaa7c28d3152e6cbc98cf" "checksum toml 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)" = "01d1404644c8b12b16bfcffa4322403a91a451584daaaa7c28d3152e6cbc98cf"
"checksum try-lock 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e604eb7b43c06650e854be16a2a03155743d3752dd1c943f6829e26b7a36e382" "checksum try-lock 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e604eb7b43c06650e854be16a2a03155743d3752dd1c943f6829e26b7a36e382"
"checksum typenum 1.11.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6d2783fe2d6b8c1101136184eb41be8b1ad379e4657050b8aaff0c79ee7575f9"
"checksum unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5" "checksum unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5"
"checksum unicode-normalization 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "09c8070a9942f5e7cfccd93f490fdebd230ee3c3c9f107cb25bad5351ef671cf" "checksum unicode-normalization 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "09c8070a9942f5e7cfccd93f490fdebd230ee3c3c9f107cb25bad5351ef671cf"
"checksum unicode-segmentation 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e83e153d1053cbb5a118eeff7fd5be06ed99153f00dbcd8ae310c5fb2b22edc0" "checksum unicode-segmentation 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e83e153d1053cbb5a118eeff7fd5be06ed99153f00dbcd8ae310c5fb2b22edc0"

View File

@ -41,6 +41,7 @@ tide = "0.6.0"
ureq = { version = "0.11.2", features = ["tls"], default-features = false } ureq = { version = "0.11.2", features = ["tls"], default-features = false }
walkdir = "2.2.9" walkdir = "2.2.9"
whoami = "0.6" whoami = "0.6"
sha2 = "0.8.1"
[dev-dependencies] [dev-dependencies]
http-service-mock = "0.4.0" http-service-mock = "0.4.0"

View File

@ -7,6 +7,7 @@ use heed::types::{SerdeBincode, Str};
use log::error; use log::error;
use meilisearch_core::{Database, Error as MError, MResult, MainT, UpdateT}; use meilisearch_core::{Database, Error as MError, MResult, MainT, UpdateT};
use sysinfo::Pid; use sysinfo::Pid;
use sha2::Digest;
use crate::option::Opt; use crate::option::Opt;
use crate::routes::index::index_update_callback; use crate::routes::index::index_update_callback;
@ -32,10 +33,34 @@ impl Deref for Data {
pub struct DataInner { pub struct DataInner {
pub db: Arc<Database>, pub db: Arc<Database>,
pub db_path: String, pub db_path: String,
pub api_key: Option<String>, pub api_keys: ApiKeys,
pub server_pid: Pid, pub server_pid: Pid,
} }
#[derive(Default, Clone)]
pub struct ApiKeys {
pub public: Option<String>,
pub private: Option<String>,
pub master: Option<String>,
}
impl ApiKeys {
pub fn generate_missing_api_keys(&mut self) {
if let Some(master_key) = &self.master {
if self.private.is_none() {
let key = format!("{}-private", master_key);
let sha = sha2::Sha256::digest(key.as_bytes());
self.private = Some(format!("{:x}", sha));
}
if self.public.is_none() {
let key = format!("{}-public", master_key);
let sha = sha2::Sha256::digest(key.as_bytes());
self.public = Some(format!("{:x}", sha));
}
}
}
}
impl DataInner { impl DataInner {
pub fn is_indexing(&self, reader: &heed::RoTxn<UpdateT>, index: &str) -> MResult<Option<bool>> { pub fn is_indexing(&self, reader: &heed::RoTxn<UpdateT>, index: &str) -> MResult<Option<bool>> {
match self.db.open_index(&index) { match self.db.open_index(&index) {
@ -107,15 +132,22 @@ impl DataInner {
impl Data { impl Data {
pub fn new(opt: Opt) -> Data { pub fn new(opt: Opt) -> Data {
let db_path = opt.db_path.clone(); let db_path = opt.db_path.clone();
let api_key = opt.api_key.clone();
let server_pid = sysinfo::get_current_pid().unwrap(); let server_pid = sysinfo::get_current_pid().unwrap();
let db = Arc::new(Database::open_or_create(opt.db_path).unwrap()); let db = Arc::new(Database::open_or_create(opt.db_path).unwrap());
let mut api_keys = ApiKeys {
master: opt.master_key.clone(),
private: None,
public: None,
};
api_keys.generate_missing_api_keys();
let inner_data = DataInner { let inner_data = DataInner {
db: db.clone(), db: db.clone(),
db_path, db_path,
api_key, api_keys,
server_pid, server_pid,
}; };

View File

@ -1,14 +1,16 @@
use crate::error::{ResponseError, SResult}; use crate::error::{ResponseError, SResult};
use crate::models::token::*;
use crate::Data; use crate::Data;
use chrono::Utc;
use heed::types::{SerdeBincode, Str};
use meilisearch_core::Index; use meilisearch_core::Index;
use tide::Request; use tide::Request;
pub enum ACL {
Admin,
Private,
Public
}
pub trait RequestExt { pub trait RequestExt {
fn is_allowed(&self, acl: ACL) -> SResult<()>; fn is_allowed(&self, acl: ACL) -> SResult<()>;
fn header(&self, name: &str) -> SResult<String>;
fn url_param(&self, name: &str) -> SResult<String>; fn url_param(&self, name: &str) -> SResult<String>;
fn index(&self) -> SResult<Index>; fn index(&self) -> SResult<Index>;
fn identifier(&self) -> SResult<String>; fn identifier(&self) -> SResult<String>;
@ -16,73 +18,36 @@ pub trait RequestExt {
impl RequestExt for Request<Data> { impl RequestExt for Request<Data> {
fn is_allowed(&self, acl: ACL) -> SResult<()> { fn is_allowed(&self, acl: ACL) -> SResult<()> {
let api_key = match &self.state().api_key { let user_api_key = self.header("X-Meili-API-Key");
Some(api_key) => api_key,
None => return Ok(()),
};
let user_api_key = self match acl {
.header("X-Meili-API-Key") ACL::Admin => {
.ok_or(ResponseError::missing_header("X-Meili-API-Key"))?; if user_api_key == self.state().api_keys.master.as_deref() {
return Ok(())
if user_api_key == *api_key { }
return Ok(()); },
} ACL::Private => {
let request_index: Option<String> = None; //self.param::<String>("index").ok(); if user_api_key == self.state().api_keys.master.as_deref() {
return Ok(())
let db = &self.state().db; }
let reader = db.main_read_txn()?; if user_api_key == self.state().api_keys.private.as_deref() {
return Ok(())
let token_key = format!("{}{}", TOKEN_PREFIX_KEY, user_api_key); }
},
let token_config = db ACL::Public => {
.common_store() if user_api_key == self.state().api_keys.master.as_deref() {
.get::<_, Str, SerdeBincode<Token>>(&reader, &token_key)? return Ok(())
.ok_or(ResponseError::invalid_token(format!( }
"Api key does not exist: {}", if user_api_key == self.state().api_keys.private.as_deref() {
user_api_key return Ok(())
)))?; }
if user_api_key == self.state().api_keys.public.as_deref() {
if token_config.revoked { return Ok(())
return Err(ResponseError::invalid_token("token revoked")); }
}
if let Some(index) = request_index {
if !token_config
.indexes
.iter()
.any(|r| match_wildcard(&r, &index))
{
return Err(ResponseError::invalid_token(
"token is not allowed to access to this index",
));
} }
} }
if token_config.expires_at < Utc::now() { Err(ResponseError::InvalidToken(user_api_key.unwrap_or("Need a token").to_owned()))
return Err(ResponseError::invalid_token("token expired"));
}
if token_config.acl.contains(&ACL::All) {
return Ok(());
}
if !token_config.acl.contains(&acl) {
return Err(ResponseError::invalid_token("no permission"));
}
Ok(())
}
fn header(&self, name: &str) -> SResult<String> {
let header = self
.headers()
.get(name)
.ok_or(ResponseError::missing_header(name))?
.to_str()
.map_err(|_| ResponseError::missing_header("X-Meili-API-Key"))?
.to_string();
Ok(header)
} }
fn url_param(&self, name: &str) -> SResult<String> { fn url_param(&self, name: &str) -> SResult<String> {

View File

@ -1,4 +1,3 @@
use std::env::VarError::NotPresent;
use std::{env, thread}; use std::{env, thread};
use async_std::task; use async_std::task;
@ -19,20 +18,35 @@ mod analytics;
static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc; static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc;
pub fn main() -> Result<(), MainError> { pub fn main() -> Result<(), MainError> {
env_logger::init();
let opt = Opt::from_args(); let opt = Opt::from_args();
let data = Data::new(opt.clone());
if env::var("MEILI_NO_ANALYTICS") == Err(NotPresent) { match opt.env.as_ref() {
"production" => {
if opt.master_key.is_none() {
return Err("In production mode, the environment variable MEILI_MASTER_KEY is mandatory".into());
}
env_logger::init();
},
"development" => {
env_logger::from_env(env_logger::Env::default().default_filter_or("info")).init();
},
_ => unreachable!(),
}
if !opt.no_analytics {
thread::spawn(analytics::analytics_sender); thread::spawn(analytics::analytics_sender);
} }
let data = Data::new(opt.clone());
let data_cloned = data.clone(); let data_cloned = data.clone();
data.db.set_update_callback(Box::new(move |name, status| { data.db.set_update_callback(Box::new(move |name, status| {
index_update_callback(name, &data_cloned, status); index_update_callback(name, &data_cloned, status);
})); }));
print_launch_resume(&opt, &data);
let mut app = tide::with_state(data); let mut app = tide::with_state(data);
app.middleware(Cors::new()); app.middleware(Cors::new());
@ -40,8 +54,48 @@ pub fn main() -> Result<(), MainError> {
routes::load_routes(&mut app); routes::load_routes(&mut app);
info!("Server HTTP enabled");
task::block_on(app.listen(opt.http_addr))?; task::block_on(app.listen(opt.http_addr))?;
Ok(()) Ok(())
} }
pub fn print_launch_resume(opt: &Opt, data: &Data) {
let ascii_name = r#"
888b d888 d8b 888 d8b .d8888b. 888
8888b d8888 Y8P 888 Y8P d88P Y88b 888
88888b.d88888 888 Y88b. 888
888Y88888P888 .d88b. 888 888 888 "Y888b. .d88b. 8888b. 888d888 .d8888b 88888b.
888 Y888P 888 d8P Y8b 888 888 888 "Y88b. d8P Y8b "88b 888P" d88P" 888 "88b
888 Y8P 888 88888888 888 888 888 "888 88888888 .d888888 888 888 888 888
888 " 888 Y8b. 888 888 888 Y88b d88P Y8b. 888 888 888 Y88b. 888 888
888 888 "Y8888 888 888 888 "Y8888P" "Y8888 "Y888888 888 "Y8888P 888 888
"#;
println!("{}", ascii_name);
info!("Database path: {:?}", opt.db_path);
info!("Start server on: {:?}", opt.http_addr);
info!("Environment: {:?}", opt.env);
info!("Commit SHA: {:?}", env!("VERGEN_SHA").to_string());
info!("Build date: {:?}", env!("VERGEN_BUILD_TIMESTAMP").to_string());
info!("Package version: {:?}", env!("CARGO_PKG_VERSION").to_string());
if let Some(master_key) = &data.api_keys.master {
info!("Master Key: {:?}", master_key);
if let Some(private_key) = &data.api_keys.private {
info!("Private Key: {:?}", private_key);
}
if let Some(public_key) = &data.api_keys.public {
info!("Public Key: {:?}", public_key);
}
} else {
info!("No master key found; The server will have no securities.\
If you need some protection in development mode, please export a key. export MEILI_MASTER_KEY=xxx");
}
info!("If you need extra information; Please refer to the documentation: http://docs.meilisearch.com");
info!("If you want to support us or help us; Please consult our Github repo: http://github.com/meilisearch/meilisearch");
info!("If you want to contact us; Please chat with us on http://meilisearch.com or by email to bonjour@meilisearch.com");
}

View File

@ -1,2 +1 @@
pub mod token;
pub mod update_operation; pub mod update_operation;

View File

@ -1,72 +0,0 @@
use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};
pub const TOKEN_PREFIX_KEY: &str = "_token_";
#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub enum ACL {
IndexesRead,
IndexesWrite,
DocumentsRead,
DocumentsWrite,
SettingsRead,
SettingsWrite,
Admin,
#[serde(rename = "*")]
All,
}
pub type Wildcard = String;
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct Token {
pub key: String,
pub description: String,
pub acl: Vec<ACL>,
pub indexes: Vec<Wildcard>,
pub created_at: DateTime<Utc>,
pub updated_at: DateTime<Utc>,
pub expires_at: DateTime<Utc>,
pub revoked: bool,
}
fn cleanup_wildcard(input: &str) -> (bool, &str, bool) {
let first = input.chars().next().filter(|&c| c == '*').is_some();
let last = input.chars().last().filter(|&c| c == '*').is_some();
let bound_last = std::cmp::max(input.len().saturating_sub(last as usize), first as usize);
let output = input.get(first as usize..bound_last).unwrap();
(first, output, last)
}
pub fn match_wildcard(pattern: &str, input: &str) -> bool {
let (first, pattern, last) = cleanup_wildcard(pattern);
match (first, last) {
(false, false) => pattern == input,
(true, false) => input.ends_with(pattern),
(false, true) => input.starts_with(pattern),
(true, true) => input.contains(pattern),
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_match_wildcard() {
assert!(match_wildcard("*", "qqq"));
assert!(match_wildcard("*", ""));
assert!(match_wildcard("*ab", "qqqab"));
assert!(match_wildcard("*ab*", "qqqabqq"));
assert!(match_wildcard("ab*", "abqqq"));
assert!(match_wildcard("**", "ab"));
assert!(match_wildcard("ab", "ab"));
assert!(match_wildcard("ab*", "ab"));
assert!(match_wildcard("*ab", "ab"));
assert!(match_wildcard("*ab*", "ab"));
assert!(match_wildcard("*😆*", "ab😆dsa"));
}
}

View File

@ -1,5 +1,7 @@
use structopt::StructOpt; use structopt::StructOpt;
const POSSIBLE_ENV: [&str; 2] = ["development", "production"];
#[derive(Debug, Clone, StructOpt)] #[derive(Debug, Clone, StructOpt)]
pub struct Opt { pub struct Opt {
/// The destination where the database must be created. /// The destination where the database must be created.
@ -11,8 +13,15 @@ pub struct Opt {
pub http_addr: String, pub http_addr: String,
/// The master key allowing you to do everything on the server. /// The master key allowing you to do everything on the server.
#[structopt(long, env = "MEILI_API_KEY")] #[structopt(long, env = "MEILI_MASTER_KEY")]
pub api_key: Option<String>, pub master_key: Option<String>,
/// This environment variable must be set to `production` if your are running in production.
/// Could be `production` or `development`
/// - `production`: Force api keys
/// - `development`: Show logs in "info" mode + not mendatory to specify the api keys
#[structopt(long, env = "MEILI_ENV", default_value = "development", possible_values = &POSSIBLE_ENV)]
pub env: String,
/// Do not send analytics to Meili. /// Do not send analytics to Meili.
#[structopt(long, env = "MEILI_NO_ANALYTICS")] #[structopt(long, env = "MEILI_NO_ANALYTICS")]

View File

@ -8,11 +8,11 @@ use tide::{Request, Response};
use crate::error::{ResponseError, SResult}; use crate::error::{ResponseError, SResult};
use crate::helpers::tide::RequestExt; use crate::helpers::tide::RequestExt;
use crate::models::token::ACL::*; use crate::helpers::tide::ACL::*;
use crate::Data; use crate::Data;
pub async fn get_document(ctx: Request<Data>) -> SResult<Response> { pub async fn get_document(ctx: Request<Data>) -> SResult<Response> {
ctx.is_allowed(DocumentsRead)?; ctx.is_allowed(Public)?;
let index = ctx.index()?; let index = ctx.index()?;
@ -40,7 +40,7 @@ pub struct IndexUpdateResponse {
} }
pub async fn delete_document(ctx: Request<Data>) -> SResult<Response> { pub async fn delete_document(ctx: Request<Data>) -> SResult<Response> {
ctx.is_allowed(DocumentsWrite)?; ctx.is_allowed(Private)?;
let index = ctx.index()?; let index = ctx.index()?;
let identifier = ctx.identifier()?; let identifier = ctx.identifier()?;
@ -66,7 +66,7 @@ struct BrowseQuery {
} }
pub async fn get_all_documents(ctx: Request<Data>) -> SResult<Response> { pub async fn get_all_documents(ctx: Request<Data>) -> SResult<Response> {
ctx.is_allowed(DocumentsRead)?; ctx.is_allowed(Private)?;
let index = ctx.index()?; let index = ctx.index()?;
let query: BrowseQuery = ctx.query().unwrap_or_default(); let query: BrowseQuery = ctx.query().unwrap_or_default();
@ -125,7 +125,7 @@ struct UpdateDocumentsQuery {
} }
async fn update_multiple_documents(mut ctx: Request<Data>, is_partial: bool) -> SResult<Response> { async fn update_multiple_documents(mut ctx: Request<Data>, is_partial: bool) -> SResult<Response> {
ctx.is_allowed(DocumentsWrite)?; ctx.is_allowed(Private)?;
let index = ctx.index()?; let index = ctx.index()?;
@ -178,7 +178,7 @@ pub async fn add_or_update_multiple_documents(ctx: Request<Data>) -> SResult<Res
} }
pub async fn delete_multiple_documents(mut ctx: Request<Data>) -> SResult<Response> { pub async fn delete_multiple_documents(mut ctx: Request<Data>) -> SResult<Response> {
ctx.is_allowed(DocumentsWrite)?; ctx.is_allowed(Private)?;
let data: Vec<Value> = ctx.body_json().await.map_err(ResponseError::bad_request)?; let data: Vec<Value> = ctx.body_json().await.map_err(ResponseError::bad_request)?;
let index = ctx.index()?; let index = ctx.index()?;
@ -204,7 +204,7 @@ pub async fn delete_multiple_documents(mut ctx: Request<Data>) -> SResult<Respon
} }
pub async fn clear_all_documents(ctx: Request<Data>) -> SResult<Response> { pub async fn clear_all_documents(ctx: Request<Data>) -> SResult<Response> {
ctx.is_allowed(DocumentsWrite)?; ctx.is_allowed(Private)?;
let index = ctx.index()?; let index = ctx.index()?;

View File

@ -1,6 +1,6 @@
use crate::error::{ResponseError, SResult}; use crate::error::{ResponseError, SResult};
use crate::helpers::tide::RequestExt; use crate::helpers::tide::RequestExt;
use crate::models::token::ACL::*; use crate::helpers::tide::ACL::*;
use crate::Data; use crate::Data;
use heed::types::{Str, Unit}; use heed::types::{Str, Unit};

View File

@ -9,7 +9,7 @@ use tide::{Request, Response};
use crate::error::{IntoInternalError, ResponseError, SResult}; use crate::error::{IntoInternalError, ResponseError, SResult};
use crate::helpers::tide::RequestExt; use crate::helpers::tide::RequestExt;
use crate::models::token::ACL::*; use crate::helpers::tide::ACL::*;
use crate::Data; use crate::Data;
fn generate_uid() -> String { fn generate_uid() -> String {
@ -22,7 +22,7 @@ fn generate_uid() -> String {
} }
pub async fn list_indexes(ctx: Request<Data>) -> SResult<Response> { pub async fn list_indexes(ctx: Request<Data>) -> SResult<Response> {
ctx.is_allowed(IndexesRead)?; ctx.is_allowed(Private)?;
let indexes_uids = ctx.state().db.indexes_uids(); let indexes_uids = ctx.state().db.indexes_uids();
@ -75,7 +75,7 @@ struct IndexResponse {
} }
pub async fn get_index(ctx: Request<Data>) -> SResult<Response> { pub async fn get_index(ctx: Request<Data>) -> SResult<Response> {
ctx.is_allowed(IndexesRead)?; ctx.is_allowed(Private)?;
let index = ctx.index()?; let index = ctx.index()?;
@ -122,7 +122,7 @@ struct IndexCreateResponse {
} }
pub async fn create_index(mut ctx: Request<Data>) -> SResult<Response> { pub async fn create_index(mut ctx: Request<Data>) -> SResult<Response> {
ctx.is_allowed(IndexesWrite)?; ctx.is_allowed(Private)?;
let body = ctx let body = ctx
.body_json::<IndexCreateRequest>() .body_json::<IndexCreateRequest>()
@ -201,7 +201,7 @@ struct UpdateIndexResponse {
} }
pub async fn update_index(mut ctx: Request<Data>) -> SResult<Response> { pub async fn update_index(mut ctx: Request<Data>) -> SResult<Response> {
ctx.is_allowed(IndexesWrite)?; ctx.is_allowed(Private)?;
let body = ctx let body = ctx
.body_json::<UpdateIndexRequest>() .body_json::<UpdateIndexRequest>()
@ -250,7 +250,7 @@ pub async fn update_index(mut ctx: Request<Data>) -> SResult<Response> {
} }
pub async fn get_update_status(ctx: Request<Data>) -> SResult<Response> { pub async fn get_update_status(ctx: Request<Data>) -> SResult<Response> {
ctx.is_allowed(IndexesRead)?; ctx.is_allowed(Private)?;
let db = &ctx.state().db; let db = &ctx.state().db;
let reader = db.update_read_txn()?; let reader = db.update_read_txn()?;
@ -273,7 +273,7 @@ pub async fn get_update_status(ctx: Request<Data>) -> SResult<Response> {
} }
pub async fn get_all_updates_status(ctx: Request<Data>) -> SResult<Response> { pub async fn get_all_updates_status(ctx: Request<Data>) -> SResult<Response> {
ctx.is_allowed(IndexesRead)?; ctx.is_allowed(Private)?;
let db = &ctx.state().db; let db = &ctx.state().db;
let reader = db.update_read_txn()?; let reader = db.update_read_txn()?;
let index = ctx.index()?; let index = ctx.index()?;
@ -282,7 +282,7 @@ pub async fn get_all_updates_status(ctx: Request<Data>) -> SResult<Response> {
} }
pub async fn delete_index(ctx: Request<Data>) -> SResult<Response> { pub async fn delete_index(ctx: Request<Data>) -> SResult<Response> {
ctx.is_allowed(IndexesWrite)?; ctx.is_allowed(Private)?;
let _ = ctx.index()?; let _ = ctx.index()?;
let index_uid = ctx.url_param("index")?; let index_uid = ctx.url_param("index")?;
ctx.state().db.delete_index(&index_uid)?; ctx.state().db.delete_index(&index_uid)?;

View File

@ -1,172 +1,18 @@
use chrono::serde::ts_seconds;
use chrono::{DateTime, Utc};
use heed::types::{SerdeBincode, Str};
use rand::seq::SliceRandom;
use serde::{Deserialize, Serialize};
use tide::{Request, Response}; use tide::{Request, Response};
use serde_json::json;
use crate::error::{ResponseError, SResult}; use crate::error::SResult;
use crate::helpers::tide::RequestExt; use crate::helpers::tide::RequestExt;
use crate::models::token::ACL::*; use crate::helpers::tide::ACL::*;
use crate::models::token::*;
use crate::Data; use crate::Data;
fn generate_api_key() -> String {
let mut rng = rand::thread_rng();
let sample = b"ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
sample
.choose_multiple(&mut rng, 40)
.map(|c| *c as char)
.collect()
}
pub async fn list(ctx: Request<Data>) -> SResult<Response> { pub async fn list(ctx: Request<Data>) -> SResult<Response> {
ctx.is_allowed(Admin)?; ctx.is_allowed(Admin)?;
let db = &ctx.state().db; let keys = &ctx.state().api_keys;
let reader = db.main_read_txn()?;
let common_store = db.common_store(); Ok(tide::Response::new(200)
.body_json(&json!({
let mut response: Vec<Token> = Vec::new(); "private": keys.private,
"public": keys.public,
let iter = }))?)
common_store.prefix_iter::<_, Str, SerdeBincode<Token>>(&reader, TOKEN_PREFIX_KEY)?;
for result in iter {
let (_, token) = result?;
response.push(token);
}
Ok(tide::Response::new(200).body_json(&response).unwrap())
}
pub async fn get(ctx: Request<Data>) -> SResult<Response> {
ctx.is_allowed(Admin)?;
let request_key = ctx.url_param("key")?;
let db = &ctx.state().db;
let reader = db.main_read_txn()?;
let token_key = format!("{}{}", TOKEN_PREFIX_KEY, request_key);
let token_config = db
.common_store()
.get::<_, Str, SerdeBincode<Token>>(&reader, &token_key)?
.ok_or(ResponseError::not_found(format!(
"token key: {}",
token_key
)))?;
Ok(tide::Response::new(200).body_json(&token_config).unwrap())
}
#[derive(Debug, Serialize, Deserialize)]
#[serde(rename_all = "camelCase", deny_unknown_fields)]
pub struct CreatedRequest {
description: String,
acl: Vec<ACL>,
indexes: Vec<Wildcard>,
#[serde(with = "ts_seconds")]
expires_at: DateTime<Utc>,
}
pub async fn create(mut ctx: Request<Data>) -> SResult<Response> {
ctx.is_allowed(Admin)?;
let data: CreatedRequest = ctx.body_json().await.map_err(ResponseError::bad_request)?;
let key = generate_api_key();
let token_key = format!("{}{}", TOKEN_PREFIX_KEY, key);
let token_definition = Token {
key,
description: data.description,
acl: data.acl,
indexes: data.indexes,
expires_at: data.expires_at,
created_at: Utc::now(),
updated_at: Utc::now(),
revoked: false,
};
let db = &ctx.state().db;
let mut writer = db.main_write_txn()?;
db.common_store().put::<_, Str, SerdeBincode<Token>>(
&mut writer,
&token_key,
&token_definition,
)?;
writer.commit()?;
Ok(tide::Response::new(201)
.body_json(&token_definition)
.unwrap())
}
#[derive(Debug, Serialize, Deserialize)]
#[serde(rename_all = "camelCase", deny_unknown_fields)]
pub struct UpdatedRequest {
description: Option<String>,
acl: Option<Vec<ACL>>,
indexes: Option<Vec<Wildcard>>,
expires_at: Option<DateTime<Utc>>,
revoked: Option<bool>,
}
pub async fn update(mut ctx: Request<Data>) -> SResult<Response> {
ctx.is_allowed(Admin)?;
let request_key = ctx.url_param("key")?;
let data: UpdatedRequest = ctx.body_json().await.map_err(ResponseError::bad_request)?;
let db = &ctx.state().db;
let mut writer = db.main_write_txn()?;
let common_store = db.common_store();
let token_key = format!("{}{}", TOKEN_PREFIX_KEY, request_key);
let mut token_config = common_store
.get::<_, Str, SerdeBincode<Token>>(&writer, &token_key)?
.ok_or(ResponseError::not_found(format!(
"token key: {}",
token_key
)))?;
// apply the modifications
if let Some(description) = data.description {
token_config.description = description;
}
if let Some(acl) = data.acl {
token_config.acl = acl;
}
if let Some(indexes) = data.indexes {
token_config.indexes = indexes;
}
if let Some(expires_at) = data.expires_at {
token_config.expires_at = expires_at;
}
if let Some(revoked) = data.revoked {
token_config.revoked = revoked;
}
token_config.updated_at = Utc::now();
common_store.put::<_, Str, SerdeBincode<Token>>(&mut writer, &token_key, &token_config)?;
writer.commit()?;
Ok(tide::Response::new(200).body_json(&token_config).unwrap())
}
pub async fn delete(ctx: Request<Data>) -> SResult<Response> {
ctx.is_allowed(Admin)?;
let request_key = ctx.url_param("key")?;
let db = &ctx.state().db;
let mut writer = db.main_write_txn()?;
let common_store = db.common_store();
let token_key = format!("{}{}", TOKEN_PREFIX_KEY, request_key);
common_store.delete::<_, Str>(&mut writer, &token_key)?;
writer.commit()?;
Ok(tide::Response::new(204))
} }

View File

@ -118,13 +118,7 @@ pub fn load_routes(app: &mut tide::Server<Data>) {
.get(|ctx| into_response(stats::index_stats(ctx))); .get(|ctx| into_response(stats::index_stats(ctx)));
app.at("/keys/") app.at("/keys/")
.get(|ctx| into_response(key::list(ctx))) .get(|ctx| into_response(key::list(ctx)));
.post(|ctx| into_response(key::create(ctx)));
app.at("/keys/:key")
.get(|ctx| into_response(key::get(ctx)))
.put(|ctx| into_response(key::update(ctx)))
.delete(|ctx| into_response(key::delete(ctx)));
app.at("/health") app.at("/health")
.get(|ctx| into_response(health::get_health(ctx))) .get(|ctx| into_response(health::get_health(ctx)))

View File

@ -7,6 +7,7 @@ use rayon::iter::{IntoParallelIterator, ParallelIterator};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use tide::{Request, Response}; use tide::{Request, Response};
use crate::helpers::tide::ACL::*;
use crate::error::{ResponseError, SResult}; use crate::error::{ResponseError, SResult};
use crate::helpers::meilisearch::{Error, IndexSearchExt, SearchHit}; use crate::helpers::meilisearch::{Error, IndexSearchExt, SearchHit};
use crate::helpers::tide::RequestExt; use crate::helpers::tide::RequestExt;
@ -28,7 +29,7 @@ struct SearchQuery {
} }
pub async fn search_with_url_query(ctx: Request<Data>) -> SResult<Response> { pub async fn search_with_url_query(ctx: Request<Data>) -> SResult<Response> {
// ctx.is_allowed(DocumentsRead)?; ctx.is_allowed(Public)?;
let index = ctx.index()?; let index = ctx.index()?;
let db = &ctx.state().db; let db = &ctx.state().db;
@ -143,7 +144,7 @@ struct SearchMultiBodyResponse {
} }
pub async fn search_multi_index(mut ctx: Request<Data>) -> SResult<Response> { pub async fn search_multi_index(mut ctx: Request<Data>) -> SResult<Response> {
// ctx.is_allowed(DocumentsRead)?; ctx.is_allowed(Public)?;
let body = ctx let body = ctx
.body_json::<SearchMultiBody>() .body_json::<SearchMultiBody>()
.await .await

View File

@ -5,12 +5,12 @@ use tide::{Request, Response};
use crate::error::{ResponseError, SResult}; use crate::error::{ResponseError, SResult};
use crate::helpers::tide::RequestExt; use crate::helpers::tide::RequestExt;
use crate::models::token::ACL::*; use crate::helpers::tide::ACL::*;
use crate::routes::document::IndexUpdateResponse; use crate::routes::document::IndexUpdateResponse;
use crate::Data; use crate::Data;
pub async fn get_all(ctx: Request<Data>) -> SResult<Response> { pub async fn get_all(ctx: Request<Data>) -> SResult<Response> {
ctx.is_allowed(SettingsRead)?; ctx.is_allowed(Private)?;
let index = ctx.index()?; let index = ctx.index()?;
let db = &ctx.state().db; let db = &ctx.state().db;
let reader = db.main_read_txn()?; let reader = db.main_read_txn()?;
@ -106,7 +106,7 @@ pub struct UpdateSettings {
} }
pub async fn update_all(mut ctx: Request<Data>) -> SResult<Response> { pub async fn update_all(mut ctx: Request<Data>) -> SResult<Response> {
ctx.is_allowed(SettingsWrite)?; ctx.is_allowed(Private)?;
let index = ctx.index()?; let index = ctx.index()?;
let settings_update: UpdateSettings = let settings_update: UpdateSettings =
ctx.body_json().await.map_err(ResponseError::bad_request)?; ctx.body_json().await.map_err(ResponseError::bad_request)?;
@ -131,7 +131,7 @@ pub async fn update_all(mut ctx: Request<Data>) -> SResult<Response> {
} }
pub async fn delete_all(ctx: Request<Data>) -> SResult<Response> { pub async fn delete_all(ctx: Request<Data>) -> SResult<Response> {
ctx.is_allowed(SettingsWrite)?; ctx.is_allowed(Private)?;
let index = ctx.index()?; let index = ctx.index()?;
let db = &ctx.state().db; let db = &ctx.state().db;
let mut writer = db.update_write_txn()?; let mut writer = db.update_write_txn()?;
@ -156,7 +156,7 @@ pub async fn delete_all(ctx: Request<Data>) -> SResult<Response> {
} }
pub async fn get_rules(ctx: Request<Data>) -> SResult<Response> { pub async fn get_rules(ctx: Request<Data>) -> SResult<Response> {
ctx.is_allowed(SettingsRead)?; ctx.is_allowed(Private)?;
let index = ctx.index()?; let index = ctx.index()?;
let db = &ctx.state().db; let db = &ctx.state().db;
let reader = db.main_read_txn()?; let reader = db.main_read_txn()?;
@ -170,7 +170,7 @@ pub async fn get_rules(ctx: Request<Data>) -> SResult<Response> {
} }
pub async fn update_rules(mut ctx: Request<Data>) -> SResult<Response> { pub async fn update_rules(mut ctx: Request<Data>) -> SResult<Response> {
ctx.is_allowed(SettingsWrite)?; ctx.is_allowed(Private)?;
let index = ctx.index()?; let index = ctx.index()?;
let ranking_rules: Option<Vec<String>> = let ranking_rules: Option<Vec<String>> =
ctx.body_json().await.map_err(ResponseError::bad_request)?; ctx.body_json().await.map_err(ResponseError::bad_request)?;
@ -190,7 +190,7 @@ pub async fn update_rules(mut ctx: Request<Data>) -> SResult<Response> {
} }
pub async fn delete_rules(ctx: Request<Data>) -> SResult<Response> { pub async fn delete_rules(ctx: Request<Data>) -> SResult<Response> {
ctx.is_allowed(SettingsWrite)?; ctx.is_allowed(Private)?;
let index = ctx.index()?; let index = ctx.index()?;
let db = &ctx.state().db; let db = &ctx.state().db;
let mut writer = db.update_write_txn()?; let mut writer = db.update_write_txn()?;
@ -209,7 +209,7 @@ pub async fn delete_rules(ctx: Request<Data>) -> SResult<Response> {
} }
pub async fn get_distinct(ctx: Request<Data>) -> SResult<Response> { pub async fn get_distinct(ctx: Request<Data>) -> SResult<Response> {
ctx.is_allowed(SettingsRead)?; ctx.is_allowed(Private)?;
let index = ctx.index()?; let index = ctx.index()?;
let db = &ctx.state().db; let db = &ctx.state().db;
let reader = db.main_read_txn()?; let reader = db.main_read_txn()?;
@ -222,7 +222,7 @@ pub async fn get_distinct(ctx: Request<Data>) -> SResult<Response> {
} }
pub async fn update_distinct(mut ctx: Request<Data>) -> SResult<Response> { pub async fn update_distinct(mut ctx: Request<Data>) -> SResult<Response> {
ctx.is_allowed(SettingsWrite)?; ctx.is_allowed(Private)?;
let index = ctx.index()?; let index = ctx.index()?;
let ranking_distinct: Option<String> = let ranking_distinct: Option<String> =
ctx.body_json().await.map_err(ResponseError::bad_request)?; ctx.body_json().await.map_err(ResponseError::bad_request)?;
@ -242,7 +242,7 @@ pub async fn update_distinct(mut ctx: Request<Data>) -> SResult<Response> {
} }
pub async fn delete_distinct(ctx: Request<Data>) -> SResult<Response> { pub async fn delete_distinct(ctx: Request<Data>) -> SResult<Response> {
ctx.is_allowed(SettingsWrite)?; ctx.is_allowed(Private)?;
let index = ctx.index()?; let index = ctx.index()?;
let db = &ctx.state().db; let db = &ctx.state().db;
let mut writer = db.update_write_txn()?; let mut writer = db.update_write_txn()?;
@ -261,7 +261,7 @@ pub async fn delete_distinct(ctx: Request<Data>) -> SResult<Response> {
} }
pub async fn get_identifier(ctx: Request<Data>) -> SResult<Response> { pub async fn get_identifier(ctx: Request<Data>) -> SResult<Response> {
ctx.is_allowed(SettingsRead)?; ctx.is_allowed(Private)?;
let index = ctx.index()?; let index = ctx.index()?;
let db = &ctx.state().db; let db = &ctx.state().db;
let reader = db.main_read_txn()?; let reader = db.main_read_txn()?;
@ -274,7 +274,7 @@ pub async fn get_identifier(ctx: Request<Data>) -> SResult<Response> {
} }
pub async fn get_searchable(ctx: Request<Data>) -> SResult<Response> { pub async fn get_searchable(ctx: Request<Data>) -> SResult<Response> {
ctx.is_allowed(SettingsRead)?; ctx.is_allowed(Private)?;
let index = ctx.index()?; let index = ctx.index()?;
let db = &ctx.state().db; let db = &ctx.state().db;
let reader = db.main_read_txn()?; let reader = db.main_read_txn()?;
@ -290,7 +290,7 @@ pub async fn get_searchable(ctx: Request<Data>) -> SResult<Response> {
} }
pub async fn update_searchable(mut ctx: Request<Data>) -> SResult<Response> { pub async fn update_searchable(mut ctx: Request<Data>) -> SResult<Response> {
ctx.is_allowed(SettingsWrite)?; ctx.is_allowed(Private)?;
let index = ctx.index()?; let index = ctx.index()?;
let searchable_attributes: Option<Vec<String>> = let searchable_attributes: Option<Vec<String>> =
ctx.body_json().await.map_err(ResponseError::bad_request)?; ctx.body_json().await.map_err(ResponseError::bad_request)?;
@ -310,7 +310,7 @@ pub async fn update_searchable(mut ctx: Request<Data>) -> SResult<Response> {
} }
pub async fn delete_searchable(ctx: Request<Data>) -> SResult<Response> { pub async fn delete_searchable(ctx: Request<Data>) -> SResult<Response> {
ctx.is_allowed(SettingsWrite)?; ctx.is_allowed(Private)?;
let index = ctx.index()?; let index = ctx.index()?;
let db = &ctx.state().db; let db = &ctx.state().db;
@ -328,7 +328,7 @@ pub async fn delete_searchable(ctx: Request<Data>) -> SResult<Response> {
} }
pub async fn displayed(ctx: Request<Data>) -> SResult<Response> { pub async fn displayed(ctx: Request<Data>) -> SResult<Response> {
ctx.is_allowed(SettingsRead)?; ctx.is_allowed(Private)?;
let index = ctx.index()?; let index = ctx.index()?;
let db = &ctx.state().db; let db = &ctx.state().db;
let reader = db.main_read_txn()?; let reader = db.main_read_txn()?;
@ -348,7 +348,7 @@ pub async fn displayed(ctx: Request<Data>) -> SResult<Response> {
} }
pub async fn update_displayed(mut ctx: Request<Data>) -> SResult<Response> { pub async fn update_displayed(mut ctx: Request<Data>) -> SResult<Response> {
ctx.is_allowed(SettingsWrite)?; ctx.is_allowed(Private)?;
let index = ctx.index()?; let index = ctx.index()?;
let displayed_attributes: Option<HashSet<String>> = let displayed_attributes: Option<HashSet<String>> =
ctx.body_json().await.map_err(ResponseError::bad_request)?; ctx.body_json().await.map_err(ResponseError::bad_request)?;
@ -368,7 +368,7 @@ pub async fn update_displayed(mut ctx: Request<Data>) -> SResult<Response> {
} }
pub async fn delete_displayed(ctx: Request<Data>) -> SResult<Response> { pub async fn delete_displayed(ctx: Request<Data>) -> SResult<Response> {
ctx.is_allowed(SettingsWrite)?; ctx.is_allowed(Private)?;
let index = ctx.index()?; let index = ctx.index()?;
let db = &ctx.state().db; let db = &ctx.state().db;
@ -386,7 +386,7 @@ pub async fn delete_displayed(ctx: Request<Data>) -> SResult<Response> {
} }
pub async fn get_index_new_fields(ctx: Request<Data>) -> SResult<Response> { pub async fn get_index_new_fields(ctx: Request<Data>) -> SResult<Response> {
ctx.is_allowed(SettingsRead)?; ctx.is_allowed(Private)?;
let index = ctx.index()?; let index = ctx.index()?;
let db = &ctx.state().db; let db = &ctx.state().db;
let reader = db.main_read_txn()?; let reader = db.main_read_txn()?;
@ -401,7 +401,7 @@ pub async fn get_index_new_fields(ctx: Request<Data>) -> SResult<Response> {
} }
pub async fn update_index_new_fields(mut ctx: Request<Data>) -> SResult<Response> { pub async fn update_index_new_fields(mut ctx: Request<Data>) -> SResult<Response> {
ctx.is_allowed(SettingsWrite)?; ctx.is_allowed(Private)?;
let index = ctx.index()?; let index = ctx.index()?;
let index_new_fields: Option<bool> = let index_new_fields: Option<bool> =
ctx.body_json().await.map_err(ResponseError::bad_request)?; ctx.body_json().await.map_err(ResponseError::bad_request)?;

View File

@ -10,7 +10,7 @@ use walkdir::WalkDir;
use crate::error::{IntoInternalError, SResult}; use crate::error::{IntoInternalError, SResult};
use crate::helpers::tide::RequestExt; use crate::helpers::tide::RequestExt;
use crate::models::token::ACL::*; use crate::helpers::tide::ACL::*;
use crate::Data; use crate::Data;
#[derive(Serialize)] #[derive(Serialize)]

View File

@ -5,12 +5,12 @@ use tide::{Request, Response};
use crate::error::{ResponseError, SResult}; use crate::error::{ResponseError, SResult};
use crate::helpers::tide::RequestExt; use crate::helpers::tide::RequestExt;
use crate::models::token::ACL::*; use crate::helpers::tide::ACL::*;
use crate::routes::document::IndexUpdateResponse; use crate::routes::document::IndexUpdateResponse;
use crate::Data; use crate::Data;
pub async fn get(ctx: Request<Data>) -> SResult<Response> { pub async fn get(ctx: Request<Data>) -> SResult<Response> {
ctx.is_allowed(SettingsRead)?; ctx.is_allowed(Private)?;
let index = ctx.index()?; let index = ctx.index()?;
let db = &ctx.state().db; let db = &ctx.state().db;
let reader = db.main_read_txn()?; let reader = db.main_read_txn()?;
@ -21,7 +21,7 @@ pub async fn get(ctx: Request<Data>) -> SResult<Response> {
} }
pub async fn update(mut ctx: Request<Data>) -> SResult<Response> { pub async fn update(mut ctx: Request<Data>) -> SResult<Response> {
ctx.is_allowed(SettingsRead)?; ctx.is_allowed(Private)?;
let index = ctx.index()?; let index = ctx.index()?;
let data: BTreeSet<String> = ctx.body_json().await.map_err(ResponseError::bad_request)?; let data: BTreeSet<String> = ctx.body_json().await.map_err(ResponseError::bad_request)?;
@ -43,7 +43,7 @@ pub async fn update(mut ctx: Request<Data>) -> SResult<Response> {
} }
pub async fn delete(ctx: Request<Data>) -> SResult<Response> { pub async fn delete(ctx: Request<Data>) -> SResult<Response> {
ctx.is_allowed(SettingsRead)?; ctx.is_allowed(Private)?;
let index = ctx.index()?; let index = ctx.index()?;
let db = &ctx.state().db; let db = &ctx.state().db;

View File

@ -6,12 +6,12 @@ use tide::{Request, Response};
use crate::error::{ResponseError, SResult}; use crate::error::{ResponseError, SResult};
use crate::helpers::tide::RequestExt; use crate::helpers::tide::RequestExt;
use crate::models::token::ACL::*; use crate::helpers::tide::ACL::*;
use crate::routes::document::IndexUpdateResponse; use crate::routes::document::IndexUpdateResponse;
use crate::Data; use crate::Data;
pub async fn get(ctx: Request<Data>) -> SResult<Response> { pub async fn get(ctx: Request<Data>) -> SResult<Response> {
ctx.is_allowed(SettingsRead)?; ctx.is_allowed(Private)?;
let index = ctx.index()?; let index = ctx.index()?;
let db = &ctx.state().db; let db = &ctx.state().db;
@ -37,7 +37,7 @@ pub async fn get(ctx: Request<Data>) -> SResult<Response> {
} }
pub async fn update(mut ctx: Request<Data>) -> SResult<Response> { pub async fn update(mut ctx: Request<Data>) -> SResult<Response> {
ctx.is_allowed(SettingsWrite)?; ctx.is_allowed(Private)?;
let data: BTreeMap<String, Vec<String>> = let data: BTreeMap<String, Vec<String>> =
ctx.body_json().await.map_err(ResponseError::bad_request)?; ctx.body_json().await.map_err(ResponseError::bad_request)?;
@ -61,7 +61,7 @@ pub async fn update(mut ctx: Request<Data>) -> SResult<Response> {
} }
pub async fn delete(ctx: Request<Data>) -> SResult<Response> { pub async fn delete(ctx: Request<Data>) -> SResult<Response> {
ctx.is_allowed(SettingsWrite)?; ctx.is_allowed(Private)?;
let index = ctx.index()?; let index = ctx.index()?;

View File

@ -22,7 +22,8 @@ pub fn setup_server() -> Result<TestBackend<Service<Data>>, Box<dyn Error>> {
let opt = Opt { let opt = Opt {
db_path: tmp_dir.path().to_str().unwrap().to_string(), db_path: tmp_dir.path().to_str().unwrap().to_string(),
http_addr: "127.0.0.1:7700".to_owned(), http_addr: "127.0.0.1:7700".to_owned(),
api_key: None, master_key: None,
env: "development".to_owned(),
no_analytics: true, no_analytics: true,
}; };