Merge pull request 'Key backups and cross signing' (#132) from cross-signing into master

Reviewed-on: https://git.koesters.xyz/timo/conduit/pulls/132
next
Timo Kösters 2020-06-26 19:01:32 +02:00
commit e809d819ac
11 changed files with 1349 additions and 294 deletions

263
Cargo.lock generated
View File

@ -1,5 +1,14 @@
# This file is automatically @generated by Cargo. # This file is automatically @generated by Cargo.
# It is not intended for manual editing. # It is not intended for manual editing.
[[package]]
name = "addr2line"
version = "0.12.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "602d785912f476e480434627e8732e6766b760c045bbf897d9dfaa9f4fbd399c"
dependencies = [
"gimli",
]
[[package]] [[package]]
name = "adler32" name = "adler32"
version = "1.1.0" version = "1.1.0"
@ -26,13 +35,13 @@ checksum = "cff77d8686867eceff3105329d4698d96c2391c176d5d03adc90c7389162b5b8"
[[package]] [[package]]
name = "async-trait" name = "async-trait"
version = "0.1.35" version = "0.1.36"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "89cb5d814ab2a47fd66d3266e9efccb53ca4c740b7451043b8ffcf9a6208f3f8" checksum = "a265e3abeffdce30b2e26b7a11b222fe37c6067404001b434101457d0385eb92"
dependencies = [ dependencies = [
"proc-macro2 1.0.18", "proc-macro2 1.0.18",
"quote 1.0.7", "quote 1.0.7",
"syn 1.0.31", "syn 1.0.33",
] ]
[[package]] [[package]]
@ -43,7 +52,7 @@ checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
dependencies = [ dependencies = [
"hermit-abi", "hermit-abi",
"libc", "libc",
"winapi 0.3.8", "winapi 0.3.9",
] ]
[[package]] [[package]]
@ -52,6 +61,20 @@ version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f8aac770f1885fd7e387acedd76065302551364496e46b3dd00860b2f8359b9d" checksum = "f8aac770f1885fd7e387acedd76065302551364496e46b3dd00860b2f8359b9d"
[[package]]
name = "backtrace"
version = "0.3.49"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "05100821de9e028f12ae3d189176b41ee198341eb8f369956407fea2f5cc666c"
dependencies = [
"addr2line",
"cfg-if",
"libc",
"miniz_oxide",
"object",
"rustc-demangle",
]
[[package]] [[package]]
name = "base16" name = "base16"
version = "0.2.1" version = "0.2.1"
@ -75,9 +98,9 @@ checksum = "b41b7ea54a0c9d92199de89e20e58d49f02f8e699814ef3fdf266f6f748d15c7"
[[package]] [[package]]
name = "base64" name = "base64"
version = "0.12.2" version = "0.12.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e223af0dc48c96d4f8342ec01a4974f139df863896b316681efd36742f22cc67" checksum = "3441f0f7b02788e948e47f457ca01f1d7e6d92c693bc132c22b087d3141c03ff"
[[package]] [[package]]
name = "bitflags" name = "bitflags"
@ -116,15 +139,18 @@ checksum = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de"
[[package]] [[package]]
name = "bytes" name = "bytes"
version = "0.5.4" version = "0.5.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "130aac562c0dd69c56b3b1cc8ffd2e17be31d0b6c25b61c96b76231aa23e39e1" checksum = "118cf036fbb97d0816e3c34b2d7a1e8cfc60f68fcf63d550ddbe9bd5f59c213b"
dependencies = [
"loom",
]
[[package]] [[package]]
name = "cc" name = "cc"
version = "1.0.54" version = "1.0.55"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7bbb73db36c1246e9034e307d0fba23f9a2e251faa47ade70c1bd252220c8311" checksum = "b1be3409f94d7bdceeb5f5fac551039d9b3f00e25da7a74fc4d33400a0d96368"
[[package]] [[package]]
name = "cfg-if" name = "cfg-if"
@ -151,7 +177,7 @@ checksum = "0dbbb57365263e881e805dc77d94697c9118fd94d8da011240555aa7b23445bd"
name = "conduit" name = "conduit"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"base64 0.12.2", "base64 0.12.3",
"directories", "directories",
"http", "http",
"image", "image",
@ -273,7 +299,7 @@ dependencies = [
"bitflags", "bitflags",
"proc-macro2 1.0.18", "proc-macro2 1.0.18",
"quote 1.0.7", "quote 1.0.7",
"syn 1.0.31", "syn 1.0.33",
] ]
[[package]] [[package]]
@ -294,14 +320,14 @@ checksum = "8e93d7f5705de3e49895a2b5e0b8855a1c27f080192ae9c32a6432d50741a57a"
dependencies = [ dependencies = [
"libc", "libc",
"redox_users", "redox_users",
"winapi 0.3.8", "winapi 0.3.9",
] ]
[[package]] [[package]]
name = "dtoa" name = "dtoa"
version = "0.4.5" version = "0.4.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4358a9e11b9a09cf52383b451b49a169e8d797b68aa02301ff586d70d9661ea3" checksum = "134951f4028bdadb9b84baf4232681efbf277da25144b9b0ad65df75946c422b"
[[package]] [[package]]
name = "encoding_rs" name = "encoding_rs"
@ -340,7 +366,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9564fc758e15025b46aa6643b1b77d047d1a56a1aea6e01002ac0c7026876213" checksum = "9564fc758e15025b46aa6643b1b77d047d1a56a1aea6e01002ac0c7026876213"
dependencies = [ dependencies = [
"libc", "libc",
"winapi 0.3.8", "winapi 0.3.9",
] ]
[[package]] [[package]]
@ -416,7 +442,7 @@ dependencies = [
"proc-macro-hack", "proc-macro-hack",
"proc-macro2 1.0.18", "proc-macro2 1.0.18",
"quote 1.0.7", "quote 1.0.7",
"syn 1.0.31", "syn 1.0.33",
] ]
[[package]] [[package]]
@ -463,6 +489,19 @@ dependencies = [
"byteorder", "byteorder",
] ]
[[package]]
name = "generator"
version = "0.6.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "add72f17bb81521258fcc8a7a3245b1e184e916bfbe34f0ea89558f440df5c68"
dependencies = [
"cc",
"libc",
"log",
"rustc_version",
"winapi 0.3.9",
]
[[package]] [[package]]
name = "getrandom" name = "getrandom"
version = "0.1.14" version = "0.1.14"
@ -484,6 +523,12 @@ dependencies = [
"lzw", "lzw",
] ]
[[package]]
name = "gimli"
version = "0.21.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bcc8e0c9bce37868955864dbecd2b1ab2bdf967e6f28066d65aaac620444b65c"
[[package]] [[package]]
name = "h2" name = "h2"
version = "0.2.5" version = "0.2.5"
@ -598,9 +643,9 @@ dependencies = [
[[package]] [[package]]
name = "image" name = "image"
version = "0.23.5" version = "0.23.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d534e95ad8b9d5aa614322d02352b4f1bf962254adcf02ac6f2def8be18498e8" checksum = "b5b0553fec6407d63fe2975b794dfb099f3f790bdc958823851af37b26404ab4"
dependencies = [ dependencies = [
"bytemuck", "bytemuck",
"byteorder", "byteorder",
@ -632,9 +677,9 @@ dependencies = [
[[package]] [[package]]
name = "itoa" name = "itoa"
version = "0.4.5" version = "0.4.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b8b7a7c0c47db5545ed3fef7468ee7bb5b74691498139e4b3f6a20685dc6dd8e" checksum = "dc6f3ad7b9d11a0c00842ff8de1b60ee58661048eb8049ed33c73594f359d7e6"
[[package]] [[package]]
name = "jpeg-decoder" name = "jpeg-decoder"
@ -656,9 +701,9 @@ dependencies = [
[[package]] [[package]]
name = "js_int" name = "js_int"
version = "0.1.5" version = "0.1.8"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "77ab7bb370a788ad675863e035fd9bfa56a66a030a16a88ab80aeb6b18cbdf31" checksum = "1b2b63d60564122f2a7d6592c2f1d6c1c60e7a266b4d24715950a1ddad784f66"
dependencies = [ dependencies = [
"serde", "serde",
] ]
@ -703,6 +748,17 @@ dependencies = [
"cfg-if", "cfg-if",
] ]
[[package]]
name = "loom"
version = "0.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4ecc775857611e1df29abba5c41355cdf540e7e9d4acfdf0f355eefee82330b7"
dependencies = [
"cfg-if",
"generator",
"scoped-tls",
]
[[package]] [[package]]
name = "lzw" name = "lzw"
version = "0.10.0" version = "0.10.0"
@ -829,7 +885,7 @@ checksum = "2ba7c918ac76704fb42afcbbb43891e72731f3dcca3bef2a19786297baf14af7"
dependencies = [ dependencies = [
"cfg-if", "cfg-if",
"libc", "libc",
"winapi 0.3.8", "winapi 0.3.9",
] ]
[[package]] [[package]]
@ -855,9 +911,9 @@ dependencies = [
[[package]] [[package]]
name = "num-rational" name = "num-rational"
version = "0.2.4" version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c000134b5dbf44adc5cb772486d335293351644b801551abe8f75c84cfa4aef" checksum = "a5b4d7360f362cfb50dde8143501e6940b22f644be75a4cc90b2d81968908138"
dependencies = [ dependencies = [
"autocfg", "autocfg",
"num-integer", "num-integer",
@ -883,6 +939,12 @@ dependencies = [
"libc", "libc",
] ]
[[package]]
name = "object"
version = "0.20.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1ab52be62400ca80aa00285d25253d7f7c437b7375c4de678f5405d3afe82ca5"
[[package]] [[package]]
name = "once_cell" name = "once_cell"
version = "1.4.0" version = "1.4.0"
@ -891,9 +953,9 @@ checksum = "0b631f7e854af39a1739f401cf34a8a013dfe09eac4fa4dba91e9768bd28168d"
[[package]] [[package]]
name = "openssl" name = "openssl"
version = "0.10.29" version = "0.10.30"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cee6d85f4cb4c4f59a6a85d5b68a233d280c82e29e822913b9c8b129fbf20bdd" checksum = "8d575eff3665419f9b83678ff2815858ad9d11567e082f5ac1814baba4e2bcb4"
dependencies = [ dependencies = [
"bitflags", "bitflags",
"cfg-if", "cfg-if",
@ -943,7 +1005,7 @@ dependencies = [
"libc", "libc",
"redox_syscall", "redox_syscall",
"smallvec", "smallvec",
"winapi 0.3.8", "winapi 0.3.9",
] ]
[[package]] [[package]]
@ -997,7 +1059,7 @@ checksum = "6a0ffd45cf79d88737d7cc85bfd5d2894bee1139b356e616fe85dc389c61aaf7"
dependencies = [ dependencies = [
"proc-macro2 1.0.18", "proc-macro2 1.0.18",
"quote 1.0.7", "quote 1.0.7",
"syn 1.0.31", "syn 1.0.33",
] ]
[[package]] [[package]]
@ -1063,7 +1125,7 @@ version = "1.0.18"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "beae6331a816b1f65d04c45b078fd8e6c93e8071771f41b8163255bbd8d7c8fa" checksum = "beae6331a816b1f65d04c45b078fd8e6c93e8071771f41b8163255bbd8d7c8fa"
dependencies = [ dependencies = [
"unicode-xid 0.2.0", "unicode-xid 0.2.1",
] ]
[[package]] [[package]]
@ -1148,7 +1210,7 @@ version = "0.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7" checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7"
dependencies = [ dependencies = [
"winapi 0.3.8", "winapi 0.3.9",
] ]
[[package]] [[package]]
@ -1157,7 +1219,7 @@ version = "0.10.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3b82c9238b305f26f53443e3a4bc8528d64b8d0bee408ec949eb7bf5635ec680" checksum = "3b82c9238b305f26f53443e3a4bc8528d64b8d0bee408ec949eb7bf5635ec680"
dependencies = [ dependencies = [
"base64 0.12.2", "base64 0.12.3",
"bytes", "bytes",
"encoding_rs", "encoding_rs",
"futures-core", "futures-core",
@ -1187,9 +1249,9 @@ dependencies = [
[[package]] [[package]]
name = "ring" name = "ring"
version = "0.16.14" version = "0.16.15"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "06b3fefa4f12272808f809a0af618501fdaba41a58963c5fb72238ab0be09603" checksum = "952cd6b98c85bbc30efa1ba5783b8abf12fec8b3287ffa52605b9432313e34e4"
dependencies = [ dependencies = [
"cc", "cc",
"libc", "libc",
@ -1197,7 +1259,7 @@ dependencies = [
"spin", "spin",
"untrusted", "untrusted",
"web-sys", "web-sys",
"winapi 0.3.8", "winapi 0.3.9",
] ]
[[package]] [[package]]
@ -1255,13 +1317,13 @@ dependencies = [
"time", "time",
"tokio", "tokio",
"tokio-rustls", "tokio-rustls",
"unicode-xid 0.2.0", "unicode-xid 0.2.1",
] ]
[[package]] [[package]]
name = "ruma" name = "ruma"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/ruma/ruma?rev=baa87104569b45dc07a9a7a16d3c7592ab8f4d6b#baa87104569b45dc07a9a7a16d3c7592ab8f4d6b" source = "git+https://github.com/timokoesters/ruma#5a30f9cfc6c168f25cfcf51f3d80b3594c0f59b1"
dependencies = [ dependencies = [
"ruma-api", "ruma-api",
"ruma-client-api", "ruma-client-api",
@ -1275,7 +1337,7 @@ dependencies = [
[[package]] [[package]]
name = "ruma-api" name = "ruma-api"
version = "0.16.1" version = "0.16.1"
source = "git+https://github.com/ruma/ruma?rev=baa87104569b45dc07a9a7a16d3c7592ab8f4d6b#baa87104569b45dc07a9a7a16d3c7592ab8f4d6b" source = "git+https://github.com/timokoesters/ruma#5a30f9cfc6c168f25cfcf51f3d80b3594c0f59b1"
dependencies = [ dependencies = [
"http", "http",
"percent-encoding 2.1.0", "percent-encoding 2.1.0",
@ -1290,17 +1352,17 @@ dependencies = [
[[package]] [[package]]
name = "ruma-api-macros" name = "ruma-api-macros"
version = "0.16.1" version = "0.16.1"
source = "git+https://github.com/ruma/ruma?rev=baa87104569b45dc07a9a7a16d3c7592ab8f4d6b#baa87104569b45dc07a9a7a16d3c7592ab8f4d6b" source = "git+https://github.com/timokoesters/ruma#5a30f9cfc6c168f25cfcf51f3d80b3594c0f59b1"
dependencies = [ dependencies = [
"proc-macro2 1.0.18", "proc-macro2 1.0.18",
"quote 1.0.7", "quote 1.0.7",
"syn 1.0.31", "syn 1.0.33",
] ]
[[package]] [[package]]
name = "ruma-client-api" name = "ruma-client-api"
version = "0.9.0" version = "0.9.0"
source = "git+https://github.com/ruma/ruma?rev=baa87104569b45dc07a9a7a16d3c7592ab8f4d6b#baa87104569b45dc07a9a7a16d3c7592ab8f4d6b" source = "git+https://github.com/timokoesters/ruma#5a30f9cfc6c168f25cfcf51f3d80b3594c0f59b1"
dependencies = [ dependencies = [
"http", "http",
"js_int", "js_int",
@ -1317,7 +1379,7 @@ dependencies = [
[[package]] [[package]]
name = "ruma-common" name = "ruma-common"
version = "0.1.3" version = "0.1.3"
source = "git+https://github.com/ruma/ruma?rev=baa87104569b45dc07a9a7a16d3c7592ab8f4d6b#baa87104569b45dc07a9a7a16d3c7592ab8f4d6b" source = "git+https://github.com/timokoesters/ruma#5a30f9cfc6c168f25cfcf51f3d80b3594c0f59b1"
dependencies = [ dependencies = [
"matches", "matches",
"ruma-serde", "ruma-serde",
@ -1348,13 +1410,13 @@ source = "git+https://github.com/ruma/ruma-events?rev=c1ee72d#c1ee72db0f3107a97f
dependencies = [ dependencies = [
"proc-macro2 1.0.18", "proc-macro2 1.0.18",
"quote 1.0.7", "quote 1.0.7",
"syn 1.0.31", "syn 1.0.33",
] ]
[[package]] [[package]]
name = "ruma-federation-api" name = "ruma-federation-api"
version = "0.0.2" version = "0.0.2"
source = "git+https://github.com/ruma/ruma?rev=baa87104569b45dc07a9a7a16d3c7592ab8f4d6b#baa87104569b45dc07a9a7a16d3c7592ab8f4d6b" source = "git+https://github.com/timokoesters/ruma#5a30f9cfc6c168f25cfcf51f3d80b3594c0f59b1"
dependencies = [ dependencies = [
"js_int", "js_int",
"matches", "matches",
@ -1369,7 +1431,7 @@ dependencies = [
[[package]] [[package]]
name = "ruma-identifiers" name = "ruma-identifiers"
version = "0.16.2" version = "0.16.2"
source = "git+https://github.com/ruma/ruma?rev=baa87104569b45dc07a9a7a16d3c7592ab8f4d6b#baa87104569b45dc07a9a7a16d3c7592ab8f4d6b" source = "git+https://github.com/timokoesters/ruma#5a30f9cfc6c168f25cfcf51f3d80b3594c0f59b1"
dependencies = [ dependencies = [
"rand", "rand",
"serde", "serde",
@ -1379,7 +1441,7 @@ dependencies = [
[[package]] [[package]]
name = "ruma-serde" name = "ruma-serde"
version = "0.2.2" version = "0.2.2"
source = "git+https://github.com/ruma/ruma?rev=baa87104569b45dc07a9a7a16d3c7592ab8f4d6b#baa87104569b45dc07a9a7a16d3c7592ab8f4d6b" source = "git+https://github.com/timokoesters/ruma#5a30f9cfc6c168f25cfcf51f3d80b3594c0f59b1"
dependencies = [ dependencies = [
"dtoa", "dtoa",
"itoa", "itoa",
@ -1392,9 +1454,9 @@ dependencies = [
[[package]] [[package]]
name = "ruma-signatures" name = "ruma-signatures"
version = "0.6.0-dev.1" version = "0.6.0-dev.1"
source = "git+https://github.com/ruma/ruma?rev=baa87104569b45dc07a9a7a16d3c7592ab8f4d6b#baa87104569b45dc07a9a7a16d3c7592ab8f4d6b" source = "git+https://github.com/timokoesters/ruma#5a30f9cfc6c168f25cfcf51f3d80b3594c0f59b1"
dependencies = [ dependencies = [
"base64 0.12.2", "base64 0.12.3",
"ring", "ring",
"serde_json", "serde_json",
"untrusted", "untrusted",
@ -1418,12 +1480,27 @@ version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9dab61250775933275e84053ac235621dfb739556d5c54a2f2e9313b7cf43a19" checksum = "9dab61250775933275e84053ac235621dfb739556d5c54a2f2e9313b7cf43a19"
dependencies = [ dependencies = [
"base64 0.12.2", "base64 0.12.3",
"blake2b_simd", "blake2b_simd",
"constant_time_eq", "constant_time_eq",
"crossbeam-utils", "crossbeam-utils",
] ]
[[package]]
name = "rustc-demangle"
version = "0.1.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4c691c0e608126e00913e33f0ccf3727d5fc84573623b8d65b2df340b5201783"
[[package]]
name = "rustc_version"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a"
dependencies = [
"semver",
]
[[package]] [[package]]
name = "rustls" name = "rustls"
version = "0.16.0" version = "0.16.0"
@ -1450,9 +1527,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f05ba609c234e60bee0d547fe94a4c7e9da733d1c962cf6e59efa4cd9c8bc75" checksum = "8f05ba609c234e60bee0d547fe94a4c7e9da733d1c962cf6e59efa4cd9c8bc75"
dependencies = [ dependencies = [
"lazy_static", "lazy_static",
"winapi 0.3.8", "winapi 0.3.9",
] ]
[[package]]
name = "scoped-tls"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "332ffa32bf586782a3efaeb58f127980944bbc8c4d6913a86107ac2a5ab24b28"
[[package]] [[package]]
name = "scopeguard" name = "scopeguard"
version = "1.1.0" version = "1.1.0"
@ -1493,23 +1576,38 @@ dependencies = [
] ]
[[package]] [[package]]
name = "serde" name = "semver"
version = "1.0.112" version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "736aac72d1eafe8e5962d1d1c3d99b0df526015ba40915cb3c49d042e92ec243" checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403"
dependencies = [
"semver-parser",
]
[[package]]
name = "semver-parser"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
[[package]]
name = "serde"
version = "1.0.114"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5317f7588f0a5078ee60ef675ef96735a1442132dc645eb1d12c018620ed8cd3"
dependencies = [ dependencies = [
"serde_derive", "serde_derive",
] ]
[[package]] [[package]]
name = "serde_derive" name = "serde_derive"
version = "1.0.112" version = "1.0.114"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bf0343ce212ac0d3d6afd9391ac8e9c9efe06b533c8d33f660f6390cc4093f57" checksum = "2a0be94b04690fbaed37cddffc5c134bf537c8e3329d53e982fe04c374978f8e"
dependencies = [ dependencies = [
"proc-macro2 1.0.18", "proc-macro2 1.0.18",
"quote 1.0.7", "quote 1.0.7",
"syn 1.0.31", "syn 1.0.33",
] ]
[[package]] [[package]]
@ -1553,10 +1651,11 @@ checksum = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8"
[[package]] [[package]]
name = "sled" name = "sled"
version = "0.31.0" version = "0.32.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8fb6824dde66ad33bf20c6e8476f5b82b871bc8bc3c129a10ea2f7dae5060fa3" checksum = "cdad3dc85d888056d3bd9954ffdf22d8a22701b6cd3aca4f6df4c436111898c4"
dependencies = [ dependencies = [
"backtrace",
"crc32fast", "crc32fast",
"crossbeam-epoch", "crossbeam-epoch",
"crossbeam-utils", "crossbeam-utils",
@ -1582,7 +1681,7 @@ dependencies = [
"cfg-if", "cfg-if",
"libc", "libc",
"redox_syscall", "redox_syscall",
"winapi 0.3.8", "winapi 0.3.9",
] ]
[[package]] [[package]]
@ -1615,7 +1714,7 @@ dependencies = [
"heck", "heck",
"proc-macro2 1.0.18", "proc-macro2 1.0.18",
"quote 1.0.7", "quote 1.0.7",
"syn 1.0.31", "syn 1.0.33",
] ]
[[package]] [[package]]
@ -1631,13 +1730,13 @@ dependencies = [
[[package]] [[package]]
name = "syn" name = "syn"
version = "1.0.31" version = "1.0.33"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b5304cfdf27365b7585c25d4af91b35016ed21ef88f17ced89c7093b43dba8b6" checksum = "e8d5d96e8cbb005d6959f119f773bfaebb5684296108fb32600c00cde305b2cd"
dependencies = [ dependencies = [
"proc-macro2 1.0.18", "proc-macro2 1.0.18",
"quote 1.0.7", "quote 1.0.7",
"unicode-xid 0.2.0", "unicode-xid 0.2.1",
] ]
[[package]] [[package]]
@ -1651,7 +1750,7 @@ dependencies = [
"rand", "rand",
"redox_syscall", "redox_syscall",
"remove_dir_all", "remove_dir_all",
"winapi 0.3.8", "winapi 0.3.9",
] ]
[[package]] [[package]]
@ -1671,7 +1770,7 @@ checksum = "bd80fc12f73063ac132ac92aceea36734f04a1d93c1240c6944e23a3b8841793"
dependencies = [ dependencies = [
"proc-macro2 1.0.18", "proc-macro2 1.0.18",
"quote 1.0.7", "quote 1.0.7",
"syn 1.0.31", "syn 1.0.33",
] ]
[[package]] [[package]]
@ -1681,9 +1780,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ca8a50ef2360fbd1eeb0ecd46795a87a19024eb4b53c5dc916ca1fd95fe62438" checksum = "ca8a50ef2360fbd1eeb0ecd46795a87a19024eb4b53c5dc916ca1fd95fe62438"
dependencies = [ dependencies = [
"libc", "libc",
"winapi 0.3.8", "winapi 0.3.9",
] ]
[[package]]
name = "tinyvec"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "53953d2d3a5ad81d9f844a32f14ebb121f50b650cd59d0ee2a07cf13c617efed"
[[package]] [[package]]
name = "tokio" name = "tokio"
version = "0.2.21" version = "0.2.21"
@ -1704,7 +1809,7 @@ dependencies = [
"signal-hook-registry", "signal-hook-registry",
"slab", "slab",
"tokio-macros", "tokio-macros",
"winapi 0.3.8", "winapi 0.3.9",
] ]
[[package]] [[package]]
@ -1715,7 +1820,7 @@ checksum = "f0c3acc6aa564495a0f2e1d59fab677cd7f81a19994cfc7f3ad0e64301560389"
dependencies = [ dependencies = [
"proc-macro2 1.0.18", "proc-macro2 1.0.18",
"quote 1.0.7", "quote 1.0.7",
"syn 1.0.31", "syn 1.0.33",
] ]
[[package]] [[package]]
@ -1795,11 +1900,11 @@ dependencies = [
[[package]] [[package]]
name = "unicode-normalization" name = "unicode-normalization"
version = "0.1.12" version = "0.1.13"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5479532badd04e128284890390c1e876ef7a993d0570b3597ae43dfa1d59afa4" checksum = "6fb19cf769fa8c6a80a162df694621ebeb4dafb606470b2b2fce0be40a98a977"
dependencies = [ dependencies = [
"smallvec", "tinyvec",
] ]
[[package]] [[package]]
@ -1816,9 +1921,9 @@ checksum = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc"
[[package]] [[package]]
name = "unicode-xid" name = "unicode-xid"
version = "0.2.0" version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c" checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564"
[[package]] [[package]]
name = "untrusted" name = "untrusted"
@ -1888,7 +1993,7 @@ dependencies = [
"log", "log",
"proc-macro2 1.0.18", "proc-macro2 1.0.18",
"quote 1.0.7", "quote 1.0.7",
"syn 1.0.31", "syn 1.0.33",
"wasm-bindgen-shared", "wasm-bindgen-shared",
] ]
@ -1922,7 +2027,7 @@ checksum = "3156052d8ec77142051a533cdd686cba889537b213f948cd1d20869926e68e92"
dependencies = [ dependencies = [
"proc-macro2 1.0.18", "proc-macro2 1.0.18",
"quote 1.0.7", "quote 1.0.7",
"syn 1.0.31", "syn 1.0.33",
"wasm-bindgen-backend", "wasm-bindgen-backend",
"wasm-bindgen-shared", "wasm-bindgen-shared",
] ]
@ -1961,9 +2066,9 @@ checksum = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a"
[[package]] [[package]]
name = "winapi" name = "winapi"
version = "0.3.8" version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6" checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
dependencies = [ dependencies = [
"winapi-i686-pc-windows-gnu", "winapi-i686-pc-windows-gnu",
"winapi-x86_64-pc-windows-gnu", "winapi-x86_64-pc-windows-gnu",
@ -1993,7 +2098,7 @@ version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0120db82e8a1e0b9fb3345a539c478767c0048d842860994d96113d5b667bd69" checksum = "0120db82e8a1e0b9fb3345a539c478767c0048d842860994d96113d5b667bd69"
dependencies = [ dependencies = [
"winapi 0.3.8", "winapi 0.3.9",
] ]
[[package]] [[package]]

View File

@ -15,7 +15,7 @@ edition = "2018"
rocket = { git = "https://github.com/SergioBenitez/Rocket.git", rev = "4928e35ec5c4b9242f50d644282d9896d0160a10", features = ["tls"] } rocket = { git = "https://github.com/SergioBenitez/Rocket.git", rev = "4928e35ec5c4b9242f50d644282d9896d0160a10", features = ["tls"] }
http = "0.2.1" http = "0.2.1"
log = "0.4.8" log = "0.4.8"
sled = "0.31.0" sled = "0.32.0"
directories = "2.0.2" directories = "2.0.2"
js_int = "0.1.5" js_int = "0.1.5"
serde_json = { version = "1.0.53", features = ["raw_value"] } serde_json = { version = "1.0.53", features = ["raw_value"] }
@ -29,15 +29,16 @@ thiserror = "1.0.19"
image = { version = "0.23.4", default-features = false, features = ["jpeg", "png", "gif"] } image = { version = "0.23.4", default-features = false, features = ["jpeg", "png", "gif"] }
[dependencies.ruma] [dependencies.ruma]
git = "https://github.com/ruma/ruma" git = "https://github.com/timokoesters/ruma"
rev = "baa87104569b45dc07a9a7a16d3c7592ab8f4d6b" #rev = "baa87104569b45dc07a9a7a16d3c7592ab8f4d6b"
#path = "../ruma/ruma" #path = "../ruma/ruma"
features = ["rand", "client-api", "federation-api"] features = ["rand", "client-api", "federation-api"]
# These are required only until ruma-events and ruma-federation-api are merged into ruma/ruma # These are required only until ruma-events and ruma-federation-api are merged into ruma/ruma
[patch.crates-io] [patch.crates-io]
ruma-common = { git = "https://github.com/ruma/ruma", rev = "baa87104569b45dc07a9a7a16d3c7592ab8f4d6b" } ruma-common = { git = "https://github.com/timokoesters/ruma" }
ruma-serde = { git = "https://github.com/ruma/ruma", rev = "baa87104569b45dc07a9a7a16d3c7592ab8f4d6b" } ruma-serde = { git = "https://github.com/timokoesters/ruma" }
ruma-identifiers = { git = "https://github.com/ruma/ruma", rev = "baa87104569b45dc07a9a7a16d3c7592ab8f4d6b" } ruma-identifiers = { git = "https://github.com/timokoesters/ruma" }
#ruma-common = { path = "../ruma/ruma-common" } #ruma-common = { path = "../ruma/ruma-common" }
#ruma-serde = { path = "../ruma/ruma-serde" } #ruma-serde = { path = "../ruma/ruma-serde" }
#ruma-identifiers = { path = "../ruma/ruma-identifiers" }

View File

@ -5,6 +5,7 @@ use std::{
}; };
use crate::{utils, ConduitResult, Database, Error, Ruma}; use crate::{utils, ConduitResult, Database, Error, Ruma};
use keys::{upload_signatures, upload_signing_keys};
use log::warn; use log::warn;
use rocket::{delete, get, options, post, put, State}; use rocket::{delete, get, options, post, put, State};
use ruma::{ use ruma::{
@ -13,6 +14,10 @@ use ruma::{
r0::{ r0::{
account::{get_username_availability, register}, account::{get_username_availability, register},
alias::{create_alias, delete_alias, get_alias}, alias::{create_alias, delete_alias, get_alias},
backup::{
add_backup_keys, create_backup, get_backup, get_backup_keys, get_latest_backup,
update_backup,
},
capabilities::get_capabilities, capabilities::get_capabilities,
config::{get_global_account_data, set_global_account_data}, config::{get_global_account_data, set_global_account_data},
context::get_context, context::get_context,
@ -33,7 +38,7 @@ use ruma::{
profile::{ profile::{
get_avatar_url, get_display_name, get_profile, set_avatar_url, set_display_name, get_avatar_url, get_display_name, get_profile, set_avatar_url, set_display_name,
}, },
push::{get_pushrules_all, set_pushrule, set_pushrule_enabled}, push::{get_pushers, get_pushrules_all, set_pushrule, set_pushrule_enabled},
read_marker::set_read_marker, read_marker::set_read_marker,
redact::redact_event, redact::redact_event,
room::{self, create_room}, room::{self, create_room},
@ -71,9 +76,13 @@ const SESSION_ID_LENGTH: usize = 256;
#[get("/_matrix/client/versions")] #[get("/_matrix/client/versions")]
pub fn get_supported_versions_route() -> ConduitResult<get_supported_versions::Response> { pub fn get_supported_versions_route() -> ConduitResult<get_supported_versions::Response> {
let mut unstable_features = BTreeMap::new();
unstable_features.insert("org.matrix.e2e_cross_signing".to_owned(), true);
Ok(get_supported_versions::Response { Ok(get_supported_versions::Response {
versions: vec!["r0.5.0".to_owned(), "r0.6.0".to_owned()], versions: vec!["r0.5.0".to_owned(), "r0.6.0".to_owned()],
unstable_features: BTreeMap::new(), unstable_features,
} }
.into()) .into())
} }
@ -204,33 +213,7 @@ pub fn register_route(
&EventType::PushRules, &EventType::PushRules,
serde_json::to_value(ruma::events::push_rules::PushRulesEvent { serde_json::to_value(ruma::events::push_rules::PushRulesEvent {
content: ruma::events::push_rules::PushRulesEventContent { content: ruma::events::push_rules::PushRulesEventContent {
global: ruma::events::push_rules::Ruleset { global: crate::push_rules::default_pushrules(&user_id),
content: vec![],
override_: vec![ruma::events::push_rules::ConditionalPushRule {
actions: vec![ruma::events::push_rules::Action::DontNotify],
default: true,
enabled: false,
rule_id: ".m.rule.master".to_owned(),
conditions: vec![],
}],
room: vec![],
sender: vec![],
underride: vec![ruma::events::push_rules::ConditionalPushRule {
actions: vec![
ruma::events::push_rules::Action::Notify,
ruma::events::push_rules::Action::SetTweak(ruma::push::Tweak::Sound(
"default".to_owned(),
)),
],
default: true,
enabled: true,
rule_id: ".m.rule.message".to_owned(),
conditions: vec![ruma::events::push_rules::PushCondition::EventMatch {
key: "type".to_owned(),
pattern: "m.room.message".to_owned(),
}],
}],
},
}, },
}) })
.expect("data is valid, we just created it") .expect("data is valid, we just created it")
@ -375,11 +358,11 @@ pub fn get_pushrules_all_route(
#[put( #[put(
"/_matrix/client/r0/pushrules/<_scope>/<_kind>/<_rule_id>", "/_matrix/client/r0/pushrules/<_scope>/<_kind>/<_rule_id>",
data = "<body>" //data = "<body>"
)] )]
pub fn set_pushrule_route( pub fn set_pushrule_route(
db: State<'_, Database>, //db: State<'_, Database>,
body: Ruma<set_pushrule::Request>, //body: Ruma<set_pushrule::Request>,
_scope: String, _scope: String,
_kind: String, _kind: String,
_rule_id: String, _rule_id: String,
@ -502,8 +485,7 @@ pub fn set_displayname_route(
displayname: body.displayname.clone(), displayname: body.displayname.clone(),
..serde_json::from_value::<EventJson<_>>( ..serde_json::from_value::<EventJson<_>>(
db.rooms db.rooms
.room_state(&room_id)? .room_state_get(&room_id, &EventType::RoomMember, &user_id.to_string())?
.get(&(EventType::RoomMember, user_id.to_string()))
.ok_or_else(|| { .ok_or_else(|| {
Error::bad_database( Error::bad_database(
"Tried to send displayname update for user not in the room.", "Tried to send displayname update for user not in the room.",
@ -593,8 +575,7 @@ pub fn set_avatar_url_route(
avatar_url: body.avatar_url.clone(), avatar_url: body.avatar_url.clone(),
..serde_json::from_value::<EventJson<_>>( ..serde_json::from_value::<EventJson<_>>(
db.rooms db.rooms
.room_state(&room_id)? .room_state_get(&room_id, &EventType::RoomMember, &user_id.to_string())?
.get(&(EventType::RoomMember, user_id.to_string()))
.ok_or_else(|| { .ok_or_else(|| {
Error::bad_database( Error::bad_database(
"Tried to send avatar url update for user not in the room.", "Tried to send avatar url update for user not in the room.",
@ -722,8 +703,11 @@ pub fn upload_keys_route(
} }
if let Some(device_keys) = &body.device_keys { if let Some(device_keys) = &body.device_keys {
db.users // This check is needed to assure that signatures are kept
.add_device_keys(user_id, device_id, device_keys, &db.globals)?; if db.users.get_device_keys(user_id, device_id)?.is_none() {
db.users
.add_device_keys(user_id, device_id, device_keys, &db.globals)?;
}
} }
Ok(upload_keys::Response { Ok(upload_keys::Response {
@ -737,33 +721,38 @@ pub fn get_keys_route(
db: State<'_, Database>, db: State<'_, Database>,
body: Ruma<get_keys::Request>, body: Ruma<get_keys::Request>,
) -> ConduitResult<get_keys::Response> { ) -> ConduitResult<get_keys::Response> {
let sender_id = body.user_id.as_ref().expect("user is authenticated");
let mut master_keys = BTreeMap::new();
let mut self_signing_keys = BTreeMap::new();
let mut user_signing_keys = BTreeMap::new();
let mut device_keys = BTreeMap::new(); let mut device_keys = BTreeMap::new();
for (user_id, device_ids) in &body.device_keys { for (user_id, device_ids) in &body.device_keys {
if device_ids.is_empty() { if device_ids.is_empty() {
let mut container = BTreeMap::new(); let mut container = BTreeMap::new();
for result in db.users.all_device_keys(&user_id.clone()) { for device_id in db.users.all_device_ids(user_id) {
let (device_id, mut keys) = result?; let device_id = device_id?;
if let Some(mut keys) = db.users.get_device_keys(user_id, &device_id)? {
let metadata = db
.users
.get_device_metadata(user_id, &device_id)?
.ok_or_else(|| {
Error::bad_database("all_device_keys contained nonexistent device.")
})?;
let metadata = db keys.unsigned = Some(keys::UnsignedDeviceInfo {
.users device_display_name: metadata.display_name,
.get_device_metadata(user_id, &device_id)? });
.ok_or_else(|| {
Error::bad_database("all_device_keys contained nonexistent device.")
})?;
keys.unsigned = Some(keys::UnsignedDeviceInfo { container.insert(device_id.to_owned(), keys);
device_display_name: metadata.display_name, }
});
container.insert(device_id, keys);
} }
device_keys.insert(user_id.clone(), container); device_keys.insert(user_id.clone(), container);
} else { } else {
for device_id in device_ids { for device_id in device_ids {
let mut container = BTreeMap::new(); let mut container = BTreeMap::new();
for keys in db.users.get_device_keys(&user_id.clone(), &device_id) { if let Some(mut keys) = db.users.get_device_keys(&user_id.clone(), &device_id)? {
let mut keys = keys?;
let metadata = db.users.get_device_metadata(user_id, &device_id)?.ok_or( let metadata = db.users.get_device_metadata(user_id, &device_id)?.ok_or(
Error::BadRequest( Error::BadRequest(
ErrorKind::InvalidParam, ErrorKind::InvalidParam,
@ -780,11 +769,26 @@ pub fn get_keys_route(
device_keys.insert(user_id.clone(), container); device_keys.insert(user_id.clone(), container);
} }
} }
if let Some(master_key) = db.users.get_master_key(user_id, sender_id)? {
master_keys.insert(user_id.clone(), master_key);
}
if let Some(self_signing_key) = db.users.get_self_signing_key(user_id, sender_id)? {
self_signing_keys.insert(user_id.clone(), self_signing_key);
}
if user_id == sender_id {
if let Some(user_signing_key) = db.users.get_user_signing_key(sender_id)? {
user_signing_keys.insert(user_id.clone(), user_signing_key);
}
}
} }
Ok(get_keys::Response { Ok(get_keys::Response {
failures: BTreeMap::new(), master_keys,
self_signing_keys,
user_signing_keys,
device_keys, device_keys,
failures: BTreeMap::new(),
} }
.into()) .into())
} }
@ -817,6 +821,125 @@ pub fn claim_keys_route(
.into()) .into())
} }
#[post("/_matrix/client/unstable/room_keys/version", data = "<body>")]
pub fn create_backup_route(
db: State<'_, Database>,
body: Ruma<create_backup::Request>,
) -> ConduitResult<create_backup::Response> {
let user_id = body.user_id.as_ref().expect("user is authenticated");
let version = db
.key_backups
.create_backup(&user_id, &body.algorithm, &db.globals)?;
Ok(create_backup::Response { version }.into())
}
#[put(
"/_matrix/client/unstable/room_keys/version/<_version>",
data = "<body>"
)]
pub fn update_backup_route(
db: State<'_, Database>,
body: Ruma<update_backup::Request>,
_version: String,
) -> ConduitResult<update_backup::Response> {
let user_id = body.user_id.as_ref().expect("user is authenticated");
db.key_backups
.update_backup(&user_id, &body.version, &body.algorithm, &db.globals)?;
Ok(update_backup::Response.into())
}
#[get("/_matrix/client/unstable/room_keys/version", data = "<body>")]
pub fn get_latest_backup_route(
db: State<'_, Database>,
body: Ruma<get_latest_backup::Request>,
) -> ConduitResult<get_latest_backup::Response> {
let user_id = body.user_id.as_ref().expect("user is authenticated");
let (version, algorithm) =
db.key_backups
.get_latest_backup(&user_id)?
.ok_or(Error::BadRequest(
ErrorKind::NotFound,
"Key backup does not exist.",
))?;
Ok(get_latest_backup::Response {
algorithm,
count: (db.key_backups.count_keys(user_id, &version)? as u32).into(),
etag: db.key_backups.get_etag(user_id, &version)?,
version,
}
.into())
}
#[get(
"/_matrix/client/unstable/room_keys/version/<_version>",
data = "<body>"
)]
pub fn get_backup_route(
db: State<'_, Database>,
body: Ruma<get_backup::Request>,
_version: String,
) -> ConduitResult<get_backup::Response> {
let user_id = body.user_id.as_ref().expect("user is authenticated");
let algorithm =
db.key_backups
.get_backup(&user_id, &body.version)?
.ok_or(Error::BadRequest(
ErrorKind::NotFound,
"Key backup does not exist.",
))?;
Ok(get_backup::Response {
algorithm,
count: (db.key_backups.count_keys(user_id, &body.version)? as u32).into(),
etag: db.key_backups.get_etag(user_id, &body.version)?,
version: body.version.clone(),
}
.into())
}
#[put("/_matrix/client/unstable/room_keys/keys", data = "<body>")]
pub fn add_backup_keys_route(
db: State<'_, Database>,
body: Ruma<add_backup_keys::Request>,
) -> ConduitResult<add_backup_keys::Response> {
let user_id = body.user_id.as_ref().expect("user is authenticated");
for (room_id, room) in &body.rooms {
for (session_id, key_data) in &room.sessions {
db.key_backups.add_key(
&user_id,
&body.version,
&room_id,
&session_id,
&key_data,
&db.globals,
)?
}
}
Ok(add_backup_keys::Response {
count: (db.key_backups.count_keys(user_id, &body.version)? as u32).into(),
etag: db.key_backups.get_etag(user_id, &body.version)?,
}
.into())
}
#[get("/_matrix/client/unstable/room_keys/keys", data = "<body>")]
pub fn get_backup_keys_route(
db: State<'_, Database>,
body: Ruma<get_backup_keys::Request>,
) -> ConduitResult<get_backup_keys::Response> {
let user_id = body.user_id.as_ref().expect("user is authenticated");
let rooms = db.key_backups.get_all(&user_id, &body.version)?;
Ok(get_backup_keys::Response { rooms }.into())
}
#[post("/_matrix/client/r0/rooms/<_room_id>/read_markers", data = "<body>")] #[post("/_matrix/client/r0/rooms/<_room_id>/read_markers", data = "<body>")]
pub fn set_read_marker_route( pub fn set_read_marker_route(
db: State<'_, Database>, db: State<'_, Database>,
@ -1265,35 +1388,13 @@ pub fn join_room_by_id_route(
// TODO: Ask a remote server if we don't have this room // TODO: Ask a remote server if we don't have this room
let event = db let event = member::MemberEventContent {
.rooms membership: member::MembershipState::Join,
.room_state(&body.room_id)? displayname: db.users.displayname(&user_id)?,
.get(&(EventType::RoomMember, user_id.to_string())) avatar_url: db.users.avatar_url(&user_id)?,
.map_or_else( is_direct: None,
|| { third_party_invite: None,
// There was no existing membership event };
Ok::<_, Error>(member::MemberEventContent {
membership: member::MembershipState::Join,
displayname: db.users.displayname(&user_id)?,
avatar_url: db.users.avatar_url(&user_id)?,
is_direct: None,
third_party_invite: None,
})
},
|pdu| {
// We change the existing membership event
let mut event = serde_json::from_value::<EventJson<member::MemberEventContent>>(
pdu.content.clone(),
)
.map_err(|_| Error::bad_database("Invalid member event in db."))?
.deserialize()
.map_err(|_| Error::bad_database("Invalid member event in db."))?;
event.membership = member::MembershipState::Join;
event.displayname = db.users.displayname(&user_id)?;
event.avatar_url = db.users.avatar_url(&user_id)?;
Ok(event)
},
)?;
db.rooms.append_pdu( db.rooms.append_pdu(
body.room_id.clone(), body.room_id.clone(),
@ -1348,11 +1449,10 @@ pub fn leave_room_route(
_room_id: String, _room_id: String,
) -> ConduitResult<leave_room::Response> { ) -> ConduitResult<leave_room::Response> {
let user_id = body.user_id.as_ref().expect("user is authenticated"); let user_id = body.user_id.as_ref().expect("user is authenticated");
let state = db.rooms.room_state(&body.room_id)?;
let mut event = serde_json::from_value::<EventJson<member::MemberEventContent>>( let mut event = serde_json::from_value::<EventJson<member::MemberEventContent>>(
state db.rooms
.get(&(EventType::RoomMember, user_id.to_string())) .room_state_get(&body.room_id, &EventType::RoomMember, &user_id.to_string())?
.ok_or(Error::BadRequest( .ok_or(Error::BadRequest(
ErrorKind::BadState, ErrorKind::BadState,
"Cannot leave a room you are not a member of.", "Cannot leave a room you are not a member of.",
@ -1387,12 +1487,11 @@ pub fn kick_user_route(
_room_id: String, _room_id: String,
) -> ConduitResult<kick_user::Response> { ) -> ConduitResult<kick_user::Response> {
let user_id = body.user_id.as_ref().expect("user is authenticated"); let user_id = body.user_id.as_ref().expect("user is authenticated");
let state = db.rooms.room_state(&body.room_id)?;
let mut event = let mut event =
serde_json::from_value::<EventJson<ruma::events::room::member::MemberEventContent>>( serde_json::from_value::<EventJson<ruma::events::room::member::MemberEventContent>>(
state db.rooms
.get(&(EventType::RoomMember, user_id.to_string())) .room_state_get(&body.room_id, &EventType::RoomMember, &user_id.to_string())?
.ok_or(Error::BadRequest( .ok_or(Error::BadRequest(
ErrorKind::BadState, ErrorKind::BadState,
"Cannot kick member that's not in the room.", "Cannot kick member that's not in the room.",
@ -1428,12 +1527,12 @@ pub fn ban_user_route(
_room_id: String, _room_id: String,
) -> ConduitResult<ban_user::Response> { ) -> ConduitResult<ban_user::Response> {
let user_id = body.user_id.as_ref().expect("user is authenticated"); let user_id = body.user_id.as_ref().expect("user is authenticated");
let state = db.rooms.room_state(&body.room_id)?;
// TODO: reason // TODO: reason
let event = state let event = db
.get(&(EventType::RoomMember, user_id.to_string())) .rooms
.room_state_get(&body.room_id, &EventType::RoomMember, &user_id.to_string())?
.map_or( .map_or(
Ok::<_, Error>(member::MemberEventContent { Ok::<_, Error>(member::MemberEventContent {
membership: member::MembershipState::Ban, membership: member::MembershipState::Ban,
@ -1475,12 +1574,11 @@ pub fn unban_user_route(
_room_id: String, _room_id: String,
) -> ConduitResult<unban_user::Response> { ) -> ConduitResult<unban_user::Response> {
let user_id = body.user_id.as_ref().expect("user is authenticated"); let user_id = body.user_id.as_ref().expect("user is authenticated");
let state = db.rooms.room_state(&body.room_id)?;
let mut event = let mut event =
serde_json::from_value::<EventJson<ruma::events::room::member::MemberEventContent>>( serde_json::from_value::<EventJson<ruma::events::room::member::MemberEventContent>>(
state db.rooms
.get(&(EventType::RoomMember, user_id.to_string())) .room_state_get(&body.room_id, &EventType::RoomMember, &user_id.to_string())?
.ok_or(Error::BadRequest( .ok_or(Error::BadRequest(
ErrorKind::BadState, ErrorKind::BadState,
"Cannot unban a user who is not banned.", "Cannot unban a user who is not banned.",
@ -1642,7 +1740,8 @@ pub async fn get_public_rooms_filtered_route(
.map(|room_id| { .map(|room_id| {
let room_id = room_id?; let room_id = room_id?;
let state = db.rooms.room_state(&room_id)?; // TODO: Do not load full state?
let state = db.rooms.room_state_full(&room_id)?;
let chunk = directory::PublicRoomsChunk { let chunk = directory::PublicRoomsChunk {
aliases: Vec::new(), aliases: Vec::new(),
@ -1774,10 +1873,30 @@ pub fn search_users_route(
.into()) .into())
} }
#[get("/_matrix/client/r0/rooms/<_room_id>/members")] #[get("/_matrix/client/r0/rooms/<_room_id>/members", data = "<body>")]
pub fn get_member_events_route(_room_id: String) -> ConduitResult<get_member_events::Response> { pub fn get_member_events_route(
warn!("TODO: get_member_events_route"); db: State<'_, Database>,
Ok(get_member_events::Response { chunk: Vec::new() }.into()) body: Ruma<get_member_events::Request>,
_room_id: String,
) -> ConduitResult<get_member_events::Response> {
let user_id = body.user_id.as_ref().expect("user is authenticated");
if !db.rooms.is_joined(user_id, &body.room_id)? {
return Err(Error::BadRequest(
ErrorKind::Forbidden,
"You don't have permission to view this room.",
));
}
Ok(get_member_events::Response {
chunk: db
.rooms
.room_state_type(&body.room_id, &EventType::RoomMember)?
.values()
.map(|pdu| pdu.to_member_event())
.collect(),
}
.into())
} }
#[get("/_matrix/client/r0/thirdparty/protocols")] #[get("/_matrix/client/r0/thirdparty/protocols")]
@ -1951,7 +2070,7 @@ pub fn get_state_events_route(
Ok(get_state_events::Response { Ok(get_state_events::Response {
room_state: db room_state: db
.rooms .rooms
.room_state(&body.room_id)? .room_state_full(&body.room_id)?
.values() .values()
.map(|pdu| pdu.to_state_event()) .map(|pdu| pdu.to_state_event())
.collect(), .collect(),
@ -1979,10 +2098,9 @@ pub fn get_state_events_for_key_route(
)); ));
} }
let state = db.rooms.room_state(&body.room_id)?; let event = db
.rooms
let event = state .room_state_get(&body.room_id, &body.event_type, &body.state_key)?
.get(&(body.event_type.clone(), body.state_key.clone()))
.ok_or(Error::BadRequest( .ok_or(Error::BadRequest(
ErrorKind::NotFound, ErrorKind::NotFound,
"State event not found.", "State event not found.",
@ -2014,17 +2132,16 @@ pub fn get_state_events_for_empty_key_route(
)); ));
} }
let state = db.rooms.room_state(&body.room_id)?; let event = db
.rooms
let event = state .room_state_get(&body.room_id, &body.event_type, "")?
.get(&(body.event_type.clone(), "".to_owned()))
.ok_or(Error::BadRequest( .ok_or(Error::BadRequest(
ErrorKind::NotFound, ErrorKind::NotFound,
"State event not found.", "State event not found.",
))?; ))?;
Ok(get_state_events_for_empty_key::Response { Ok(get_state_events_for_empty_key::Response {
content: serde_json::value::to_raw_value(event) content: serde_json::value::to_raw_value(&event)
.map_err(|_| Error::bad_database("Invalid event content in database"))?, .map_err(|_| Error::bad_database("Invalid event content in database"))?,
} }
.into()) .into())
@ -2053,7 +2170,7 @@ pub fn sync_route(
let mut pdus = db let mut pdus = db
.rooms .rooms
.pdus_since(&room_id, since)? .pdus_since(&user_id, &room_id, since)?
.filter_map(|r| r.ok()) // Filter out buggy events .filter_map(|r| r.ok()) // Filter out buggy events
.collect::<Vec<_>>(); .collect::<Vec<_>>();
@ -2068,7 +2185,7 @@ pub fn sync_route(
let content = serde_json::from_value::< let content = serde_json::from_value::<
EventJson<ruma::events::room::member::MemberEventContent>, EventJson<ruma::events::room::member::MemberEventContent>,
>(pdu.content.clone()) >(pdu.content.clone())
.map_err(|_| Error::bad_database("Invalid PDU in database."))? .expect("EventJson::from_value always works")
.deserialize() .deserialize()
.map_err(|_| Error::bad_database("Invalid PDU in database."))?; .map_err(|_| Error::bad_database("Invalid PDU in database."))?;
if content.membership == ruma::events::room::member::MembershipState::Join { if content.membership == ruma::events::room::member::MembershipState::Join {
@ -2081,7 +2198,7 @@ pub fn sync_route(
} }
} }
let state = db.rooms.room_state(&room_id)?; let members = db.rooms.room_state_type(&room_id, &EventType::RoomMember)?;
let (joined_member_count, invited_member_count, heroes) = if send_member_count { let (joined_member_count, invited_member_count, heroes) = if send_member_count {
let joined_member_count = db.rooms.room_members(&room_id).count(); let joined_member_count = db.rooms.room_members(&room_id).count();
@ -2096,7 +2213,7 @@ pub fn sync_route(
for hero in db for hero in db
.rooms .rooms
.all_pdus(&room_id)? .all_pdus(&user_id, &room_id)?
.filter_map(|pdu| pdu.ok()) // Ignore all broken pdus .filter_map(|pdu| pdu.ok()) // Ignore all broken pdus
.filter(|pdu| pdu.kind == EventType::RoomMember) .filter(|pdu| pdu.kind == EventType::RoomMember)
.map(|pdu| { .map(|pdu| {
@ -2111,8 +2228,8 @@ pub fn sync_route(
let current_content = serde_json::from_value::< let current_content = serde_json::from_value::<
EventJson<ruma::events::room::member::MemberEventContent>, EventJson<ruma::events::room::member::MemberEventContent>,
>( >(
state members
.get(&(EventType::RoomMember, state_key.clone())) .get(state_key)
.ok_or_else(|| { .ok_or_else(|| {
Error::bad_database( Error::bad_database(
"A user that joined once has no member event anymore.", "A user that joined once has no member event anymore.",
@ -2170,7 +2287,7 @@ pub fn sync_route(
if let Some(last_read) = db.rooms.edus.room_read_get(&room_id, &user_id)? { if let Some(last_read) = db.rooms.edus.room_read_get(&room_id, &user_id)? {
Some( Some(
(db.rooms (db.rooms
.pdus_since(&room_id, last_read)? .pdus_since(&user_id, &room_id, last_read)?
.filter_map(|pdu| pdu.ok()) // Filter out buggy events .filter_map(|pdu| pdu.ok()) // Filter out buggy events
.filter(|pdu| { .filter(|pdu| {
matches!( matches!(
@ -2264,7 +2381,8 @@ pub fn sync_route(
// TODO: state before timeline // TODO: state before timeline
state: sync_events::State { state: sync_events::State {
events: if joined_since_last_sync { events: if joined_since_last_sync {
state db.rooms
.room_state_full(&room_id)?
.into_iter() .into_iter()
.map(|(_, pdu)| pdu.to_state_event()) .map(|(_, pdu)| pdu.to_state_event())
.collect() .collect()
@ -2283,7 +2401,7 @@ pub fn sync_route(
let mut left_rooms = BTreeMap::new(); let mut left_rooms = BTreeMap::new();
for room_id in db.rooms.rooms_left(&user_id) { for room_id in db.rooms.rooms_left(&user_id) {
let room_id = room_id?; let room_id = room_id?;
let pdus = db.rooms.pdus_since(&room_id, since)?; let pdus = db.rooms.pdus_since(&user_id, &room_id, since)?;
let room_events = pdus let room_events = pdus
.filter_map(|pdu| pdu.ok()) // Filter out buggy events .filter_map(|pdu| pdu.ok()) // Filter out buggy events
.map(|pdu| pdu.to_room_event()) .map(|pdu| pdu.to_room_event())
@ -2337,7 +2455,7 @@ pub fn sync_route(
invite_state: sync_events::InviteState { invite_state: sync_events::InviteState {
events: db events: db
.rooms .rooms
.room_state(&room_id)? .room_state_full(&room_id)?
.into_iter() .into_iter()
.map(|(_, pdu)| pdu.to_stripped_state_event()) .map(|(_, pdu)| pdu.to_stripped_state_event())
.collect(), .collect(),
@ -2387,7 +2505,7 @@ pub fn sync_route(
device_lists: sync_events::DeviceLists { device_lists: sync_events::DeviceLists {
changed: if since != 0 { changed: if since != 0 {
db.users db.users
.device_keys_changed(since) .keys_changed(since)
.filter_map(|u| u.ok()) .filter_map(|u| u.ok())
.collect() // Filter out buggy events .collect() // Filter out buggy events
} else { } else {
@ -2438,7 +2556,7 @@ pub fn get_context_route(
let events_before = db let events_before = db
.rooms .rooms
.pdus_until(&body.room_id, base_token) .pdus_until(&user_id, &body.room_id, base_token)
.take( .take(
u32::try_from(body.limit).map_err(|_| { u32::try_from(body.limit).map_err(|_| {
Error::BadRequest(ErrorKind::InvalidParam, "Limit value is invalid.") Error::BadRequest(ErrorKind::InvalidParam, "Limit value is invalid.")
@ -2464,7 +2582,7 @@ pub fn get_context_route(
let events_after = db let events_after = db
.rooms .rooms
.pdus_after(&body.room_id, base_token) .pdus_after(&user_id, &body.room_id, base_token)
.take( .take(
u32::try_from(body.limit).map_err(|_| { u32::try_from(body.limit).map_err(|_| {
Error::BadRequest(ErrorKind::InvalidParam, "Limit value is invalid.") Error::BadRequest(ErrorKind::InvalidParam, "Limit value is invalid.")
@ -2496,7 +2614,7 @@ pub fn get_context_route(
events_after, events_after,
state: db // TODO: State at event state: db // TODO: State at event
.rooms .rooms
.room_state(&body.room_id)? .room_state_full(&body.room_id)?
.values() .values()
.map(|pdu| pdu.to_state_event()) .map(|pdu| pdu.to_state_event())
.collect(), .collect(),
@ -2528,7 +2646,7 @@ pub fn get_message_events_route(
get_message_events::Direction::Forward => { get_message_events::Direction::Forward => {
let events_after = db let events_after = db
.rooms .rooms
.pdus_after(&body.room_id, from) .pdus_after(&user_id, &body.room_id, from)
// Use limit or else 10 // Use limit or else 10
.take(body.limit.map_or(Ok::<_, Error>(10_usize), |l| { .take(body.limit.map_or(Ok::<_, Error>(10_usize), |l| {
Ok(u32::try_from(l).map_err(|_| { Ok(u32::try_from(l).map_err(|_| {
@ -2563,7 +2681,7 @@ pub fn get_message_events_route(
get_message_events::Direction::Backward => { get_message_events::Direction::Backward => {
let events_before = db let events_before = db
.rooms .rooms
.pdus_until(&body.room_id, from) .pdus_until(&user_id, &body.room_id, from)
// Use limit or else 10 // Use limit or else 10
.take(body.limit.map_or(Ok::<_, Error>(10_usize), |l| { .take(body.limit.map_or(Ok::<_, Error>(10_usize), |l| {
Ok(u32::try_from(l).map_err(|_| { Ok(u32::try_from(l).map_err(|_| {
@ -2883,6 +3001,122 @@ pub fn delete_devices_route(
Ok(delete_devices::Response.into()) Ok(delete_devices::Response.into())
} }
#[post("/_matrix/client/unstable/keys/device_signing/upload", data = "<body>")]
pub fn upload_signing_keys_route(
db: State<'_, Database>,
body: Ruma<upload_signing_keys::Request>,
) -> ConduitResult<upload_signing_keys::Response> {
let user_id = body.user_id.as_ref().expect("user is authenticated");
let device_id = body.device_id.as_ref().expect("user is authenticated");
// UIAA
let mut uiaainfo = UiaaInfo {
flows: vec![AuthFlow {
stages: vec!["m.login.password".to_owned()],
}],
completed: Vec::new(),
params: Default::default(),
session: None,
auth_error: None,
};
if let Some(auth) = &body.auth {
let (worked, uiaainfo) = db.uiaa.try_auth(
&user_id,
&device_id,
auth,
&uiaainfo,
&db.users,
&db.globals,
)?;
if !worked {
return Err(Error::Uiaa(uiaainfo));
}
// Success!
} else {
uiaainfo.session = Some(utils::random_string(SESSION_ID_LENGTH));
db.uiaa.create(&user_id, &device_id, &uiaainfo)?;
return Err(Error::Uiaa(uiaainfo));
}
if let Some(master_key) = &body.master_key {
db.users.add_cross_signing_keys(
user_id,
&master_key,
&body.self_signing_key,
&body.user_signing_key,
&db.globals,
)?;
}
Ok(upload_signing_keys::Response.into())
}
#[post("/_matrix/client/unstable/keys/signatures/upload", data = "<body>")]
pub fn upload_signatures_route(
db: State<'_, Database>,
body: Ruma<upload_signatures::Request>,
) -> ConduitResult<upload_signatures::Response> {
let sender_id = body.user_id.as_ref().expect("user is authenticated");
for (user_id, signed_keys) in &body.signed_keys {
for (key_id, signed_key) in signed_keys {
for signature in signed_key
.get("signatures")
.ok_or(Error::BadRequest(
ErrorKind::InvalidParam,
"Missing signatures field.",
))?
.get(sender_id.to_string())
.ok_or(Error::BadRequest(
ErrorKind::InvalidParam,
"Invalid user in signatures field.",
))?
.as_object()
.ok_or(Error::BadRequest(
ErrorKind::InvalidParam,
"Invalid signature.",
))?
.clone()
.into_iter()
{
// Signature validation?
let signature = (
signature.0,
signature
.1
.as_str()
.ok_or(Error::BadRequest(
ErrorKind::InvalidParam,
"Invalid signature value.",
))?
.to_owned(),
);
db.users
.sign_key(&user_id, &key_id, signature, &sender_id, &db.globals)?;
}
}
}
Ok(upload_signatures::Response.into())
}
#[get("/_matrix/client/r0/pushers")]
pub fn pushers_route() -> ConduitResult<get_pushers::Response> {
Ok(get_pushers::Response {
pushers: Vec::new(),
}
.into())
}
#[post("/_matrix/client/r0/pushers/set")]
pub fn set_pushers_route() -> ConduitResult<get_pushers::Response> {
Ok(get_pushers::Response {
pushers: Vec::new(),
}
.into())
}
#[options("/<_segments..>")] #[options("/<_segments..>")]
pub fn options_route( pub fn options_route(
_segments: rocket::http::uri::Segments<'_>, _segments: rocket::http::uri::Segments<'_>,

View File

@ -1,6 +1,7 @@
pub(self) mod account_data; pub(self) mod account_data;
pub(self) mod global_edus; pub(self) mod global_edus;
pub(self) mod globals; pub(self) mod globals;
pub(self) mod key_backups;
pub(self) mod media; pub(self) mod media;
pub(self) mod rooms; pub(self) mod rooms;
pub(self) mod uiaa; pub(self) mod uiaa;
@ -21,6 +22,7 @@ pub struct Database {
pub account_data: account_data::AccountData, pub account_data: account_data::AccountData,
pub global_edus: global_edus::GlobalEdus, pub global_edus: global_edus::GlobalEdus,
pub media: media::Media, pub media: media::Media,
pub key_backups: key_backups::KeyBackups,
pub _db: sled::Db, pub _db: sled::Db,
} }
@ -73,8 +75,11 @@ impl Database {
userdeviceid_metadata: db.open_tree("userdeviceid_metadata")?, userdeviceid_metadata: db.open_tree("userdeviceid_metadata")?,
token_userdeviceid: db.open_tree("token_userdeviceid")?, token_userdeviceid: db.open_tree("token_userdeviceid")?,
onetimekeyid_onetimekeys: db.open_tree("onetimekeyid_onetimekeys")?, onetimekeyid_onetimekeys: db.open_tree("onetimekeyid_onetimekeys")?,
userdeviceid_devicekeys: db.open_tree("userdeviceid_devicekeys")?, keychangeid_userid: db.open_tree("devicekeychangeid_userid")?,
devicekeychangeid_userid: db.open_tree("devicekeychangeid_userid")?, keyid_key: db.open_tree("keyid_key")?,
userid_masterkeyid: db.open_tree("userid_masterkeyid")?,
userid_selfsigningkeyid: db.open_tree("userid_selfsigningkeyid")?,
userid_usersigningkeyid: db.open_tree("userid_usersigningkeyid")?,
todeviceid_events: db.open_tree("todeviceid_events")?, todeviceid_events: db.open_tree("todeviceid_events")?,
}, },
uiaa: uiaa::Uiaa { uiaa: uiaa::Uiaa {
@ -111,6 +116,11 @@ impl Database {
media: media::Media { media: media::Media {
mediaid_file: db.open_tree("mediaid_file")?, mediaid_file: db.open_tree("mediaid_file")?,
}, },
key_backups: key_backups::KeyBackups {
backupid_algorithm: db.open_tree("backupid_algorithm")?,
backupid_etag: db.open_tree("backupid_etag")?,
backupkeyid_backup: db.open_tree("backupkeyid_backupmetadata")?,
},
_db: db, _db: db,
}) })
} }

207
src/database/key_backups.rs Normal file
View File

@ -0,0 +1,207 @@
use crate::{utils, Error, Result};
use ruma::{
api::client::{
error::ErrorKind,
r0::backup::{get_backup_keys::Sessions, BackupAlgorithm, KeyData},
},
identifiers::{RoomId, UserId},
};
use std::{collections::BTreeMap, convert::TryFrom};
pub struct KeyBackups {
pub(super) backupid_algorithm: sled::Tree, // BackupId = UserId + Version(Count)
pub(super) backupid_etag: sled::Tree, // BackupId = UserId + Version(Count)
pub(super) backupkeyid_backup: sled::Tree, // BackupKeyId = UserId + Version + RoomId + SessionId
}
impl KeyBackups {
pub fn create_backup(
&self,
user_id: &UserId,
backup_metadata: &BackupAlgorithm,
globals: &super::globals::Globals,
) -> Result<String> {
let version = globals.next_count()?.to_string();
let mut key = user_id.to_string().as_bytes().to_vec();
key.push(0xff);
key.extend_from_slice(&version.as_bytes());
self.backupid_algorithm.insert(
&key,
&*serde_json::to_string(backup_metadata)
.expect("BackupAlgorithm::to_string always works"),
)?;
self.backupid_etag
.insert(&key, &globals.next_count()?.to_be_bytes())?;
Ok(version)
}
pub fn update_backup(
&self,
user_id: &UserId,
version: &str,
backup_metadata: &BackupAlgorithm,
globals: &super::globals::Globals,
) -> Result<String> {
let mut key = user_id.to_string().as_bytes().to_vec();
key.push(0xff);
key.extend_from_slice(&version.as_bytes());
if self.backupid_algorithm.get(&key)?.is_none() {
return Err(Error::BadRequest(
ErrorKind::NotFound,
"Tried to update nonexistent backup.",
));
}
self.backupid_algorithm.insert(
&key,
&*serde_json::to_string(backup_metadata)
.expect("BackupAlgorithm::to_string always works"),
)?;
self.backupid_etag
.insert(&key, &globals.next_count()?.to_be_bytes())?;
Ok(version.to_string())
}
pub fn get_latest_backup(&self, user_id: &UserId) -> Result<Option<(String, BackupAlgorithm)>> {
let mut prefix = user_id.to_string().as_bytes().to_vec();
prefix.push(0xff);
self.backupid_algorithm
.scan_prefix(&prefix)
.last()
.map_or(Ok(None), |r| {
let (key, value) = r?;
let version = utils::string_from_bytes(
key.rsplit(|&b| b == 0xff)
.next()
.expect("rsplit always returns an element"),
)
.map_err(|_| Error::bad_database("backupid_algorithm key is invalid."))?;
Ok(Some((
version,
serde_json::from_slice(&value).map_err(|_| {
Error::bad_database("Algorithm in backupid_algorithm is invalid.")
})?,
)))
})
}
pub fn get_backup(&self, user_id: &UserId, version: &str) -> Result<Option<BackupAlgorithm>> {
let mut key = user_id.to_string().as_bytes().to_vec();
key.push(0xff);
key.extend_from_slice(version.as_bytes());
self.backupid_algorithm.get(key)?.map_or(Ok(None), |bytes| {
Ok(serde_json::from_slice(&bytes)
.map_err(|_| Error::bad_database("Algorithm in backupid_algorithm is invalid."))?)
})
}
pub fn add_key(
&self,
user_id: &UserId,
version: &str,
room_id: &RoomId,
session_id: &str,
key_data: &KeyData,
globals: &super::globals::Globals,
) -> Result<()> {
let mut key = user_id.to_string().as_bytes().to_vec();
key.push(0xff);
key.extend_from_slice(version.as_bytes());
if self.backupid_algorithm.get(&key)?.is_none() {
return Err(Error::BadRequest(
ErrorKind::NotFound,
"Tried to update nonexistent backup.",
));
}
self.backupid_etag
.insert(&key, &globals.next_count()?.to_be_bytes())?;
key.push(0xff);
key.extend_from_slice(room_id.to_string().as_bytes());
key.push(0xff);
key.extend_from_slice(session_id.as_bytes());
self.backupkeyid_backup.insert(
&key,
&*serde_json::to_string(&key_data).expect("KeyData::to_string always works"),
)?;
Ok(())
}
pub fn count_keys(&self, user_id: &UserId, version: &str) -> Result<usize> {
let mut prefix = user_id.to_string().as_bytes().to_vec();
prefix.push(0xff);
prefix.extend_from_slice(version.as_bytes());
Ok(self.backupkeyid_backup.scan_prefix(&prefix).count())
}
pub fn get_etag(&self, user_id: &UserId, version: &str) -> Result<String> {
let mut key = user_id.to_string().as_bytes().to_vec();
key.push(0xff);
key.extend_from_slice(&version.as_bytes());
Ok(utils::u64_from_bytes(
&self
.backupid_etag
.get(&key)?
.ok_or_else(|| Error::bad_database("Backup has no etag."))?,
)
.map_err(|_| Error::bad_database("etag in backupid_etag invalid."))?
.to_string())
}
pub fn get_all(&self, user_id: &UserId, version: &str) -> Result<BTreeMap<RoomId, Sessions>> {
let mut prefix = user_id.to_string().as_bytes().to_vec();
prefix.push(0xff);
prefix.extend_from_slice(version.as_bytes());
let mut rooms = BTreeMap::<RoomId, Sessions>::new();
for result in self.backupkeyid_backup.scan_prefix(&prefix).map(|r| {
let (key, value) = r?;
let mut parts = key.rsplit(|&b| b == 0xff);
let session_id = utils::string_from_bytes(
&parts
.next()
.ok_or_else(|| Error::bad_database("backupkeyid_backup key is invalid."))?,
)
.map_err(|_| Error::bad_database("backupkeyid_backup session_id is invalid."))?;
let room_id = RoomId::try_from(
utils::string_from_bytes(
&parts
.next()
.ok_or_else(|| Error::bad_database("backupkeyid_backup key is invalid."))?,
)
.map_err(|_| Error::bad_database("backupkeyid_backup room_id is invalid."))?,
)
.map_err(|_| Error::bad_database("backupkeyid_backup room_id is invalid room id."))?;
let key_data = serde_json::from_slice(&value)
.map_err(|_| Error::bad_database("KeyData in backupkeyid_backup is invalid."))?;
Ok::<_, Error>((room_id, session_id, key_data))
}) {
let (room_id, session_id, key_data) = result?;
rooms
.entry(room_id)
.or_insert_with(|| Sessions {
sessions: BTreeMap::new(),
})
.sessions
.insert(session_id, key_data);
}
Ok(rooms)
}
}

View File

@ -56,7 +56,10 @@ impl Rooms {
} }
/// Returns the full room state. /// Returns the full room state.
pub fn room_state(&self, room_id: &RoomId) -> Result<HashMap<(EventType, String), PduEvent>> { pub fn room_state_full(
&self,
room_id: &RoomId,
) -> Result<HashMap<(EventType, String), PduEvent>> {
let mut hashmap = HashMap::new(); let mut hashmap = HashMap::new();
for pdu in self for pdu in self
.roomstateid_pdu .roomstateid_pdu
@ -78,6 +81,58 @@ impl Rooms {
Ok(hashmap) Ok(hashmap)
} }
/// Returns the full room state.
pub fn room_state_type(
&self,
room_id: &RoomId,
event_type: &EventType,
) -> Result<HashMap<String, PduEvent>> {
let mut prefix = room_id.to_string().as_bytes().to_vec();
prefix.push(0xff);
prefix.extend_from_slice(&event_type.to_string().as_bytes());
let mut hashmap = HashMap::new();
for pdu in self
.roomstateid_pdu
.scan_prefix(&prefix)
.values()
.map(|value| {
Ok::<_, Error>(
serde_json::from_slice::<PduEvent>(&value?)
.map_err(|_| Error::bad_database("Invalid PDU in db."))?,
)
})
{
let pdu = pdu?;
let state_key = pdu.state_key.clone().ok_or_else(|| {
Error::bad_database("Room state contains event without state_key.")
})?;
hashmap.insert(state_key, pdu);
}
Ok(hashmap)
}
/// Returns the full room state.
pub fn room_state_get(
&self,
room_id: &RoomId,
event_type: &EventType,
state_key: &str,
) -> Result<Option<PduEvent>> {
let mut key = room_id.to_string().as_bytes().to_vec();
key.push(0xff);
key.extend_from_slice(&event_type.to_string().as_bytes());
key.push(0xff);
key.extend_from_slice(&state_key.as_bytes());
self.roomstateid_pdu.get(&key)?.map_or(Ok(None), |value| {
Ok::<_, Error>(Some(
serde_json::from_slice::<PduEvent>(&value)
.map_err(|_| Error::bad_database("Invalid PDU in db."))?,
))
})
}
/// Returns the `count` of this pdu's id. /// Returns the `count` of this pdu's id.
pub fn get_pdu_count(&self, event_id: &EventId) -> Result<Option<u64>> { pub fn get_pdu_count(&self, event_id: &EventId) -> Result<Option<u64>> {
self.eventid_pduid self.eventid_pduid
@ -212,8 +267,7 @@ impl Rooms {
// Is the event authorized? // Is the event authorized?
if let Some(state_key) = &state_key { if let Some(state_key) = &state_key {
let power_levels = self let power_levels = self
.room_state(&room_id)? .room_state_get(&room_id, &EventType::RoomPowerLevels, "")?
.get(&(EventType::RoomPowerLevels, "".to_owned()))
.map_or_else( .map_or_else(
|| { || {
Ok::<_, Error>(power_levels::PowerLevelsEventContent { Ok::<_, Error>(power_levels::PowerLevelsEventContent {
@ -244,8 +298,7 @@ impl Rooms {
}, },
)?; )?;
let sender_membership = self let sender_membership = self
.room_state(&room_id)? .room_state_get(&room_id, &EventType::RoomMember, &sender.to_string())?
.get(&(EventType::RoomMember, sender.to_string()))
.map_or(Ok::<_, Error>(member::MembershipState::Leave), |pdu| { .map_or(Ok::<_, Error>(member::MembershipState::Leave), |pdu| {
Ok( Ok(
serde_json::from_value::<EventJson<member::MemberEventContent>>( serde_json::from_value::<EventJson<member::MemberEventContent>>(
@ -280,8 +333,11 @@ impl Rooms {
})?; })?;
let current_membership = self let current_membership = self
.room_state(&room_id)? .room_state_get(
.get(&(EventType::RoomMember, target_user_id.to_string())) &room_id,
&EventType::RoomMember,
&target_user_id.to_string(),
)?
.map_or(Ok::<_, Error>(member::MembershipState::Leave), |pdu| { .map_or(Ok::<_, Error>(member::MembershipState::Leave), |pdu| {
Ok( Ok(
serde_json::from_value::<EventJson<member::MemberEventContent>>( serde_json::from_value::<EventJson<member::MemberEventContent>>(
@ -315,8 +371,7 @@ impl Rooms {
); );
let join_rules = let join_rules =
self.room_state(&room_id)? self.room_state_get(&room_id, &EventType::RoomJoinRules, "")?
.get(&(EventType::RoomJoinRules, "".to_owned()))
.map_or(Ok::<_, Error>(join_rules::JoinRule::Public), |pdu| { .map_or(Ok::<_, Error>(join_rules::JoinRule::Public), |pdu| {
Ok(serde_json::from_value::< Ok(serde_json::from_value::<
EventJson<join_rules::JoinRulesEventContent>, EventJson<join_rules::JoinRulesEventContent>,
@ -446,13 +501,13 @@ impl Rooms {
+ 1; + 1;
let mut unsigned = unsigned.unwrap_or_default(); let mut unsigned = unsigned.unwrap_or_default();
// TODO: Optimize this to not load the whole room state?
if let Some(state_key) = &state_key { if let Some(state_key) = &state_key {
if let Some(prev_pdu) = self if let Some(prev_pdu) = self.room_state_get(&room_id, &event_type, &state_key)? {
.room_state(&room_id)?
.get(&(event_type.clone(), state_key.to_owned()))
{
unsigned.insert("prev_content".to_owned(), prev_pdu.content.clone()); unsigned.insert("prev_content".to_owned(), prev_pdu.content.clone());
unsigned.insert(
"prev_sender".to_owned(),
serde_json::to_value(prev_pdu.sender).expect("UserId::to_value always works"),
);
} }
} }
@ -551,13 +606,18 @@ impl Rooms {
} }
/// Returns an iterator over all PDUs in a room. /// Returns an iterator over all PDUs in a room.
pub fn all_pdus(&self, room_id: &RoomId) -> Result<impl Iterator<Item = Result<PduEvent>>> { pub fn all_pdus(
self.pdus_since(room_id, 0) &self,
user_id: &UserId,
room_id: &RoomId,
) -> Result<impl Iterator<Item = Result<PduEvent>>> {
self.pdus_since(user_id, room_id, 0)
} }
/// Returns an iterator over all events in a room that happened after the event with id `since`. /// Returns an iterator over all events in a room that happened after the event with id `since`.
pub fn pdus_since( pub fn pdus_since(
&self, &self,
user_id: &UserId,
room_id: &RoomId, room_id: &RoomId,
since: u64, since: u64,
) -> Result<impl Iterator<Item = Result<PduEvent>>> { ) -> Result<impl Iterator<Item = Result<PduEvent>>> {
@ -566,12 +626,13 @@ impl Rooms {
pdu_id.push(0xff); pdu_id.push(0xff);
pdu_id.extend_from_slice(&(since).to_be_bytes()); pdu_id.extend_from_slice(&(since).to_be_bytes());
self.pdus_since_pduid(room_id, &pdu_id) self.pdus_since_pduid(user_id, room_id, &pdu_id)
} }
/// Returns an iterator over all events in a room that happened after the event with id `since`. /// Returns an iterator over all events in a room that happened after the event with id `since`.
pub fn pdus_since_pduid( pub fn pdus_since_pduid(
&self, &self,
user_id: &UserId,
room_id: &RoomId, room_id: &RoomId,
pdu_id: &[u8], pdu_id: &[u8],
) -> Result<impl Iterator<Item = Result<PduEvent>>> { ) -> Result<impl Iterator<Item = Result<PduEvent>>> {
@ -579,6 +640,7 @@ impl Rooms {
let mut prefix = room_id.to_string().as_bytes().to_vec(); let mut prefix = room_id.to_string().as_bytes().to_vec();
prefix.push(0xff); prefix.push(0xff);
let user_id = user_id.clone();
Ok(self Ok(self
.pduid_pdu .pduid_pdu
.range(pdu_id..) .range(pdu_id..)
@ -590,9 +652,13 @@ impl Rooms {
}) })
.filter_map(|r| r.ok()) .filter_map(|r| r.ok())
.take_while(move |(k, _)| k.starts_with(&prefix)) .take_while(move |(k, _)| k.starts_with(&prefix))
.map(|(_, v)| { .map(move |(_, v)| {
Ok(serde_json::from_slice(&v) let mut pdu = serde_json::from_slice::<PduEvent>(&v)
.map_err(|_| Error::bad_database("PDU in db is invalid."))?) .map_err(|_| Error::bad_database("PDU in db is invalid."))?;
if pdu.sender != user_id {
pdu.unsigned.remove("transaction_id");
}
Ok(pdu)
})) }))
} }
@ -600,6 +666,7 @@ impl Rooms {
/// `until` in reverse-chronological order. /// `until` in reverse-chronological order.
pub fn pdus_until( pub fn pdus_until(
&self, &self,
user_id: &UserId,
room_id: &RoomId, room_id: &RoomId,
until: u64, until: u64,
) -> impl Iterator<Item = Result<PduEvent>> { ) -> impl Iterator<Item = Result<PduEvent>> {
@ -612,14 +679,19 @@ impl Rooms {
let current: &[u8] = &current; let current: &[u8] = &current;
let user_id = user_id.clone();
self.pduid_pdu self.pduid_pdu
.range(..current) .range(..current)
.rev() .rev()
.filter_map(|r| r.ok()) .filter_map(|r| r.ok())
.take_while(move |(k, _)| k.starts_with(&prefix)) .take_while(move |(k, _)| k.starts_with(&prefix))
.map(|(_, v)| { .map(move |(_, v)| {
Ok(serde_json::from_slice(&v) let mut pdu = serde_json::from_slice::<PduEvent>(&v)
.map_err(|_| Error::bad_database("PDU in db is invalid."))?) .map_err(|_| Error::bad_database("PDU in db is invalid."))?;
if pdu.sender != user_id {
pdu.unsigned.remove("transaction_id");
}
Ok(pdu)
}) })
} }
@ -627,6 +699,7 @@ impl Rooms {
/// `from` in chronological order. /// `from` in chronological order.
pub fn pdus_after( pub fn pdus_after(
&self, &self,
user_id: &UserId,
room_id: &RoomId, room_id: &RoomId,
from: u64, from: u64,
) -> impl Iterator<Item = Result<PduEvent>> { ) -> impl Iterator<Item = Result<PduEvent>> {
@ -639,13 +712,18 @@ impl Rooms {
let current: &[u8] = &current; let current: &[u8] = &current;
let user_id = user_id.clone();
self.pduid_pdu self.pduid_pdu
.range(current..) .range(current..)
.filter_map(|r| r.ok()) .filter_map(|r| r.ok())
.take_while(move |(k, _)| k.starts_with(&prefix)) .take_while(move |(k, _)| k.starts_with(&prefix))
.map(|(_, v)| { .map(move |(_, v)| {
Ok(serde_json::from_slice(&v) let mut pdu = serde_json::from_slice::<PduEvent>(&v)
.map_err(|_| Error::bad_database("PDU in db is invalid."))?) .map_err(|_| Error::bad_database("PDU in db is invalid."))?;
if pdu.sender != user_id {
pdu.unsigned.remove("transaction_id");
}
Ok(pdu)
}) })
} }

View File

@ -1,9 +1,12 @@
use crate::{utils, Error, Result}; use crate::{utils, Error, Result};
use js_int::UInt; use js_int::UInt;
use ruma::{ use ruma::{
api::client::r0::{ api::client::{
device::Device, error::ErrorKind,
keys::{AlgorithmAndDeviceId, DeviceKeys, KeyAlgorithm, OneTimeKey}, r0::{
device::Device,
keys::{AlgorithmAndDeviceId, CrossSigningKey, DeviceKeys, KeyAlgorithm, OneTimeKey},
},
}, },
events::{to_device::AnyToDeviceEvent, EventJson, EventType}, events::{to_device::AnyToDeviceEvent, EventJson, EventType},
identifiers::UserId, identifiers::UserId,
@ -19,8 +22,11 @@ pub struct Users {
pub(super) token_userdeviceid: sled::Tree, pub(super) token_userdeviceid: sled::Tree,
pub(super) onetimekeyid_onetimekeys: sled::Tree, // OneTimeKeyId = UserId + AlgorithmAndDeviceId pub(super) onetimekeyid_onetimekeys: sled::Tree, // OneTimeKeyId = UserId + AlgorithmAndDeviceId
pub(super) userdeviceid_devicekeys: sled::Tree, pub(super) keychangeid_userid: sled::Tree, // KeyChangeId = Count
pub(super) devicekeychangeid_userid: sled::Tree, // DeviceKeyChangeId = Count pub(super) keyid_key: sled::Tree, // KeyId = UserId + KeyId (depends on key type)
pub(super) userid_masterkeyid: sled::Tree,
pub(super) userid_selfsigningkeyid: sled::Tree,
pub(super) userid_usersigningkeyid: sled::Tree,
pub(super) todeviceid_events: sled::Tree, // ToDeviceId = UserId + DeviceId + Count pub(super) todeviceid_events: sled::Tree, // ToDeviceId = UserId + DeviceId + Count
} }
@ -171,9 +177,6 @@ impl Users {
userdeviceid.push(0xff); userdeviceid.push(0xff);
userdeviceid.extend_from_slice(device_id.as_bytes()); userdeviceid.extend_from_slice(device_id.as_bytes());
// Remove device keys
self.userdeviceid_devicekeys.remove(&userdeviceid)?;
// Remove tokens // Remove tokens
if let Some(old_token) = self.userdeviceid_token.remove(&userdeviceid)? { if let Some(old_token) = self.userdeviceid_token.remove(&userdeviceid)? {
self.token_userdeviceid.remove(&old_token)?; self.token_userdeviceid.remove(&old_token)?;
@ -350,38 +353,163 @@ impl Users {
userdeviceid.push(0xff); userdeviceid.push(0xff);
userdeviceid.extend_from_slice(device_id.as_bytes()); userdeviceid.extend_from_slice(device_id.as_bytes());
self.userdeviceid_devicekeys.insert( self.keyid_key.insert(
&userdeviceid, &userdeviceid,
&*serde_json::to_string(&device_keys).expect("DeviceKeys::to_string always works"), &*serde_json::to_string(&device_keys).expect("DeviceKeys::to_string always works"),
)?; )?;
self.devicekeychangeid_userid self.keychangeid_userid
.insert(globals.next_count()?.to_be_bytes(), &*user_id.to_string())?; .insert(globals.next_count()?.to_be_bytes(), &*user_id.to_string())?;
Ok(()) Ok(())
} }
pub fn get_device_keys( pub fn add_cross_signing_keys(
&self, &self,
user_id: &UserId, user_id: &UserId,
device_id: &str, master_key: &CrossSigningKey,
) -> impl Iterator<Item = Result<DeviceKeys>> { self_signing_key: &Option<CrossSigningKey>,
let mut key = user_id.to_string().as_bytes().to_vec(); user_signing_key: &Option<CrossSigningKey>,
key.push(0xff); globals: &super::globals::Globals,
key.extend_from_slice(device_id.as_bytes()); ) -> Result<()> {
// TODO: Check signatures
self.userdeviceid_devicekeys let mut prefix = user_id.to_string().as_bytes().to_vec();
.scan_prefix(key) prefix.push(0xff);
.values()
.map(|bytes| { // Master key
Ok(serde_json::from_slice(&bytes?) let mut master_key_ids = master_key.keys.values();
.map_err(|_| Error::bad_database("DeviceKeys in db are invalid."))?) let master_key_id = master_key_ids.next().ok_or(Error::BadRequest(
}) ErrorKind::InvalidParam,
"Master key contained no key.",
))?;
if master_key_ids.next().is_some() {
return Err(Error::BadRequest(
ErrorKind::InvalidParam,
"Master key contained more than one key.",
));
}
let mut master_key_key = prefix.clone();
master_key_key.extend_from_slice(master_key_id.as_bytes());
self.keyid_key.insert(
&master_key_key,
&*serde_json::to_string(&master_key).expect("CrossSigningKey::to_string always works"),
)?;
self.userid_masterkeyid
.insert(&*user_id.to_string(), master_key_key)?;
// Self-signing key
if let Some(self_signing_key) = self_signing_key {
let mut self_signing_key_ids = self_signing_key.keys.values();
let self_signing_key_id = self_signing_key_ids.next().ok_or(Error::BadRequest(
ErrorKind::InvalidParam,
"Self signing key contained no key.",
))?;
if self_signing_key_ids.next().is_some() {
return Err(Error::BadRequest(
ErrorKind::InvalidParam,
"Self signing key contained more than one key.",
));
}
let mut self_signing_key_key = prefix.clone();
self_signing_key_key.extend_from_slice(self_signing_key_id.as_bytes());
self.keyid_key.insert(
&self_signing_key_key,
&*serde_json::to_string(&self_signing_key)
.expect("CrossSigningKey::to_string always works"),
)?;
self.userid_selfsigningkeyid
.insert(&*user_id.to_string(), self_signing_key_key)?;
}
// User-signing key
if let Some(user_signing_key) = user_signing_key {
let mut user_signing_key_ids = user_signing_key.keys.values();
let user_signing_key_id = user_signing_key_ids.next().ok_or(Error::BadRequest(
ErrorKind::InvalidParam,
"User signing key contained no key.",
))?;
if user_signing_key_ids.next().is_some() {
return Err(Error::BadRequest(
ErrorKind::InvalidParam,
"User signing key contained more than one key.",
));
}
let mut user_signing_key_key = prefix.clone();
user_signing_key_key.extend_from_slice(user_signing_key_id.as_bytes());
self.keyid_key.insert(
&user_signing_key_key,
&*serde_json::to_string(&user_signing_key)
.expect("CrossSigningKey::to_string always works"),
)?;
self.userid_usersigningkeyid
.insert(&*user_id.to_string(), user_signing_key_key)?;
}
self.keychangeid_userid
.insert(globals.next_count()?.to_be_bytes(), &*user_id.to_string())?;
Ok(())
} }
pub fn device_keys_changed(&self, since: u64) -> impl Iterator<Item = Result<UserId>> { pub fn sign_key(
self.devicekeychangeid_userid &self,
.range(since.to_be_bytes()..) target_id: &UserId,
key_id: &str,
signature: (String, String),
sender_id: &UserId,
globals: &super::globals::Globals,
) -> Result<()> {
let mut key = target_id.to_string().as_bytes().to_vec();
key.push(0xff);
key.extend_from_slice(key_id.to_string().as_bytes());
let mut cross_signing_key =
serde_json::from_slice::<serde_json::Value>(&self.keyid_key.get(&key)?.ok_or(
Error::BadRequest(ErrorKind::InvalidParam, "Tried to sign nonexistent key."),
)?)
.map_err(|_| Error::bad_database("key in keyid_key is invalid."))?;
let signatures = cross_signing_key
.get_mut("signatures")
.ok_or_else(|| Error::bad_database("key in keyid_key has no signatures field."))?
.as_object_mut()
.ok_or_else(|| Error::bad_database("key in keyid_key has invalid signatures field."))?
.entry(sender_id.clone())
.or_insert_with(|| serde_json::Map::new().into());
signatures
.as_object_mut()
.ok_or_else(|| Error::bad_database("signatures in keyid_key for a user is invalid."))?
.insert(signature.0, signature.1.into());
self.keyid_key.insert(
&key,
&*serde_json::to_string(&cross_signing_key)
.expect("CrossSigningKey::to_string always works"),
)?;
self.keychangeid_userid
.insert(globals.next_count()?.to_be_bytes(), &*target_id.to_string())?;
Ok(())
}
pub fn keys_changed(&self, since: u64) -> impl Iterator<Item = Result<UserId>> {
self.keychangeid_userid
.range((since + 1).to_be_bytes()..)
.values() .values()
.map(|bytes| { .map(|bytes| {
Ok( Ok(
@ -397,29 +525,85 @@ impl Users {
}) })
} }
pub fn all_device_keys( pub fn get_device_keys(&self, user_id: &UserId, device_id: &str) -> Result<Option<DeviceKeys>> {
&self,
user_id: &UserId,
) -> impl Iterator<Item = Result<(String, DeviceKeys)>> {
let mut key = user_id.to_string().as_bytes().to_vec(); let mut key = user_id.to_string().as_bytes().to_vec();
key.push(0xff); key.push(0xff);
key.extend_from_slice(device_id.as_bytes());
self.userdeviceid_devicekeys.scan_prefix(key).map(|r| { self.keyid_key.get(key)?.map_or(Ok(None), |bytes| {
let (key, value) = r?; Ok(Some(serde_json::from_slice(&bytes).map_err(|_| {
let userdeviceid = utils::string_from_bytes( Error::bad_database("DeviceKeys in db are invalid.")
key.rsplit(|&b| b == 0xff) })?))
.next()
.ok_or_else(|| Error::bad_database("UserDeviceID in db is invalid."))?,
)
.map_err(|_| Error::bad_database("UserDeviceId in db is invalid."))?;
Ok((
userdeviceid,
serde_json::from_slice(&*value)
.map_err(|_| Error::bad_database("DeviceKeys in db are invalid."))?,
))
}) })
} }
pub fn get_master_key(
&self,
user_id: &UserId,
sender_id: &UserId,
) -> Result<Option<CrossSigningKey>> {
// TODO: hide some signatures
self.userid_masterkeyid
.get(user_id.to_string())?
.map_or(Ok(None), |key| {
self.keyid_key.get(key)?.map_or(Ok(None), |bytes| {
let mut cross_signing_key = serde_json::from_slice::<CrossSigningKey>(&bytes)
.map_err(|_| {
Error::bad_database("CrossSigningKey in db is invalid.")
})?;
// A user is not allowed to see signatures from users other than himself and
// the target user
cross_signing_key.signatures = cross_signing_key
.signatures
.into_iter()
.filter(|(user, _)| user == user_id || user == sender_id)
.collect();
Ok(Some(cross_signing_key))
})
})
}
pub fn get_self_signing_key(
&self,
user_id: &UserId,
sender_id: &UserId,
) -> Result<Option<CrossSigningKey>> {
self.userid_selfsigningkeyid
.get(user_id.to_string())?
.map_or(Ok(None), |key| {
self.keyid_key.get(key)?.map_or(Ok(None), |bytes| {
let mut cross_signing_key = serde_json::from_slice::<CrossSigningKey>(&bytes)
.map_err(|_| {
Error::bad_database("CrossSigningKey in db is invalid.")
})?;
// A user is not allowed to see signatures from users other than himself and
// the target user
cross_signing_key.signatures = cross_signing_key
.signatures
.into_iter()
.filter(|(user, _)| user == user_id || user == sender_id)
.collect();
Ok(Some(cross_signing_key))
})
})
}
pub fn get_user_signing_key(&self, user_id: &UserId) -> Result<Option<CrossSigningKey>> {
self.userid_usersigningkeyid
.get(user_id.to_string())?
.map_or(Ok(None), |key| {
self.keyid_key.get(key)?.map_or(Ok(None), |bytes| {
Ok(Some(serde_json::from_slice(&bytes).map_err(|_| {
Error::bad_database("CrossSigningKey in db is invalid.")
})?))
})
})
}
pub fn add_to_device_event( pub fn add_to_device_event(
&self, &self,
sender: &UserId, sender: &UserId,

View File

@ -1,6 +1,8 @@
#![feature(proc_macro_hygiene, decl_macro)] #![feature(proc_macro_hygiene, decl_macro)]
#![warn(rust_2018_idioms)] #![warn(rust_2018_idioms)]
pub mod push_rules;
mod client_server; mod client_server;
mod database; mod database;
mod error; mod error;
@ -44,6 +46,12 @@ fn setup_rocket() -> rocket::Rocket {
client_server::upload_keys_route, client_server::upload_keys_route,
client_server::get_keys_route, client_server::get_keys_route,
client_server::claim_keys_route, client_server::claim_keys_route,
client_server::create_backup_route,
client_server::update_backup_route,
client_server::get_latest_backup_route,
client_server::get_backup_route,
client_server::add_backup_keys_route,
client_server::get_backup_keys_route,
client_server::set_read_marker_route, client_server::set_read_marker_route,
client_server::create_typing_event_route, client_server::create_typing_event_route,
client_server::create_room_route, client_server::create_room_route,
@ -88,6 +96,10 @@ fn setup_rocket() -> rocket::Rocket {
client_server::delete_device_route, client_server::delete_device_route,
client_server::delete_devices_route, client_server::delete_devices_route,
client_server::options_route, client_server::options_route,
client_server::upload_signing_keys_route,
client_server::upload_signatures_route,
client_server::pushers_route,
client_server::set_pushers_route,
//server_server::well_known_server, //server_server::well_known_server,
//server_server::get_server_version, //server_server::get_server_version,
//server_server::get_server_keys, //server_server::get_server_keys,

View File

@ -4,6 +4,7 @@ use ruma::{
api::federation::EventHash, api::federation::EventHash,
events::{ events::{
collections::all::{RoomEvent, StateEvent}, collections::all::{RoomEvent, StateEvent},
room::member::MemberEvent,
stripped::AnyStrippedStateEvent, stripped::AnyStrippedStateEvent,
EventJson, EventType, EventJson, EventType,
}, },
@ -95,4 +96,9 @@ impl PduEvent {
serde_json::from_str::<EventJson<AnyStrippedStateEvent>>(&json) serde_json::from_str::<EventJson<AnyStrippedStateEvent>>(&json)
.expect("EventJson::from_str always works") .expect("EventJson::from_str always works")
} }
pub fn to_member_event(&self) -> EventJson<MemberEvent> {
let json = serde_json::to_string(&self).expect("PDUs are always valid");
serde_json::from_str::<EventJson<MemberEvent>>(&json)
.expect("EventJson::from_str always works")
}
} }

230
src/push_rules.rs Normal file
View File

@ -0,0 +1,230 @@
use ruma::{
events::push_rules::{ConditionalPushRule, PatternedPushRule, PushCondition, Ruleset},
identifiers::UserId,
push::{Action, Tweak},
};
pub fn default_pushrules(user_id: &UserId) -> Ruleset {
Ruleset {
content: vec![contains_user_name_rule(&user_id)],
override_: vec![
master_rule(),
suppress_notices_rule(),
invite_for_me_rule(),
member_event_rule(),
contains_display_name_rule(),
tombstone_rule(),
roomnotif_rule(),
],
room: vec![],
sender: vec![],
underride: vec![
call_rule(),
encrypted_room_one_to_one_rule(),
room_one_to_one_rule(),
message_rule(),
encrypted_rule(),
],
}
}
pub fn master_rule() -> ConditionalPushRule {
ConditionalPushRule {
actions: vec![Action::DontNotify],
default: true,
enabled: false,
rule_id: ".m.rule.master".to_owned(),
conditions: vec![],
}
}
pub fn suppress_notices_rule() -> ConditionalPushRule {
ConditionalPushRule {
actions: vec![Action::DontNotify],
default: true,
enabled: true,
rule_id: ".m.rule.suppress_notices".to_owned(),
conditions: vec![PushCondition::EventMatch {
key: "content.msgtype".to_owned(),
pattern: "m.notice".to_owned(),
}],
}
}
pub fn invite_for_me_rule() -> ConditionalPushRule {
ConditionalPushRule {
actions: vec![
Action::Notify,
Action::SetTweak(Tweak::Sound("default".to_owned())),
Action::SetTweak(Tweak::Highlight(false)),
],
default: true,
enabled: true,
rule_id: ".m.rule.invite_for_me".to_owned(),
conditions: vec![PushCondition::EventMatch {
key: "content.membership".to_owned(),
pattern: "m.invite".to_owned(),
}],
}
}
pub fn member_event_rule() -> ConditionalPushRule {
ConditionalPushRule {
actions: vec![Action::DontNotify],
default: true,
enabled: true,
rule_id: ".m.rule.member_event".to_owned(),
conditions: vec![PushCondition::EventMatch {
key: "content.membership".to_owned(),
pattern: "type".to_owned(),
}],
}
}
pub fn contains_display_name_rule() -> ConditionalPushRule {
ConditionalPushRule {
actions: vec![
Action::Notify,
Action::SetTweak(Tweak::Sound("default".to_owned())),
Action::SetTweak(Tweak::Highlight(true)),
],
default: true,
enabled: true,
rule_id: ".m.rule.contains_display_name".to_owned(),
conditions: vec![PushCondition::ContainsDisplayName],
}
}
pub fn tombstone_rule() -> ConditionalPushRule {
ConditionalPushRule {
actions: vec![Action::Notify, Action::SetTweak(Tweak::Highlight(true))],
default: true,
enabled: true,
rule_id: ".m.rule.tombstone".to_owned(),
conditions: vec![
PushCondition::EventMatch {
key: "type".to_owned(),
pattern: "m.room.tombstone".to_owned(),
},
PushCondition::EventMatch {
key: "state_key".to_owned(),
pattern: "".to_owned(),
},
],
}
}
pub fn roomnotif_rule() -> ConditionalPushRule {
ConditionalPushRule {
actions: vec![Action::Notify, Action::SetTweak(Tweak::Highlight(true))],
default: true,
enabled: true,
rule_id: ".m.rule.roomnotif".to_owned(),
conditions: vec![
PushCondition::EventMatch {
key: "content.body".to_owned(),
pattern: "@room".to_owned(),
},
PushCondition::SenderNotificationPermission {
key: "room".to_owned(),
},
],
}
}
pub fn contains_user_name_rule(user_id: &UserId) -> PatternedPushRule {
PatternedPushRule {
actions: vec![
Action::Notify,
Action::SetTweak(Tweak::Sound("default".to_owned())),
Action::SetTweak(Tweak::Highlight(true)),
],
default: true,
enabled: true,
rule_id: ".m.rule.contains_user_name".to_owned(),
pattern: user_id.localpart().to_owned(),
}
}
pub fn call_rule() -> ConditionalPushRule {
ConditionalPushRule {
actions: vec![
Action::Notify,
Action::SetTweak(Tweak::Sound("ring".to_owned())),
Action::SetTweak(Tweak::Highlight(false)),
],
default: true,
enabled: true,
rule_id: ".m.rule.call".to_owned(),
conditions: vec![PushCondition::EventMatch {
key: "type".to_owned(),
pattern: "m.call.invite".to_owned(),
}],
}
}
pub fn encrypted_room_one_to_one_rule() -> ConditionalPushRule {
ConditionalPushRule {
actions: vec![
Action::Notify,
Action::SetTweak(Tweak::Sound("default".to_owned())),
Action::SetTweak(Tweak::Highlight(false)),
],
default: true,
enabled: true,
rule_id: ".m.rule.encrypted_room_one_to_one".to_owned(),
conditions: vec![
PushCondition::RoomMemberCount { is: "2".to_owned() },
PushCondition::EventMatch {
key: "type".to_owned(),
pattern: "m.room.encrypted".to_owned(),
},
],
}
}
pub fn room_one_to_one_rule() -> ConditionalPushRule {
ConditionalPushRule {
actions: vec![
Action::Notify,
Action::SetTweak(Tweak::Sound("default".to_owned())),
Action::SetTweak(Tweak::Highlight(false)),
],
default: true,
enabled: true,
rule_id: ".m.rule.room_one_to_one".to_owned(),
conditions: vec![
PushCondition::RoomMemberCount { is: "2".to_owned() },
PushCondition::EventMatch {
key: "type".to_owned(),
pattern: "m.room.message".to_owned(),
},
],
}
}
pub fn message_rule() -> ConditionalPushRule {
ConditionalPushRule {
actions: vec![Action::Notify, Action::SetTweak(Tweak::Highlight(false))],
default: true,
enabled: true,
rule_id: ".m.rule.message".to_owned(),
conditions: vec![PushCondition::EventMatch {
key: "type".to_owned(),
pattern: "m.room.message".to_owned(),
}],
}
}
pub fn encrypted_rule() -> ConditionalPushRule {
ConditionalPushRule {
actions: vec![Action::Notify, Action::SetTweak(Tweak::Highlight(false))],
default: true,
enabled: true,
rule_id: ".m.rule.encrypted".to_owned(),
conditions: vec![PushCondition::EventMatch {
key: "type".to_owned(),
pattern: "m.room.encrypted".to_owned(),
}],
}
}

View File

@ -1,4 +1,3 @@
# Register endpoints implemented
GET /register yields a set of flows GET /register yields a set of flows
POST /register can create a user POST /register can create a user
POST /register downcases capitals in usernames POST /register downcases capitals in usernames
@ -17,14 +16,12 @@ POST /register rejects registration of usernames with '£'
POST /register rejects registration of usernames with 'é' POST /register rejects registration of usernames with 'é'
POST /register rejects registration of usernames with '\n' POST /register rejects registration of usernames with '\n'
POST /register rejects registration of usernames with ''' POST /register rejects registration of usernames with '''
# Login endpoints implemented
GET /login yields a set of flows GET /login yields a set of flows
POST /login can log in as a user POST /login can log in as a user
POST /login returns the same device_id as that in the request POST /login returns the same device_id as that in the request
POST /login can log in as a user with just the local part of the id POST /login can log in as a user with just the local part of the id
POST /login as non-existing user is rejected POST /login as non-existing user is rejected
POST /login wrong password is rejected POST /login wrong password is rejected
# Room creation endpoints implemented
POST /createRoom makes a private room POST /createRoom makes a private room
POST /createRoom makes a private room with invites POST /createRoom makes a private room with invites
GET /rooms/:room_id/state/m.room.member/:user_id fetches my membership GET /rooms/:room_id/state/m.room.member/:user_id fetches my membership
@ -49,15 +46,6 @@ Can read configuration endpoint
AS cannot create users outside its own namespace AS cannot create users outside its own namespace
Changing the actions of an unknown default rule fails with 404 Changing the actions of an unknown default rule fails with 404
Changing the actions of an unknown rule fails with 404 Changing the actions of an unknown rule fails with 404
Trying to add push rule with invalid scope fails with 400
Trying to add push rule with invalid template fails with 400
Trying to add push rule with rule_id with slashes fails with 400
Trying to add push rule with override rule without conditions fails with 400
Trying to add push rule with underride rule without conditions fails with 400
Trying to add push rule with condition without kind fails with 400
Trying to add push rule with content rule without pattern fails with 400
Trying to add push rule with no actions fails with 400
Trying to add push rule with invalid action fails with 400
Trying to get push rules with unknown rule_id fails with 404 Trying to get push rules with unknown rule_id fails with 404
GET /events with non-numeric 'limit' GET /events with non-numeric 'limit'
GET /events with negative 'limit' GET /events with negative 'limit'