improvement: federation get_keys and optimize signingkey storage

- get encryption keys over federation
- optimize signing key storage
- rate limit parsing of bad events
- rate limit signature fetching
- dependency bumps
next
Timo Kösters 2021-05-20 23:46:52 +02:00
parent ae41bc5067
commit 09157b2096
No known key found for this signature in database
GPG Key ID: 24DA7517711A2BA4
18 changed files with 566 additions and 371 deletions

203
Cargo.lock generated
View File

@ -316,9 +316,9 @@ dependencies = [
[[package]] [[package]]
name = "derive_more" name = "derive_more"
version = "0.99.13" version = "0.99.14"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f82b1b72f1263f214c0f823371768776c4f5841b942c9883aa8e5ec584fd0ba6" checksum = "5cc7b9cef1e351660e5443924e4f43ab25fbbed3e9a5f052df3677deb4d6b320"
dependencies = [ dependencies = [
"convert_case", "convert_case",
"proc-macro2", "proc-macro2",
@ -470,9 +470,9 @@ dependencies = [
[[package]] [[package]]
name = "futures" name = "futures"
version = "0.3.14" version = "0.3.15"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a9d5813545e459ad3ca1bff9915e9ad7f1a47dc6a91b627ce321d5863b7dd253" checksum = "0e7e43a803dae2fa37c1f6a8fe121e1f7bf9548b4dfc0522a42f34145dadfc27"
dependencies = [ dependencies = [
"futures-channel", "futures-channel",
"futures-core", "futures-core",
@ -485,9 +485,9 @@ dependencies = [
[[package]] [[package]]
name = "futures-channel" name = "futures-channel"
version = "0.3.14" version = "0.3.15"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ce79c6a52a299137a6013061e0cf0e688fce5d7f1bc60125f520912fdb29ec25" checksum = "e682a68b29a882df0545c143dc3646daefe80ba479bcdede94d5a703de2871e2"
dependencies = [ dependencies = [
"futures-core", "futures-core",
"futures-sink", "futures-sink",
@ -495,15 +495,15 @@ dependencies = [
[[package]] [[package]]
name = "futures-core" name = "futures-core"
version = "0.3.14" version = "0.3.15"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "098cd1c6dda6ca01650f1a37a794245eb73181d0d4d4e955e2f3c37db7af1815" checksum = "0402f765d8a89a26043b889b26ce3c4679d268fa6bb22cd7c6aad98340e179d1"
[[package]] [[package]]
name = "futures-executor" name = "futures-executor"
version = "0.3.14" version = "0.3.15"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "10f6cb7042eda00f0049b1d2080aa4b93442997ee507eb3828e8bd7577f94c9d" checksum = "badaa6a909fac9e7236d0620a2f57f7664640c56575b71a7552fbd68deafab79"
dependencies = [ dependencies = [
"futures-core", "futures-core",
"futures-task", "futures-task",
@ -512,16 +512,17 @@ dependencies = [
[[package]] [[package]]
name = "futures-io" name = "futures-io"
version = "0.3.14" version = "0.3.15"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "365a1a1fb30ea1c03a830fdb2158f5236833ac81fa0ad12fe35b29cddc35cb04" checksum = "acc499defb3b348f8d8f3f66415835a9131856ff7714bf10dadfc4ec4bdb29a1"
[[package]] [[package]]
name = "futures-macro" name = "futures-macro"
version = "0.3.14" version = "0.3.15"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "668c6733a182cd7deb4f1de7ba3bf2120823835b3bcfbeacf7d2c4a773c1bb8b" checksum = "a4c40298486cdf52cc00cd6d6987892ba502c7656a16a4192a9992b1ccedd121"
dependencies = [ dependencies = [
"autocfg",
"proc-macro-hack", "proc-macro-hack",
"proc-macro2", "proc-macro2",
"quote", "quote",
@ -530,22 +531,23 @@ dependencies = [
[[package]] [[package]]
name = "futures-sink" name = "futures-sink"
version = "0.3.14" version = "0.3.15"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c5629433c555de3d82861a7a4e3794a4c40040390907cfbfd7143a92a426c23" checksum = "a57bead0ceff0d6dde8f465ecd96c9338121bb7717d3e7b108059531870c4282"
[[package]] [[package]]
name = "futures-task" name = "futures-task"
version = "0.3.14" version = "0.3.15"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ba7aa51095076f3ba6d9a1f702f74bd05ec65f555d70d2033d55ba8d69f581bc" checksum = "8a16bef9fc1a4dddb5bee51c989e3fbba26569cbb0e31f5b303c184e3dd33dae"
[[package]] [[package]]
name = "futures-util" name = "futures-util"
version = "0.3.14" version = "0.3.15"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3c144ad54d60f23927f0a6b6d816e4271278b64f005ad65e4e35291d2de9c025" checksum = "feb5c238d27e2bf94ffdfd27b2c29e3df4a68c4193bb6427384259e2bf191967"
dependencies = [ dependencies = [
"autocfg",
"futures-channel", "futures-channel",
"futures-core", "futures-core",
"futures-io", "futures-io",
@ -676,9 +678,9 @@ dependencies = [
[[package]] [[package]]
name = "http-body" name = "http-body"
version = "0.4.1" version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5dfb77c123b4e2f72a2069aeae0b4b4949cc7e966df277813fc16347e7549737" checksum = "60daa14be0e0786db0f03a9e57cb404c9d756eed2b6c62b9ea98ec5743ec75a9"
dependencies = [ dependencies = [
"bytes", "bytes",
"http", "http",
@ -687,9 +689,9 @@ dependencies = [
[[package]] [[package]]
name = "httparse" name = "httparse"
version = "1.4.0" version = "1.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4a1ce40d6fc9764887c2fdc7305c3dcc429ba11ff981c1509416afd5697e4437" checksum = "f3a87b616e37e93c22fb19bcd386f02f3af5ea98a25670ad0fce773de23c5e68"
[[package]] [[package]]
name = "httpdate" name = "httpdate"
@ -784,6 +786,15 @@ dependencies = [
"serde", "serde",
] ]
[[package]]
name = "indoc"
version = "1.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e5a75aeaaef0ce18b58056d306c27b07436fbb34b8816c53094b76dd81803136"
dependencies = [
"unindent",
]
[[package]] [[package]]
name = "inlinable_string" name = "inlinable_string"
version = "0.1.14" version = "0.1.14"
@ -864,9 +875,9 @@ checksum = "229d53d58899083193af11e15917b5640cd40b29ff475a1fe4ef725deb02d0f2"
[[package]] [[package]]
name = "js-sys" name = "js-sys"
version = "0.3.50" version = "0.3.51"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2d99f9e3e84b8f67f846ef5b4cbbc3b1c29f6c759fcbce6f01aa0e73d932a24c" checksum = "83bdfbace3a0e81a4253f73b49e960b053e396a11012cbd49b9b74d6a2b67062"
dependencies = [ dependencies = [
"wasm-bindgen", "wasm-bindgen",
] ]
@ -1129,9 +1140,9 @@ checksum = "af8b08b04175473088b46763e51ee54da5f9a164bc162f615b91bc179dbf15a3"
[[package]] [[package]]
name = "openssl-probe" name = "openssl-probe"
version = "0.1.2" version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "77af24da69f9d9341038eba93a073b1fdaaa1b788221b00a69bce9e762cb32de" checksum = "28988d872ab76095a6e6ac88d99b54fd267702734fd7ffe610ca27f533ddb95a"
[[package]] [[package]]
name = "opentelemetry" name = "opentelemetry"
@ -1614,8 +1625,8 @@ dependencies = [
[[package]] [[package]]
name = "ruma" name = "ruma"
version = "0.0.3" version = "0.1.1"
source = "git+https://github.com/ruma/ruma?rev=71686ce8a4d1770a80de216080718fe9de7bd925#71686ce8a4d1770a80de216080718fe9de7bd925" source = "git+https://github.com/ruma/ruma?rev=a238a0dda5b06fad146f8f01d690cbe011d13245#a238a0dda5b06fad146f8f01d690cbe011d13245"
dependencies = [ dependencies = [
"assign", "assign",
"js_int", "js_int",
@ -1635,8 +1646,8 @@ dependencies = [
[[package]] [[package]]
name = "ruma-api" name = "ruma-api"
version = "0.17.0-alpha.4" version = "0.17.0"
source = "git+https://github.com/ruma/ruma?rev=71686ce8a4d1770a80de216080718fe9de7bd925#71686ce8a4d1770a80de216080718fe9de7bd925" source = "git+https://github.com/ruma/ruma?rev=a238a0dda5b06fad146f8f01d690cbe011d13245#a238a0dda5b06fad146f8f01d690cbe011d13245"
dependencies = [ dependencies = [
"bytes", "bytes",
"http", "http",
@ -1651,8 +1662,8 @@ dependencies = [
[[package]] [[package]]
name = "ruma-api-macros" name = "ruma-api-macros"
version = "0.17.0-alpha.4" version = "0.17.0"
source = "git+https://github.com/ruma/ruma?rev=71686ce8a4d1770a80de216080718fe9de7bd925#71686ce8a4d1770a80de216080718fe9de7bd925" source = "git+https://github.com/ruma/ruma?rev=a238a0dda5b06fad146f8f01d690cbe011d13245#a238a0dda5b06fad146f8f01d690cbe011d13245"
dependencies = [ dependencies = [
"proc-macro-crate", "proc-macro-crate",
"proc-macro2", "proc-macro2",
@ -1662,8 +1673,8 @@ dependencies = [
[[package]] [[package]]
name = "ruma-appservice-api" name = "ruma-appservice-api"
version = "0.2.0-alpha.3" version = "0.2.0"
source = "git+https://github.com/ruma/ruma?rev=71686ce8a4d1770a80de216080718fe9de7bd925#71686ce8a4d1770a80de216080718fe9de7bd925" source = "git+https://github.com/ruma/ruma?rev=a238a0dda5b06fad146f8f01d690cbe011d13245#a238a0dda5b06fad146f8f01d690cbe011d13245"
dependencies = [ dependencies = [
"ruma-api", "ruma-api",
"ruma-common", "ruma-common",
@ -1676,8 +1687,8 @@ dependencies = [
[[package]] [[package]]
name = "ruma-client-api" name = "ruma-client-api"
version = "0.10.0-alpha.3" version = "0.10.1"
source = "git+https://github.com/ruma/ruma?rev=71686ce8a4d1770a80de216080718fe9de7bd925#71686ce8a4d1770a80de216080718fe9de7bd925" source = "git+https://github.com/ruma/ruma?rev=a238a0dda5b06fad146f8f01d690cbe011d13245#a238a0dda5b06fad146f8f01d690cbe011d13245"
dependencies = [ dependencies = [
"assign", "assign",
"bytes", "bytes",
@ -1696,8 +1707,8 @@ dependencies = [
[[package]] [[package]]
name = "ruma-common" name = "ruma-common"
version = "0.5.0" version = "0.5.1"
source = "git+https://github.com/ruma/ruma?rev=71686ce8a4d1770a80de216080718fe9de7bd925#71686ce8a4d1770a80de216080718fe9de7bd925" source = "git+https://github.com/ruma/ruma?rev=a238a0dda5b06fad146f8f01d690cbe011d13245#a238a0dda5b06fad146f8f01d690cbe011d13245"
dependencies = [ dependencies = [
"indexmap", "indexmap",
"js_int", "js_int",
@ -1711,9 +1722,10 @@ dependencies = [
[[package]] [[package]]
name = "ruma-events" name = "ruma-events"
version = "0.22.0-alpha.3" version = "0.22.2"
source = "git+https://github.com/ruma/ruma?rev=71686ce8a4d1770a80de216080718fe9de7bd925#71686ce8a4d1770a80de216080718fe9de7bd925" source = "git+https://github.com/ruma/ruma?rev=a238a0dda5b06fad146f8f01d690cbe011d13245#a238a0dda5b06fad146f8f01d690cbe011d13245"
dependencies = [ dependencies = [
"indoc",
"js_int", "js_int",
"ruma-common", "ruma-common",
"ruma-events-macros", "ruma-events-macros",
@ -1725,8 +1737,8 @@ dependencies = [
[[package]] [[package]]
name = "ruma-events-macros" name = "ruma-events-macros"
version = "0.22.0-alpha.3" version = "0.22.2"
source = "git+https://github.com/ruma/ruma?rev=71686ce8a4d1770a80de216080718fe9de7bd925#71686ce8a4d1770a80de216080718fe9de7bd925" source = "git+https://github.com/ruma/ruma?rev=a238a0dda5b06fad146f8f01d690cbe011d13245#a238a0dda5b06fad146f8f01d690cbe011d13245"
dependencies = [ dependencies = [
"proc-macro-crate", "proc-macro-crate",
"proc-macro2", "proc-macro2",
@ -1736,8 +1748,8 @@ dependencies = [
[[package]] [[package]]
name = "ruma-federation-api" name = "ruma-federation-api"
version = "0.1.0-alpha.2" version = "0.1.0"
source = "git+https://github.com/ruma/ruma?rev=71686ce8a4d1770a80de216080718fe9de7bd925#71686ce8a4d1770a80de216080718fe9de7bd925" source = "git+https://github.com/ruma/ruma?rev=a238a0dda5b06fad146f8f01d690cbe011d13245#a238a0dda5b06fad146f8f01d690cbe011d13245"
dependencies = [ dependencies = [
"js_int", "js_int",
"ruma-api", "ruma-api",
@ -1751,8 +1763,8 @@ dependencies = [
[[package]] [[package]]
name = "ruma-identifiers" name = "ruma-identifiers"
version = "0.19.0" version = "0.19.1"
source = "git+https://github.com/ruma/ruma?rev=71686ce8a4d1770a80de216080718fe9de7bd925#71686ce8a4d1770a80de216080718fe9de7bd925" source = "git+https://github.com/ruma/ruma?rev=a238a0dda5b06fad146f8f01d690cbe011d13245#a238a0dda5b06fad146f8f01d690cbe011d13245"
dependencies = [ dependencies = [
"paste", "paste",
"rand", "rand",
@ -1765,8 +1777,8 @@ dependencies = [
[[package]] [[package]]
name = "ruma-identifiers-macros" name = "ruma-identifiers-macros"
version = "0.19.0" version = "0.19.1"
source = "git+https://github.com/ruma/ruma?rev=71686ce8a4d1770a80de216080718fe9de7bd925#71686ce8a4d1770a80de216080718fe9de7bd925" source = "git+https://github.com/ruma/ruma?rev=a238a0dda5b06fad146f8f01d690cbe011d13245#a238a0dda5b06fad146f8f01d690cbe011d13245"
dependencies = [ dependencies = [
"quote", "quote",
"ruma-identifiers-validation", "ruma-identifiers-validation",
@ -1776,12 +1788,12 @@ dependencies = [
[[package]] [[package]]
name = "ruma-identifiers-validation" name = "ruma-identifiers-validation"
version = "0.3.0" version = "0.3.0"
source = "git+https://github.com/ruma/ruma?rev=71686ce8a4d1770a80de216080718fe9de7bd925#71686ce8a4d1770a80de216080718fe9de7bd925" source = "git+https://github.com/ruma/ruma?rev=a238a0dda5b06fad146f8f01d690cbe011d13245#a238a0dda5b06fad146f8f01d690cbe011d13245"
[[package]] [[package]]
name = "ruma-identity-service-api" name = "ruma-identity-service-api"
version = "0.1.0-alpha.1" version = "0.1.0"
source = "git+https://github.com/ruma/ruma?rev=71686ce8a4d1770a80de216080718fe9de7bd925#71686ce8a4d1770a80de216080718fe9de7bd925" source = "git+https://github.com/ruma/ruma?rev=a238a0dda5b06fad146f8f01d690cbe011d13245#a238a0dda5b06fad146f8f01d690cbe011d13245"
dependencies = [ dependencies = [
"js_int", "js_int",
"ruma-api", "ruma-api",
@ -1793,8 +1805,8 @@ dependencies = [
[[package]] [[package]]
name = "ruma-push-gateway-api" name = "ruma-push-gateway-api"
version = "0.1.0-alpha.1" version = "0.1.0"
source = "git+https://github.com/ruma/ruma?rev=71686ce8a4d1770a80de216080718fe9de7bd925#71686ce8a4d1770a80de216080718fe9de7bd925" source = "git+https://github.com/ruma/ruma?rev=a238a0dda5b06fad146f8f01d690cbe011d13245#a238a0dda5b06fad146f8f01d690cbe011d13245"
dependencies = [ dependencies = [
"js_int", "js_int",
"ruma-api", "ruma-api",
@ -1808,8 +1820,8 @@ dependencies = [
[[package]] [[package]]
name = "ruma-serde" name = "ruma-serde"
version = "0.3.1" version = "0.4.0"
source = "git+https://github.com/ruma/ruma?rev=71686ce8a4d1770a80de216080718fe9de7bd925#71686ce8a4d1770a80de216080718fe9de7bd925" source = "git+https://github.com/ruma/ruma?rev=a238a0dda5b06fad146f8f01d690cbe011d13245#a238a0dda5b06fad146f8f01d690cbe011d13245"
dependencies = [ dependencies = [
"bytes", "bytes",
"form_urlencoded", "form_urlencoded",
@ -1822,8 +1834,8 @@ dependencies = [
[[package]] [[package]]
name = "ruma-serde-macros" name = "ruma-serde-macros"
version = "0.3.1" version = "0.4.0"
source = "git+https://github.com/ruma/ruma?rev=71686ce8a4d1770a80de216080718fe9de7bd925#71686ce8a4d1770a80de216080718fe9de7bd925" source = "git+https://github.com/ruma/ruma?rev=a238a0dda5b06fad146f8f01d690cbe011d13245#a238a0dda5b06fad146f8f01d690cbe011d13245"
dependencies = [ dependencies = [
"proc-macro-crate", "proc-macro-crate",
"proc-macro2", "proc-macro2",
@ -1833,8 +1845,8 @@ dependencies = [
[[package]] [[package]]
name = "ruma-signatures" name = "ruma-signatures"
version = "0.7.0" version = "0.7.1"
source = "git+https://github.com/ruma/ruma?rev=71686ce8a4d1770a80de216080718fe9de7bd925#71686ce8a4d1770a80de216080718fe9de7bd925" source = "git+https://github.com/ruma/ruma?rev=a238a0dda5b06fad146f8f01d690cbe011d13245#a238a0dda5b06fad146f8f01d690cbe011d13245"
dependencies = [ dependencies = [
"base64 0.13.0", "base64 0.13.0",
"ring", "ring",
@ -1847,11 +1859,12 @@ dependencies = [
[[package]] [[package]]
name = "ruma-state-res" name = "ruma-state-res"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/ruma/ruma?rev=71686ce8a4d1770a80de216080718fe9de7bd925#71686ce8a4d1770a80de216080718fe9de7bd925" source = "git+https://github.com/ruma/ruma?rev=a238a0dda5b06fad146f8f01d690cbe011d13245#a238a0dda5b06fad146f8f01d690cbe011d13245"
dependencies = [ dependencies = [
"itertools 0.10.0", "itertools 0.10.0",
"js_int", "js_int",
"maplit", "maplit",
"ruma-common",
"ruma-events", "ruma-events",
"ruma-identifiers", "ruma-identifiers",
"ruma-serde", "ruma-serde",
@ -1910,9 +1923,9 @@ dependencies = [
[[package]] [[package]]
name = "rustversion" name = "rustversion"
version = "1.0.4" version = "1.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cb5d2a036dc6d2d8fd16fde3498b04306e29bd193bf306a57427019b823d5acd" checksum = "61b3909d758bb75c79f23d4736fac9433868679d3ad2ea7a61e3c25cfda9a088"
[[package]] [[package]]
name = "ryu" name = "ryu"
@ -1992,18 +2005,18 @@ checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
[[package]] [[package]]
name = "serde" name = "serde"
version = "1.0.125" version = "1.0.126"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "558dc50e1a5a5fa7112ca2ce4effcb321b0300c0d4ccf0776a9f60cd89031171" checksum = "ec7505abeacaec74ae4778d9d9328fe5a5d04253220a85c4ee022239fc996d03"
dependencies = [ dependencies = [
"serde_derive", "serde_derive",
] ]
[[package]] [[package]]
name = "serde_derive" name = "serde_derive"
version = "1.0.125" version = "1.0.126"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b093b7a2bb58203b5da3056c05b4ec1fed827dcfdb37347a8841695263b3d06d" checksum = "963a7dbc9895aeac7ac90e74f34a5d5261828f79df35cbed41e10189d3804d43"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@ -2361,9 +2374,9 @@ checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c"
[[package]] [[package]]
name = "tokio" name = "tokio"
version = "1.5.0" version = "1.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "83f0c8e7c0addab50b663055baf787d0af7f413a46e6e7fb9559a4e4db7137a5" checksum = "bd3076b5c8cc18138b8f8814895c11eb4de37114a5d127bafdc5e55798ceef37"
dependencies = [ dependencies = [
"autocfg", "autocfg",
"bytes", "bytes",
@ -2380,9 +2393,9 @@ dependencies = [
[[package]] [[package]]
name = "tokio-macros" name = "tokio-macros"
version = "1.1.0" version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "caf7b11a536f46a809a8a9f0bb4237020f70ecbf115b842360afb127ea2fda57" checksum = "c49e3df43841dafb86046472506755d8501c5615673955f6aa17181125d13c37"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@ -2402,9 +2415,9 @@ dependencies = [
[[package]] [[package]]
name = "tokio-util" name = "tokio-util"
version = "0.6.6" version = "0.6.7"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "940a12c99365c31ea8dd9ba04ec1be183ffe4920102bb7122c2f515437601e8e" checksum = "1caa0b0c8d94a049db56b5acf8cba99dc0623aab1b26d5b5f5e2d945846b3592"
dependencies = [ dependencies = [
"bytes", "bytes",
"futures-core", "futures-core",
@ -2519,9 +2532,9 @@ dependencies = [
[[package]] [[package]]
name = "trust-dns-proto" name = "trust-dns-proto"
version = "0.20.2" version = "0.20.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "952a078337565ba39007de99b151770f41039253a31846f0a3d5cd5a4ac8eedf" checksum = "ad0d7f5db438199a6e2609debe3f69f808d074e0a2888ee0bccb45fe234d03f4"
dependencies = [ dependencies = [
"async-trait", "async-trait",
"cfg-if 1.0.0", "cfg-if 1.0.0",
@ -2544,9 +2557,9 @@ dependencies = [
[[package]] [[package]]
name = "trust-dns-resolver" name = "trust-dns-resolver"
version = "0.20.2" version = "0.20.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "da9c97f7d103e0f94dbe384a57908833505ae5870126492f166821b7cf685589" checksum = "f6ad17b608a64bd0735e67bde16b0636f8aa8591f831a25d18443ed00a699770"
dependencies = [ dependencies = [
"cfg-if 1.0.0", "cfg-if 1.0.0",
"futures-util", "futures-util",
@ -2633,6 +2646,12 @@ version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3"
[[package]]
name = "unindent"
version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f14ee04d9415b52b3aeab06258a3f07093182b88ba0f9b8d203f211a7a7d41c7"
[[package]] [[package]]
name = "untrusted" name = "untrusted"
version = "0.7.1" version = "0.7.1"
@ -2675,9 +2694,9 @@ checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6"
[[package]] [[package]]
name = "wasm-bindgen" name = "wasm-bindgen"
version = "0.2.73" version = "0.2.74"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "83240549659d187488f91f33c0f8547cbfef0b2088bc470c116d1d260ef623d9" checksum = "d54ee1d4ed486f78874278e63e4069fc1ab9f6a18ca492076ffb90c5eb2997fd"
dependencies = [ dependencies = [
"cfg-if 1.0.0", "cfg-if 1.0.0",
"serde", "serde",
@ -2687,9 +2706,9 @@ dependencies = [
[[package]] [[package]]
name = "wasm-bindgen-backend" name = "wasm-bindgen-backend"
version = "0.2.73" version = "0.2.74"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ae70622411ca953215ca6d06d3ebeb1e915f0f6613e3b495122878d7ebec7dae" checksum = "3b33f6a0694ccfea53d94db8b2ed1c3a8a4c86dd936b13b9f0a15ec4a451b900"
dependencies = [ dependencies = [
"bumpalo", "bumpalo",
"lazy_static", "lazy_static",
@ -2702,9 +2721,9 @@ dependencies = [
[[package]] [[package]]
name = "wasm-bindgen-futures" name = "wasm-bindgen-futures"
version = "0.4.23" version = "0.4.24"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "81b8b767af23de6ac18bf2168b690bed2902743ddf0fb39252e36f9e2bfc63ea" checksum = "5fba7978c679d53ce2d0ac80c8c175840feb849a161664365d1287b41f2e67f1"
dependencies = [ dependencies = [
"cfg-if 1.0.0", "cfg-if 1.0.0",
"js-sys", "js-sys",
@ -2714,9 +2733,9 @@ dependencies = [
[[package]] [[package]]
name = "wasm-bindgen-macro" name = "wasm-bindgen-macro"
version = "0.2.73" version = "0.2.74"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3e734d91443f177bfdb41969de821e15c516931c3c3db3d318fa1b68975d0f6f" checksum = "088169ca61430fe1e58b8096c24975251700e7b1f6fd91cc9d59b04fb9b18bd4"
dependencies = [ dependencies = [
"quote", "quote",
"wasm-bindgen-macro-support", "wasm-bindgen-macro-support",
@ -2724,9 +2743,9 @@ dependencies = [
[[package]] [[package]]
name = "wasm-bindgen-macro-support" name = "wasm-bindgen-macro-support"
version = "0.2.73" version = "0.2.74"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d53739ff08c8a68b0fdbcd54c372b8ab800b1449ab3c9d706503bc7dd1621b2c" checksum = "be2241542ff3d9f241f5e2cb6dd09b37efe786df8851c54957683a49f0987a97"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@ -2737,15 +2756,15 @@ dependencies = [
[[package]] [[package]]
name = "wasm-bindgen-shared" name = "wasm-bindgen-shared"
version = "0.2.73" version = "0.2.74"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d9a543ae66aa233d14bb765ed9af4a33e81b8b58d1584cf1b47ff8cd0b9e4489" checksum = "d7cff876b8f18eed75a66cf49b65e7f967cb354a7aa16003fb55dbfd25b44b4f"
[[package]] [[package]]
name = "web-sys" name = "web-sys"
version = "0.3.50" version = "0.3.51"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a905d57e488fec8861446d3393670fb50d27a262344013181c2cdf9fff5481be" checksum = "e828417b379f3df7111d3a2a9e5753706cae29c41f7c4029ee9fd77f3e09e582"
dependencies = [ dependencies = [
"js-sys", "js-sys",
"wasm-bindgen", "wasm-bindgen",

View File

@ -17,7 +17,8 @@ edition = "2018"
rocket = { git = "https://github.com/SergioBenitez/Rocket.git", rev = "801e04bd5369eb39e126c75f6d11e1e9597304d8", features = ["tls"] } # Used to handle requests rocket = { git = "https://github.com/SergioBenitez/Rocket.git", rev = "801e04bd5369eb39e126c75f6d11e1e9597304d8", features = ["tls"] } # Used to handle requests
# Used for matrix spec type definitions and helpers # Used for matrix spec type definitions and helpers
ruma = { git = "https://github.com/ruma/ruma", rev = "71686ce8a4d1770a80de216080718fe9de7bd925", features = ["compat", "rand", "appservice-api-c", "client-api", "federation-api", "push-gateway-api-c", "state-res", "unstable-pre-spec", "unstable-exhaustive-types"] } ruma = { git = "https://github.com/ruma/ruma", rev = "a238a0dda5b06fad146f8f01d690cbe011d13245", features = ["compat", "rand", "appservice-api-c", "client-api", "federation-api", "push-gateway-api-c", "state-res", "unstable-pre-spec", "unstable-exhaustive-types"] }
#ruma = { path = "../ruma/crates/ruma", features = ["compat", "rand", "appservice-api-c", "client-api", "federation-api", "push-gateway-api-c", "state-res", "unstable-pre-spec", "unstable-exhaustive-types"] }
# Used for long polling and federation sender, should be the same as rocket::tokio # Used for long polling and federation sender, should be the same as rocket::tokio
tokio = "1.2.0" tokio = "1.2.0"
@ -108,5 +109,5 @@ maintainer-scripts = "debian/"
systemd-units = { unit-name = "matrix-conduit" } systemd-units = { unit-name = "matrix-conduit" }
# For flamegraphs: # For flamegraphs:
[profile.release] #[profile.release]
debug = true #debug = true

View File

@ -8,11 +8,11 @@ use ruma::{
set_room_account_data, set_room_account_data,
}, },
}, },
events::{custom::CustomEventContent, AnyBasicEventContent, BasicEvent}, events::{AnyGlobalAccountDataEventContent, AnyRoomAccountDataEventContent},
serde::Raw, serde::Raw,
}; };
use serde::Deserialize; use serde::Deserialize;
use serde_json::value::RawValue as RawJsonValue; use serde_json::{json, value::RawValue as RawJsonValue};
#[cfg(feature = "conduit_bin")] #[cfg(feature = "conduit_bin")]
use rocket::{get, put}; use rocket::{get, put};
@ -28,7 +28,7 @@ pub async fn set_global_account_data_route(
) -> ConduitResult<set_global_account_data::Response> { ) -> ConduitResult<set_global_account_data::Response> {
let sender_user = body.sender_user.as_ref().expect("user is authenticated"); let sender_user = body.sender_user.as_ref().expect("user is authenticated");
let data = serde_json::from_str(body.data.get()) let data = serde_json::from_str::<serde_json::Value>(body.data.get())
.map_err(|_| Error::BadRequest(ErrorKind::BadJson, "Data is invalid."))?; .map_err(|_| Error::BadRequest(ErrorKind::BadJson, "Data is invalid."))?;
let event_type = body.event_type.to_string(); let event_type = body.event_type.to_string();
@ -37,9 +37,10 @@ pub async fn set_global_account_data_route(
None, None,
sender_user, sender_user,
event_type.clone().into(), event_type.clone().into(),
&BasicEvent { &json!({
content: CustomEventContent { event_type, data }, "type": event_type,
}, "content": data,
}),
&db.globals, &db.globals,
)?; )?;
@ -71,9 +72,10 @@ pub async fn set_room_account_data_route(
Some(&body.room_id), Some(&body.room_id),
sender_user, sender_user,
event_type.clone().into(), event_type.clone().into(),
&BasicEvent { &json!({
content: CustomEventContent { event_type, data }, "type": event_type,
}, "content": data,
}),
&db.globals, &db.globals,
)?; )?;
@ -99,7 +101,7 @@ pub async fn get_global_account_data_route(
.ok_or(Error::BadRequest(ErrorKind::NotFound, "Data not found."))?; .ok_or(Error::BadRequest(ErrorKind::NotFound, "Data not found."))?;
db.flush().await?; db.flush().await?;
let account_data = serde_json::from_str::<ExtractEventContent>(event.get()) let account_data = serde_json::from_str::<ExtractGlobalEventContent>(event.get())
.map_err(|_| Error::bad_database("Invalid account data event in db."))? .map_err(|_| Error::bad_database("Invalid account data event in db."))?
.content; .content;
@ -130,7 +132,7 @@ pub async fn get_room_account_data_route(
.ok_or(Error::BadRequest(ErrorKind::NotFound, "Data not found."))?; .ok_or(Error::BadRequest(ErrorKind::NotFound, "Data not found."))?;
db.flush().await?; db.flush().await?;
let account_data = serde_json::from_str::<ExtractEventContent>(event.get()) let account_data = serde_json::from_str::<ExtractRoomEventContent>(event.get())
.map_err(|_| Error::bad_database("Invalid account data event in db."))? .map_err(|_| Error::bad_database("Invalid account data event in db."))?
.content; .content;
@ -138,6 +140,11 @@ pub async fn get_room_account_data_route(
} }
#[derive(Deserialize)] #[derive(Deserialize)]
struct ExtractEventContent { struct ExtractRoomEventContent {
content: Raw<AnyBasicEventContent>, content: Raw<AnyRoomAccountDataEventContent>,
}
#[derive(Deserialize)]
struct ExtractGlobalEventContent {
content: Raw<AnyGlobalAccountDataEventContent>,
} }

View File

@ -1,5 +1,5 @@
use super::{State, SESSION_ID_LENGTH}; use super::{State, SESSION_ID_LENGTH};
use crate::{utils, ConduitResult, Database, Error, Ruma}; use crate::{utils, ConduitResult, Database, Error, Result, Ruma};
use ruma::{ use ruma::{
api::client::{ api::client::{
error::ErrorKind, error::ErrorKind,
@ -12,6 +12,7 @@ use ruma::{
}, },
}, },
encryption::UnsignedDeviceInfo, encryption::UnsignedDeviceInfo,
DeviceId, UserId,
}; };
use std::collections::{BTreeMap, HashSet}; use std::collections::{BTreeMap, HashSet};
@ -78,74 +79,14 @@ pub async fn get_keys_route(
) -> ConduitResult<get_keys::Response> { ) -> ConduitResult<get_keys::Response> {
let sender_user = body.sender_user.as_ref().expect("user is authenticated"); let sender_user = body.sender_user.as_ref().expect("user is authenticated");
let mut master_keys = BTreeMap::new(); let response = get_keys_helper(
let mut self_signing_keys = BTreeMap::new(); Some(sender_user),
let mut user_signing_keys = BTreeMap::new(); &body.device_keys,
let mut device_keys = BTreeMap::new(); |u| u == sender_user,
&db,
)?;
for (user_id, device_ids) in &body.device_keys { Ok(response.into())
if device_ids.is_empty() {
let mut container = BTreeMap::new();
for device_id in db.users.all_device_ids(user_id) {
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.")
})?;
keys.unsigned = UnsignedDeviceInfo {
device_display_name: metadata.display_name,
};
container.insert(device_id, keys);
}
}
device_keys.insert(user_id.clone(), container);
} else {
for device_id in device_ids {
let mut container = BTreeMap::new();
if let Some(mut keys) = db.users.get_device_keys(&user_id.clone(), &device_id)? {
let metadata = db.users.get_device_metadata(user_id, &device_id)?.ok_or(
Error::BadRequest(
ErrorKind::InvalidParam,
"Tried to get keys for nonexistent device.",
),
)?;
keys.unsigned = UnsignedDeviceInfo {
device_display_name: metadata.display_name,
};
container.insert(device_id.clone(), keys);
}
device_keys.insert(user_id.clone(), container);
}
}
if let Some(master_key) = db.users.get_master_key(user_id, sender_user)? {
master_keys.insert(user_id.clone(), master_key);
}
if let Some(self_signing_key) = db.users.get_self_signing_key(user_id, sender_user)? {
self_signing_keys.insert(user_id.clone(), self_signing_key);
}
if user_id == sender_user {
if let Some(user_signing_key) = db.users.get_user_signing_key(sender_user)? {
user_signing_keys.insert(user_id.clone(), user_signing_key);
}
}
}
Ok(get_keys::Response {
master_keys,
self_signing_keys,
user_signing_keys,
device_keys,
failures: BTreeMap::new(),
}
.into())
} }
#[cfg_attr( #[cfg_attr(
@ -356,3 +297,81 @@ pub async fn get_key_changes_route(
} }
.into()) .into())
} }
pub fn get_keys_helper<F: Fn(&UserId) -> bool>(
sender_user: Option<&UserId>,
device_keys_input: &BTreeMap<UserId, Vec<Box<DeviceId>>>,
allowed_signatures: F,
db: &Database,
) -> Result<get_keys::Response> {
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();
for (user_id, device_ids) in device_keys_input {
if device_ids.is_empty() {
let mut container = BTreeMap::new();
for device_id in db.users.all_device_ids(user_id) {
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.")
})?;
keys.unsigned = UnsignedDeviceInfo {
device_display_name: metadata.display_name,
};
container.insert(device_id, keys);
}
}
device_keys.insert(user_id.clone(), container);
} else {
for device_id in device_ids {
let mut container = BTreeMap::new();
if let Some(mut keys) = db.users.get_device_keys(&user_id.clone(), &device_id)? {
let metadata = db.users.get_device_metadata(user_id, &device_id)?.ok_or(
Error::BadRequest(
ErrorKind::InvalidParam,
"Tried to get keys for nonexistent device.",
),
)?;
keys.unsigned = UnsignedDeviceInfo {
device_display_name: metadata.display_name,
};
container.insert(device_id.clone(), keys);
}
device_keys.insert(user_id.clone(), container);
}
}
if let Some(master_key) = db.users.get_master_key(user_id, &allowed_signatures)? {
master_keys.insert(user_id.clone(), master_key);
}
if let Some(self_signing_key) = db
.users
.get_self_signing_key(user_id, &allowed_signatures)?
{
self_signing_keys.insert(user_id.clone(), self_signing_key);
}
if Some(user_id) == sender_user {
if let Some(user_signing_key) = db.users.get_user_signing_key(user_id)? {
user_signing_keys.insert(user_id.clone(), user_signing_key);
}
}
}
Ok(get_keys::Response {
master_keys,
self_signing_keys,
user_signing_keys,
device_keys,
failures: BTreeMap::new(),
})
}

View File

@ -4,7 +4,7 @@ use crate::{
pdu::{PduBuilder, PduEvent}, pdu::{PduBuilder, PduEvent},
server_server, utils, ConduitResult, Database, Error, Result, Ruma, server_server, utils, ConduitResult, Database, Error, Result, Ruma,
}; };
use log::{error, warn}; use log::{debug, error, warn};
use member::{MemberEventContent, MembershipState}; use member::{MemberEventContent, MembershipState};
use rocket::futures; use rocket::futures;
use ruma::{ use ruma::{
@ -29,9 +29,10 @@ use ruma::{
uint, EventId, RoomId, RoomVersionId, ServerName, UserId, uint, EventId, RoomId, RoomVersionId, ServerName, UserId,
}; };
use std::{ use std::{
collections::{BTreeMap, HashSet}, collections::{btree_map::Entry, BTreeMap, HashSet},
convert::{TryFrom, TryInto}, convert::{TryFrom, TryInto},
sync::{Arc, RwLock}, sync::{Arc, RwLock},
time::{Duration, Instant},
}; };
#[cfg(feature = "conduit_bin")] #[cfg(feature = "conduit_bin")]
@ -703,6 +704,38 @@ async fn validate_and_add_event_id(
error!("{:?}: {:?}", pdu, e); error!("{:?}: {:?}", pdu, e);
Error::BadServerResponse("Invalid PDU in server response") Error::BadServerResponse("Invalid PDU in server response")
})?; })?;
let event_id = EventId::try_from(&*format!(
"${}",
ruma::signatures::reference_hash(&value, &room_version)
.expect("ruma can calculate reference hashes")
))
.expect("ruma's reference hashes are valid event ids");
let back_off = |id| match db.globals.bad_event_ratelimiter.write().unwrap().entry(id) {
Entry::Vacant(e) => {
e.insert((Instant::now(), 1));
}
Entry::Occupied(mut e) => *e.get_mut() = (Instant::now(), e.get().1 + 1),
};
if let Some((time, tries)) = db
.globals
.bad_event_ratelimiter
.read()
.unwrap()
.get(&event_id)
{
// Exponential backoff
let mut min_elapsed_duration = Duration::from_secs(30) * (*tries) * (*tries);
if min_elapsed_duration > Duration::from_secs(60 * 60 * 24) {
min_elapsed_duration = Duration::from_secs(60 * 60 * 24);
}
if time.elapsed() < min_elapsed_duration {
debug!("Backing off from {}", event_id);
return Err(Error::BadServerResponse("bad event, still backing off"));
}
}
server_server::fetch_required_signing_keys(&value, pub_key_map, db).await?; server_server::fetch_required_signing_keys(&value, pub_key_map, db).await?;
if let Err(e) = ruma::signatures::verify_event( if let Err(e) = ruma::signatures::verify_event(
@ -712,17 +745,11 @@ async fn validate_and_add_event_id(
&value, &value,
room_version, room_version,
) { ) {
warn!("Event failed verification: {}", e); warn!("Event {} failed verification: {}", event_id, e);
back_off(event_id);
return Err(Error::BadServerResponse("Event failed verification.")); return Err(Error::BadServerResponse("Event failed verification."));
} }
let event_id = EventId::try_from(&*format!(
"${}",
ruma::signatures::reference_hash(&value, &room_version)
.expect("ruma can calculate reference hashes")
))
.expect("ruma's reference hashes are valid event ids");
value.insert( value.insert(
"event_id".to_owned(), "event_id".to_owned(),
CanonicalJsonValue::String(event_id.as_str().to_owned()), CanonicalJsonValue::String(event_id.as_str().to_owned()),

View File

@ -5,12 +5,14 @@ use ruma::{
error::ErrorKind, error::ErrorKind,
r0::{read_marker::set_read_marker, receipt::create_receipt}, r0::{read_marker::set_read_marker, receipt::create_receipt},
}, },
events::{AnyEphemeralRoomEvent, AnyEvent, EventType}, events::{AnyEphemeralRoomEvent, EventType},
receipt::ReceiptType,
MilliSecondsSinceUnixEpoch,
}; };
#[cfg(feature = "conduit_bin")] #[cfg(feature = "conduit_bin")]
use rocket::post; use rocket::post;
use std::{collections::BTreeMap, time::SystemTime}; use std::collections::BTreeMap;
#[cfg_attr( #[cfg_attr(
feature = "conduit_bin", feature = "conduit_bin",
@ -27,7 +29,6 @@ pub async fn set_read_marker_route(
content: ruma::events::fully_read::FullyReadEventContent { content: ruma::events::fully_read::FullyReadEventContent {
event_id: body.fully_read.clone(), event_id: body.fully_read.clone(),
}, },
room_id: body.room_id.clone(),
}; };
db.account_data.update( db.account_data.update(
Some(&body.room_id), Some(&body.room_id),
@ -54,26 +55,23 @@ pub async fn set_read_marker_route(
user_receipts.insert( user_receipts.insert(
sender_user.clone(), sender_user.clone(),
ruma::events::receipt::Receipt { ruma::events::receipt::Receipt {
ts: Some(SystemTime::now()), ts: Some(MilliSecondsSinceUnixEpoch::now()),
}, },
); );
let mut receipts = BTreeMap::new();
receipts.insert(ReceiptType::Read, user_receipts);
let mut receipt_content = BTreeMap::new(); let mut receipt_content = BTreeMap::new();
receipt_content.insert( receipt_content.insert(event.to_owned(), receipts);
event.to_owned(),
ruma::events::receipt::Receipts {
read: Some(user_receipts),
},
);
db.rooms.edus.readreceipt_update( db.rooms.edus.readreceipt_update(
&sender_user, &sender_user,
&body.room_id, &body.room_id,
AnyEvent::Ephemeral(AnyEphemeralRoomEvent::Receipt( AnyEphemeralRoomEvent::Receipt(ruma::events::receipt::ReceiptEvent {
ruma::events::receipt::ReceiptEvent { content: ruma::events::receipt::ReceiptEventContent(receipt_content),
content: ruma::events::receipt::ReceiptEventContent(receipt_content), room_id: body.room_id.clone(),
room_id: body.room_id.clone(), }),
},
)),
&db.globals, &db.globals,
)?; )?;
} }
@ -112,26 +110,22 @@ pub async fn create_receipt_route(
user_receipts.insert( user_receipts.insert(
sender_user.clone(), sender_user.clone(),
ruma::events::receipt::Receipt { ruma::events::receipt::Receipt {
ts: Some(SystemTime::now()), ts: Some(MilliSecondsSinceUnixEpoch::now()),
}, },
); );
let mut receipts = BTreeMap::new();
receipts.insert(ReceiptType::Read, user_receipts);
let mut receipt_content = BTreeMap::new(); let mut receipt_content = BTreeMap::new();
receipt_content.insert( receipt_content.insert(body.event_id.to_owned(), receipts);
body.event_id.to_owned(),
ruma::events::receipt::Receipts {
read: Some(user_receipts),
},
);
db.rooms.edus.readreceipt_update( db.rooms.edus.readreceipt_update(
&sender_user, &sender_user,
&body.room_id, &body.room_id,
AnyEvent::Ephemeral(AnyEphemeralRoomEvent::Receipt( AnyEphemeralRoomEvent::Receipt(ruma::events::receipt::ReceiptEvent {
ruma::events::receipt::ReceiptEvent { content: ruma::events::receipt::ReceiptEventContent(receipt_content),
content: ruma::events::receipt::ReceiptEventContent(receipt_content), room_id: body.room_id.clone(),
room_id: body.room_id.clone(), }),
},
)),
&db.globals, &db.globals,
)?; )?;

View File

@ -422,7 +422,7 @@ pub async fn sync_events_route(
} }
let joined_room = sync_events::JoinedRoom { let joined_room = sync_events::JoinedRoom {
account_data: sync_events::AccountData { account_data: sync_events::RoomAccountData {
events: db events: db
.account_data .account_data
.changes_since(Some(&room_id), &sender_user, since)? .changes_since(Some(&room_id), &sender_user, since)?
@ -506,7 +506,7 @@ pub async fn sync_events_route(
left_rooms.insert( left_rooms.insert(
room_id.clone(), room_id.clone(),
sync_events::LeftRoom { sync_events::LeftRoom {
account_data: sync_events::AccountData { events: Vec::new() }, account_data: sync_events::RoomAccountData { events: Vec::new() },
timeline: sync_events::Timeline { timeline: sync_events::Timeline {
limited: false, limited: false,
prev_batch: Some(next_batch.clone()), prev_batch: Some(next_batch.clone()),
@ -577,7 +577,7 @@ pub async fn sync_events_route(
.map(|(_, v)| Raw::from(v)) .map(|(_, v)| Raw::from(v))
.collect(), .collect(),
}, },
account_data: sync_events::AccountData { account_data: sync_events::GlobalAccountData {
events: db events: db
.account_data .account_data
.changes_since(None, &sender_user, since)? .changes_since(None, &sender_user, since)?

View File

@ -213,7 +213,7 @@ impl Database {
pusher: pusher::PushData::new(&db)?, pusher: pusher::PushData::new(&db)?,
globals: globals::Globals::load( globals: globals::Globals::load(
db.open_tree("global")?, db.open_tree("global")?,
db.open_tree("servertimeout_signingkey")?, db.open_tree("server_signingkeys")?,
config, config,
)?, )?,
_db: db, _db: db,

View File

@ -1,7 +1,7 @@
use crate::{utils, Error, Result}; use crate::{utils, Error, Result};
use ruma::{ use ruma::{
api::client::error::ErrorKind, api::client::error::ErrorKind,
events::{AnyEvent as EduEvent, EventType}, events::{AnyEphemeralRoomEvent, EventType},
serde::Raw, serde::Raw,
RoomId, UserId, RoomId, UserId,
}; };
@ -80,7 +80,7 @@ impl AccountData {
room_id: Option<&RoomId>, room_id: Option<&RoomId>,
user_id: &UserId, user_id: &UserId,
since: u64, since: u64,
) -> Result<HashMap<EventType, Raw<EduEvent>>> { ) -> Result<HashMap<EventType, Raw<AnyEphemeralRoomEvent>>> {
let mut userdata = HashMap::new(); let mut userdata = HashMap::new();
let mut prefix = room_id let mut prefix = room_id
@ -110,7 +110,7 @@ impl AccountData {
.map_err(|_| Error::bad_database("RoomUserData ID in db is invalid."))?, .map_err(|_| Error::bad_database("RoomUserData ID in db is invalid."))?,
) )
.map_err(|_| Error::bad_database("RoomUserData ID in db is invalid."))?, .map_err(|_| Error::bad_database("RoomUserData ID in db is invalid."))?,
serde_json::from_slice::<Raw<EduEvent>>(&v).map_err(|_| { serde_json::from_slice::<Raw<AnyEphemeralRoomEvent>>(&v).map_err(|_| {
Error::bad_database("Database contains invalid account data.") Error::bad_database("Database contains invalid account data.")
})?, })?,
)) ))

View File

@ -2,20 +2,22 @@ use crate::{database::Config, utils, Error, Result};
use log::{error, info}; use log::{error, info};
use ruma::{ use ruma::{
api::federation::discovery::{ServerSigningKeys, VerifyKey}, api::federation::discovery::{ServerSigningKeys, VerifyKey},
ServerName, ServerSigningKeyId, EventId, MilliSecondsSinceUnixEpoch, ServerName, ServerSigningKeyId,
}; };
use rustls::{ServerCertVerifier, WebPKIVerifier}; use rustls::{ServerCertVerifier, WebPKIVerifier};
use std::{ use std::{
collections::{BTreeMap, HashMap}, collections::{BTreeMap, HashMap},
sync::{Arc, RwLock}, sync::{Arc, RwLock},
time::Duration, time::{Duration, Instant},
}; };
use tokio::sync::Semaphore;
use trust_dns_resolver::TokioAsyncResolver; use trust_dns_resolver::TokioAsyncResolver;
pub const COUNTER: &str = "c"; pub const COUNTER: &str = "c";
type WellKnownMap = HashMap<Box<ServerName>, (String, String)>; type WellKnownMap = HashMap<Box<ServerName>, (String, String)>;
type TlsNameMap = HashMap<String, webpki::DNSName>; type TlsNameMap = HashMap<String, webpki::DNSName>;
type RateLimitState = (Instant, u32); // Time if last failed try, number of failed tries
#[derive(Clone)] #[derive(Clone)]
pub struct Globals { pub struct Globals {
pub actual_destination_cache: Arc<RwLock<WellKnownMap>>, // actual_destination, host pub actual_destination_cache: Arc<RwLock<WellKnownMap>>, // actual_destination, host
@ -26,7 +28,10 @@ pub struct Globals {
reqwest_client: reqwest::Client, reqwest_client: reqwest::Client,
dns_resolver: TokioAsyncResolver, dns_resolver: TokioAsyncResolver,
jwt_decoding_key: Option<jsonwebtoken::DecodingKey<'static>>, jwt_decoding_key: Option<jsonwebtoken::DecodingKey<'static>>,
pub(super) servertimeout_signingkey: sled::Tree, // ServerName + Timeout Timestamp -> algorithm:key + pubkey pub(super) server_signingkeys: sled::Tree,
pub bad_event_ratelimiter: Arc<RwLock<BTreeMap<EventId, RateLimitState>>>,
pub bad_signature_ratelimiter: Arc<RwLock<BTreeMap<Vec<String>, RateLimitState>>>,
pub servername_ratelimiter: Arc<RwLock<BTreeMap<Box<ServerName>, Arc<Semaphore>>>>,
} }
struct MatrixServerVerifier { struct MatrixServerVerifier {
@ -65,7 +70,7 @@ impl ServerCertVerifier for MatrixServerVerifier {
impl Globals { impl Globals {
pub fn load( pub fn load(
globals: sled::Tree, globals: sled::Tree,
servertimeout_signingkey: sled::Tree, server_signingkeys: sled::Tree,
config: Config, config: Config,
) -> Result<Self> { ) -> Result<Self> {
let bytes = &*globals let bytes = &*globals
@ -135,8 +140,11 @@ impl Globals {
})?, })?,
actual_destination_cache: Arc::new(RwLock::new(WellKnownMap::new())), actual_destination_cache: Arc::new(RwLock::new(WellKnownMap::new())),
tls_name_override, tls_name_override,
servertimeout_signingkey, server_signingkeys,
jwt_decoding_key, jwt_decoding_key,
bad_event_ratelimiter: Arc::new(RwLock::new(BTreeMap::new())),
bad_signature_ratelimiter: Arc::new(RwLock::new(BTreeMap::new())),
servername_ratelimiter: Arc::new(RwLock::new(BTreeMap::new())),
}) })
} }
@ -203,31 +211,21 @@ impl Globals {
/// Remove the outdated keys and insert the new ones. /// Remove the outdated keys and insert the new ones.
/// ///
/// This doesn't actually check that the keys provided are newer than the old set. /// This doesn't actually check that the keys provided are newer than the old set.
pub fn add_signing_key(&self, origin: &ServerName, keys: &ServerSigningKeys) -> Result<()> { pub fn add_signing_key(&self, origin: &ServerName, new_keys: &ServerSigningKeys) -> Result<()> {
let mut key1 = origin.as_bytes().to_vec(); self.server_signingkeys
key1.push(0xff); .update_and_fetch(origin.as_bytes(), |signingkeys| {
let mut keys = signingkeys
let mut key2 = key1.clone(); .and_then(|keys| serde_json::from_slice(keys).ok())
.unwrap_or_else(|| {
let ts = keys // Just insert "now", it doesn't matter
.valid_until_ts ServerSigningKeys::new(origin.to_owned(), MilliSecondsSinceUnixEpoch::now())
.duration_since(std::time::UNIX_EPOCH) });
.expect("time is valid") keys.verify_keys
.as_millis() as u64; .extend(new_keys.verify_keys.clone().into_iter());
keys.old_verify_keys
key1.extend_from_slice(&ts.to_be_bytes()); .extend(new_keys.old_verify_keys.clone().into_iter());
key2.extend_from_slice(&(ts + 1).to_be_bytes()); Some(serde_json::to_vec(&keys).expect("serversigningkeys can be serialized"))
})?;
self.servertimeout_signingkey.insert(
key1,
serde_json::to_vec(&keys.verify_keys).expect("ServerSigningKeys are a valid string"),
)?;
self.servertimeout_signingkey.insert(
key2,
serde_json::to_vec(&keys.old_verify_keys)
.expect("ServerSigningKeys are a valid string"),
)?;
Ok(()) Ok(())
} }
@ -237,26 +235,22 @@ impl Globals {
&self, &self,
origin: &ServerName, origin: &ServerName,
) -> Result<BTreeMap<ServerSigningKeyId, VerifyKey>> { ) -> Result<BTreeMap<ServerSigningKeyId, VerifyKey>> {
let mut response = BTreeMap::new(); let signingkeys = self
.server_signingkeys
.get(origin.as_bytes())?
.and_then(|bytes| serde_json::from_slice::<ServerSigningKeys>(&bytes).ok())
.map(|keys| {
let mut tree = keys.verify_keys;
tree.extend(
keys.old_verify_keys
.into_iter()
.map(|old| (old.0, VerifyKey::new(old.1.key))),
);
tree
})
.unwrap_or_else(BTreeMap::new);
let now = crate::utils::millis_since_unix_epoch(); Ok(signingkeys)
for item in self.servertimeout_signingkey.scan_prefix(origin.as_bytes()) {
let (k, bytes) = item?;
let valid_until = k
.splitn(2, |&b| b == 0xff)
.nth(1)
.map(crate::utils::u64_from_bytes)
.ok_or_else(|| Error::bad_database("Invalid signing keys."))?
.map_err(|_| Error::bad_database("Invalid signing key valid until bytes"))?;
// If these keys are still valid use em!
if valid_until > now {
let btree: BTreeMap<_, _> = serde_json::from_slice(&bytes)
.map_err(|_| Error::bad_database("Invalid BTreeMap<> of signing keys"))?;
response.extend(btree);
}
}
Ok(response)
} }
pub fn database_version(&self) -> Result<u64> { pub fn database_version(&self) -> Result<u64> {

View File

@ -294,7 +294,8 @@ async fn send_notice(
} else { } else {
notifi.sender = Some(&event.sender); notifi.sender = Some(&event.sender);
notifi.event_type = Some(&event.kind); notifi.event_type = Some(&event.kind);
notifi.content = serde_json::value::to_raw_value(&event.content).ok(); let content = serde_json::value::to_raw_value(&event.content).ok();
notifi.content = content.as_deref();
if event.kind == EventType::RoomMember { if event.kind == EventType::RoomMember {
notifi.user_is_target = event.state_key.as_deref() == Some(event.sender.as_str()); notifi.user_is_target = event.state_key.as_deref() == Some(event.sender.as_str());

View File

@ -2,7 +2,7 @@ use crate::{utils, Error, Result};
use ruma::{ use ruma::{
events::{ events::{
presence::{PresenceEvent, PresenceEventContent}, presence::{PresenceEvent, PresenceEventContent},
AnyEvent as EduEvent, SyncEphemeralRoomEvent, AnyEphemeralRoomEvent, SyncEphemeralRoomEvent,
}, },
presence::PresenceState, presence::PresenceState,
serde::Raw, serde::Raw,
@ -32,7 +32,7 @@ impl RoomEdus {
&self, &self,
user_id: &UserId, user_id: &UserId,
room_id: &RoomId, room_id: &RoomId,
event: EduEvent, event: AnyEphemeralRoomEvent,
globals: &super::super::globals::Globals, globals: &super::super::globals::Globals,
) -> Result<()> { ) -> Result<()> {
let mut prefix = room_id.as_bytes().to_vec(); let mut prefix = room_id.as_bytes().to_vec();

View File

@ -3,7 +3,7 @@ use std::{
convert::{TryFrom, TryInto}, convert::{TryFrom, TryInto},
fmt::Debug, fmt::Debug,
sync::Arc, sync::Arc,
time::{Duration, Instant, SystemTime}, time::{Duration, Instant},
}; };
use crate::{ use crate::{
@ -23,7 +23,9 @@ use ruma::{
OutgoingRequest, OutgoingRequest,
}, },
events::{push_rules, AnySyncEphemeralRoomEvent, EventType}, events::{push_rules, AnySyncEphemeralRoomEvent, EventType},
push, ServerName, UInt, UserId, push,
receipt::ReceiptType,
MilliSecondsSinceUnixEpoch, ServerName, UInt, UserId,
}; };
use sled::IVec; use sled::IVec;
use tokio::{select, sync::Semaphore}; use tokio::{select, sync::Semaphore};
@ -277,17 +279,14 @@ impl Sending {
events.push(e); events.push(e);
} }
match outgoing_kind { if let OutgoingKind::Normal(server_name) = outgoing_kind {
OutgoingKind::Normal(server_name) => { if let Ok((select_edus, last_count)) = Self::select_edus(db, server_name) {
if let Ok((select_edus, last_count)) = Self::select_edus(db, server_name) { events.extend_from_slice(&select_edus);
events.extend_from_slice(&select_edus); db.sending
db.sending .servername_educount
.servername_educount .insert(server_name.as_bytes(), &last_count.to_be_bytes())
.insert(server_name.as_bytes(), &last_count.to_be_bytes()) .unwrap();
.unwrap();
}
} }
_ => {}
} }
} }
@ -326,14 +325,14 @@ impl Sending {
AnySyncEphemeralRoomEvent::Receipt(r) => { AnySyncEphemeralRoomEvent::Receipt(r) => {
let mut read = BTreeMap::new(); let mut read = BTreeMap::new();
let (event_id, receipt) = r let (event_id, mut receipt) = r
.content .content
.0 .0
.into_iter() .into_iter()
.next() .next()
.expect("we only use one event per read receipt"); .expect("we only use one event per read receipt");
let receipt = receipt let receipt = receipt
.read .remove(&ReceiptType::Read)
.expect("our read receipts always set this") .expect("our read receipts always set this")
.remove(&user_id) .remove(&user_id)
.expect("our read receipts always have the user here"); .expect("our read receipts always have the user here");
@ -436,7 +435,7 @@ impl Sending {
), ),
) )
})? })?
.to_any_event()) .to_room_event())
} }
SendingEventType::Edu(_) => { SendingEventType::Edu(_) => {
// Appservices don't need EDUs (?) // Appservices don't need EDUs (?)
@ -610,7 +609,7 @@ impl Sending {
origin: db.globals.server_name(), origin: db.globals.server_name(),
pdus: &pdu_jsons, pdus: &pdu_jsons,
edus: &edu_jsons, edus: &edu_jsons,
origin_server_ts: SystemTime::now(), origin_server_ts: MilliSecondsSinceUnixEpoch::now(),
transaction_id: &base64::encode_config( transaction_id: &base64::encode_config(
Self::calculate_hash( Self::calculate_hash(
&events &events

View File

@ -1,19 +1,13 @@
use crate::{utils, Error, Result}; use crate::{utils, Error, Result};
use ruma::{ use ruma::{
api::client::{ api::client::{error::ErrorKind, r0::device::Device},
error::ErrorKind, encryption::{CrossSigningKey, DeviceKeys, OneTimeKey},
r0::{
device::Device,
keys::{CrossSigningKey, OneTimeKey},
},
},
encryption::DeviceKeys,
events::{AnyToDeviceEvent, EventType}, events::{AnyToDeviceEvent, EventType},
identifiers::MxcUri, identifiers::MxcUri,
serde::Raw, serde::Raw,
DeviceId, DeviceKeyAlgorithm, DeviceKeyId, UInt, UserId, DeviceId, DeviceKeyAlgorithm, DeviceKeyId, MilliSecondsSinceUnixEpoch, UInt, UserId,
}; };
use std::{collections::BTreeMap, convert::TryFrom, mem, time::SystemTime}; use std::{collections::BTreeMap, convert::TryFrom, mem};
#[derive(Clone)] #[derive(Clone)]
pub struct Users { pub struct Users {
@ -200,7 +194,7 @@ impl Users {
device_id: device_id.into(), device_id: device_id.into(),
display_name: initial_device_display_name, display_name: initial_device_display_name,
last_seen_ip: None, // TODO last_seen_ip: None, // TODO
last_seen_ts: Some(SystemTime::now()), last_seen_ts: Some(MilliSecondsSinceUnixEpoch::now()),
}) })
.expect("Device::to_string never fails.") .expect("Device::to_string never fails.")
.as_bytes(), .as_bytes(),
@ -653,12 +647,11 @@ impl Users {
}) })
} }
pub fn get_master_key( pub fn get_master_key<F: Fn(&UserId) -> bool>(
&self, &self,
user_id: &UserId, user_id: &UserId,
sender_id: &UserId, allowed_signatures: F,
) -> Result<Option<CrossSigningKey>> { ) -> Result<Option<CrossSigningKey>> {
// TODO: hide some signatures
self.userid_masterkeyid self.userid_masterkeyid
.get(user_id.to_string())? .get(user_id.to_string())?
.map_or(Ok(None), |key| { .map_or(Ok(None), |key| {
@ -673,7 +666,7 @@ impl Users {
cross_signing_key.signatures = cross_signing_key cross_signing_key.signatures = cross_signing_key
.signatures .signatures
.into_iter() .into_iter()
.filter(|(user, _)| user == user_id || user == sender_id) .filter(|(user, _)| allowed_signatures(user))
.collect(); .collect();
Ok(Some(cross_signing_key)) Ok(Some(cross_signing_key))
@ -681,10 +674,10 @@ impl Users {
}) })
} }
pub fn get_self_signing_key( pub fn get_self_signing_key<F: Fn(&UserId) -> bool>(
&self, &self,
user_id: &UserId, user_id: &UserId,
sender_id: &UserId, allowed_signatures: F,
) -> Result<Option<CrossSigningKey>> { ) -> Result<Option<CrossSigningKey>> {
self.userid_selfsigningkeyid self.userid_selfsigningkeyid
.get(user_id.to_string())? .get(user_id.to_string())?
@ -700,7 +693,7 @@ impl Users {
cross_signing_key.signatures = cross_signing_key cross_signing_key.signatures = cross_signing_key
.signatures .signatures
.into_iter() .into_iter()
.filter(|(user, _)| user == user_id || user == sender_id) .filter(|(user, _)| user == user_id || allowed_signatures(user))
.collect(); .collect();
Ok(Some(cross_signing_key)) Ok(Some(cross_signing_key))

View File

@ -158,6 +158,7 @@ fn setup_rocket(config: Figment, data: Database) -> rocket::Rocket<rocket::Build
server_server::get_devices_route, server_server::get_devices_route,
server_server::get_room_information_route, server_server::get_room_information_route,
server_server::get_profile_information_route, server_server::get_profile_information_route,
server_server::get_keys_route,
], ],
) )
.register( .register(

View File

@ -2,15 +2,17 @@ use crate::Error;
use log::error; use log::error;
use ruma::{ use ruma::{
events::{ events::{
pdu::EventHash, room::member::MemberEventContent, AnyEvent, AnyRoomEvent, AnyStateEvent, pdu::EventHash, room::member::MemberEventContent, AnyEphemeralRoomEvent, AnyRoomEvent,
AnyStrippedStateEvent, AnySyncRoomEvent, AnySyncStateEvent, EventType, StateEvent, AnyStateEvent, AnyStrippedStateEvent, AnySyncRoomEvent, AnySyncStateEvent, EventType,
StateEvent,
}, },
serde::{CanonicalJsonObject, CanonicalJsonValue, Raw}, serde::{CanonicalJsonObject, CanonicalJsonValue, Raw},
state_res, EventId, RoomId, RoomVersionId, ServerName, ServerSigningKeyId, UInt, UserId, state_res, EventId, MilliSecondsSinceUnixEpoch, RoomId, RoomVersionId, ServerName,
ServerSigningKeyId, UInt, UserId,
}; };
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use serde_json::json; use serde_json::json;
use std::{cmp::Ordering, collections::BTreeMap, convert::TryFrom, time::UNIX_EPOCH}; use std::{cmp::Ordering, collections::BTreeMap, convert::TryFrom};
#[derive(Clone, Deserialize, Serialize, Debug)] #[derive(Clone, Deserialize, Serialize, Debug)]
pub struct PduEvent { pub struct PduEvent {
@ -105,7 +107,7 @@ impl PduEvent {
/// This only works for events that are also AnyRoomEvents. /// This only works for events that are also AnyRoomEvents.
#[tracing::instrument(skip(self))] #[tracing::instrument(skip(self))]
pub fn to_any_event(&self) -> Raw<AnyEvent> { pub fn to_any_event(&self) -> Raw<AnyEphemeralRoomEvent> {
let mut json = json!({ let mut json = json!({
"content": self.content, "content": self.content,
"type": self.kind, "type": self.kind,
@ -267,10 +269,9 @@ impl state_res::Event for PduEvent {
fn content(&self) -> serde_json::Value { fn content(&self) -> serde_json::Value {
self.content.clone() self.content.clone()
} }
fn origin_server_ts(&self) -> std::time::SystemTime { fn origin_server_ts(&self) -> MilliSecondsSinceUnixEpoch {
UNIX_EPOCH + std::time::Duration::from_millis(self.origin_server_ts.into()) MilliSecondsSinceUnixEpoch(self.origin_server_ts)
} }
fn state_key(&self) -> Option<String> { fn state_key(&self) -> Option<String> {
self.state_key.clone() self.state_key.clone()
} }

View File

@ -34,6 +34,7 @@ pub struct Ruma<T: Outgoing> {
pub body: T::Incoming, pub body: T::Incoming,
pub sender_user: Option<UserId>, pub sender_user: Option<UserId>,
pub sender_device: Option<Box<DeviceId>>, pub sender_device: Option<Box<DeviceId>>,
pub sender_servername: Option<Box<ServerName>>,
// This is None when body is not a valid string // This is None when body is not a valid string
pub json_body: Option<CanonicalJsonValue>, pub json_body: Option<CanonicalJsonValue>,
pub from_appservice: bool, pub from_appservice: bool,
@ -68,7 +69,10 @@ where
let mut json_body = serde_json::from_slice::<CanonicalJsonValue>(&body).ok(); let mut json_body = serde_json::from_slice::<CanonicalJsonValue>(&body).ok();
let (sender_user, sender_device, from_appservice) = if let Some((_id, registration)) = db let (sender_user, sender_device, sender_servername, from_appservice) = if let Some((
_id,
registration,
)) = db
.appservice .appservice
.iter_all() .iter_all()
.filter_map(|r| r.ok()) .filter_map(|r| r.ok())
@ -104,10 +108,10 @@ where
} }
// TODO: Check if appservice is allowed to be that user // TODO: Check if appservice is allowed to be that user
(Some(user_id), None, true) (Some(user_id), None, None, true)
} }
AuthScheme::ServerSignatures => (None, None, true), AuthScheme::ServerSignatures => (None, None, None, true),
AuthScheme::None => (None, None, true), AuthScheme::None => (None, None, None, true),
} }
} else { } else {
match metadata.authentication { match metadata.authentication {
@ -116,9 +120,12 @@ where
match db.users.find_from_token(&token).unwrap() { match db.users.find_from_token(&token).unwrap() {
// Unknown Token // Unknown Token
None => return Failure((Status::raw(581), ())), None => return Failure((Status::raw(581), ())),
Some((user_id, device_id)) => { Some((user_id, device_id)) => (
(Some(user_id), Some(Box::<DeviceId>::from(device_id)), false) Some(user_id),
} Some(Box::<DeviceId>::from(device_id)),
None,
false,
),
} }
} else { } else {
// Missing Token // Missing Token
@ -227,27 +234,24 @@ where
CanonicalJsonValue::Object(signatures), CanonicalJsonValue::Object(signatures),
); );
let keys = match server_server::fetch_signing_keys( let keys =
&db, match server_server::fetch_signing_keys(&db, &origin, vec![key.to_owned()])
&origin, .await
vec![&key.to_owned()], {
) Ok(b) => b,
.await Err(e) => {
{ warn!("Failed to fetch signing keys: {}", e);
Ok(b) => b,
Err(e) => {
warn!("Failed to fetch signing keys: {}", e);
// Forbidden // Forbidden
return Failure((Status::raw(580), ())); return Failure((Status::raw(580), ()));
} }
}; };
let mut pub_key_map = BTreeMap::new(); let mut pub_key_map = BTreeMap::new();
pub_key_map.insert(origin.as_str().to_owned(), keys); pub_key_map.insert(origin.as_str().to_owned(), keys);
match ruma::signatures::verify_json(&pub_key_map, &request_map) { match ruma::signatures::verify_json(&pub_key_map, &request_map) {
Ok(()) => (None, None, false), Ok(()) => (None, None, Some(origin), false),
Err(e) => { Err(e) => {
warn!("Failed to verify json request from {}: {}", origin, e); warn!("Failed to verify json request from {}: {}", origin, e);
@ -260,7 +264,7 @@ where
} }
} }
} }
AuthScheme::None => (None, None, false), AuthScheme::None => (None, None, None, false),
} }
}; };
@ -307,6 +311,7 @@ where
body: t, body: t,
sender_user, sender_user,
sender_device, sender_device,
sender_servername,
from_appservice, from_appservice,
json_body, json_body,
}), }),

View File

@ -1,7 +1,10 @@
use crate::{client_server, utils, ConduitResult, Database, Error, PduEvent, Result, Ruma}; use crate::{
client_server::{self, get_keys_helper},
utils, ConduitResult, Database, Error, PduEvent, Result, Ruma,
};
use get_profile_information::v1::ProfileField; use get_profile_information::v1::ProfileField;
use http::header::{HeaderValue, AUTHORIZATION, HOST}; use http::header::{HeaderValue, AUTHORIZATION, HOST};
use log::{debug, error, info, warn}; use log::{debug, error, info, trace, warn};
use regex::Regex; use regex::Regex;
use rocket::{response::content::Json, State}; use rocket::{response::content::Json, State};
use ruma::{ use ruma::{
@ -15,6 +18,7 @@ use ruma::{
VerifyKey, VerifyKey,
}, },
event::{get_event, get_missing_events, get_room_state_ids}, event::{get_event, get_missing_events, get_room_state_ids},
keys::get_keys,
membership::{ membership::{
create_invite, create_invite,
create_join_event::{self, RoomState}, create_join_event::{self, RoomState},
@ -32,12 +36,14 @@ use ruma::{
create::CreateEventContent, create::CreateEventContent,
member::{MemberEventContent, MembershipState}, member::{MemberEventContent, MembershipState},
}, },
AnyEphemeralRoomEvent, AnyEvent as EduEvent, EventType, AnyEphemeralRoomEvent, EventType,
}, },
receipt::ReceiptType,
serde::Raw, serde::Raw,
signatures::{CanonicalJsonObject, CanonicalJsonValue}, signatures::{CanonicalJsonObject, CanonicalJsonValue},
state_res::{self, Event, EventMap, RoomVersion, StateMap}, state_res::{self, Event, EventMap, RoomVersion, StateMap},
uint, EventId, RoomId, RoomVersionId, ServerName, ServerSigningKeyId, UserId, uint, EventId, MilliSecondsSinceUnixEpoch, RoomId, RoomVersionId, ServerName,
ServerSigningKeyId, UserId,
}; };
use std::{ use std::{
collections::{btree_map::Entry, BTreeMap, BTreeSet, HashSet}, collections::{btree_map::Entry, BTreeMap, BTreeSet, HashSet},
@ -49,8 +55,9 @@ use std::{
pin::Pin, pin::Pin,
result::Result as StdResult, result::Result as StdResult,
sync::{Arc, RwLock}, sync::{Arc, RwLock},
time::{Duration, SystemTime}, time::{Duration, Instant, SystemTime},
}; };
use tokio::sync::Semaphore;
#[cfg(feature = "conduit_bin")] #[cfg(feature = "conduit_bin")]
use rocket::{get, post, put}; use rocket::{get, post, put};
@ -452,7 +459,10 @@ pub fn get_server_keys_route(db: State<'_, Database>) -> Json<String> {
verify_keys, verify_keys,
old_verify_keys: BTreeMap::new(), old_verify_keys: BTreeMap::new(),
signatures: BTreeMap::new(), signatures: BTreeMap::new(),
valid_until_ts: SystemTime::now() + Duration::from_secs(60 * 2), valid_until_ts: MilliSecondsSinceUnixEpoch::from_system_time(
SystemTime::now() + Duration::from_secs(60 * 2),
)
.expect("time is valid"),
}, },
} }
.try_into_http_response::<Vec<u8>>() .try_into_http_response::<Vec<u8>>()
@ -608,6 +618,7 @@ pub async fn send_transaction_message_route<'a>(
} }
}; };
let start_time = Instant::now();
if let Err(e) = handle_incoming_pdu( if let Err(e) = handle_incoming_pdu(
&body.origin, &body.origin,
&event_id, &event_id,
@ -619,7 +630,17 @@ pub async fn send_transaction_message_route<'a>(
) )
.await .await
{ {
resolved_map.insert(event_id, Err(e)); resolved_map.insert(event_id.clone(), Err(e));
}
let elapsed = start_time.elapsed();
if elapsed > Duration::from_secs(1) {
warn!(
"Handling event {} took {}m{}s",
event_id,
elapsed.as_secs() / 60,
elapsed.as_secs() % 60
);
} }
} }
@ -653,19 +674,16 @@ pub async fn send_transaction_message_route<'a>(
let mut user_receipts = BTreeMap::new(); let mut user_receipts = BTreeMap::new();
user_receipts.insert(user_id.clone(), user_updates.data); user_receipts.insert(user_id.clone(), user_updates.data);
let mut receipt_content = BTreeMap::new(); let mut receipts = BTreeMap::new();
receipt_content.insert( receipts.insert(ReceiptType::Read, user_receipts);
event_id.to_owned(),
ruma::events::receipt::Receipts {
read: Some(user_receipts),
},
);
let event = let mut receipt_content = BTreeMap::new();
EduEvent::Ephemeral(AnyEphemeralRoomEvent::Receipt(ReceiptEvent { receipt_content.insert(event_id.to_owned(), receipts);
content: ReceiptEventContent(receipt_content),
room_id: room_id.clone(), let event = AnyEphemeralRoomEvent::Receipt(ReceiptEvent {
})); content: ReceiptEventContent(receipt_content),
room_id: room_id.clone(),
});
db.rooms.edus.readreceipt_update( db.rooms.edus.readreceipt_update(
&user_id, &user_id,
&room_id, &room_id,
@ -698,6 +716,8 @@ pub async fn send_transaction_message_route<'a>(
} }
} }
info!("/send/{} done", body.transaction_id);
Ok(send_transaction_message::v1::Response { pdus: resolved_map }.into()) Ok(send_transaction_message::v1::Response { pdus: resolved_map }.into())
} }
@ -794,7 +814,7 @@ pub fn handle_incoming_pdu<'a>(
) { ) {
Err(e) => { Err(e) => {
// Drop // Drop
warn!("{:?}: {}", value, e); warn!("Dropping bad event {}: {}", event_id, e);
return Err("Signature verification failed".to_string()); return Err("Signature verification failed".to_string());
} }
Ok(ruma::signatures::Verified::Signatures) => { Ok(ruma::signatures::Verified::Signatures) => {
@ -821,6 +841,7 @@ pub fn handle_incoming_pdu<'a>(
// 4. fetch any missing auth events doing all checks listed here starting at 1. These are not timeline events // 4. fetch any missing auth events doing all checks listed here starting at 1. These are not timeline events
// 5. Reject "due to auth events" if can't get all the auth events or some of the auth events are also rejected "due to auth events" // 5. Reject "due to auth events" if can't get all the auth events or some of the auth events are also rejected "due to auth events"
// EDIT: Step 5 is not applied anymore because it failed too often
debug!("Fetching auth events for {}", incoming_pdu.event_id); debug!("Fetching auth events for {}", incoming_pdu.event_id);
fetch_and_handle_events( fetch_and_handle_events(
db, db,
@ -1292,12 +1313,30 @@ pub(crate) fn fetch_and_handle_events<'a>(
auth_cache: &'a mut EventMap<Arc<PduEvent>>, auth_cache: &'a mut EventMap<Arc<PduEvent>>,
) -> AsyncRecursiveResult<'a, Vec<Arc<PduEvent>>, Error> { ) -> AsyncRecursiveResult<'a, Vec<Arc<PduEvent>>, Error> {
Box::pin(async move { Box::pin(async move {
let back_off = |id| match db.globals.bad_event_ratelimiter.write().unwrap().entry(id) {
Entry::Vacant(e) => {
e.insert((Instant::now(), 1));
}
Entry::Occupied(mut e) => *e.get_mut() = (Instant::now(), e.get().1 + 1),
};
let mut pdus = vec![]; let mut pdus = vec![];
for id in events { for id in events {
if let Some((time, tries)) = db.globals.bad_event_ratelimiter.read().unwrap().get(&id) {
// Exponential backoff
let mut min_elapsed_duration = Duration::from_secs(30) * (*tries) * (*tries);
if min_elapsed_duration > Duration::from_secs(60 * 60 * 24) {
min_elapsed_duration = Duration::from_secs(60 * 60 * 24);
}
if time.elapsed() < min_elapsed_duration {
debug!("Backing off from {}", id);
continue;
}
}
// a. Look at auth cache // a. Look at auth cache
let pdu = match auth_cache.get(id) { let pdu = match auth_cache.get(id) {
Some(pdu) => { Some(pdu) => {
debug!("Found {} in cache", id);
// We already have the auth chain for events in cache // We already have the auth chain for events in cache
pdu.clone() pdu.clone()
} }
@ -1306,7 +1345,7 @@ pub(crate) fn fetch_and_handle_events<'a>(
// (get_pdu checks both) // (get_pdu checks both)
None => match db.rooms.get_pdu(&id)? { None => match db.rooms.get_pdu(&id)? {
Some(pdu) => { Some(pdu) => {
debug!("Found {} in db", id); trace!("Found {} in db", id);
// We need to fetch the auth chain // We need to fetch the auth chain
let _ = fetch_and_handle_events( let _ = fetch_and_handle_events(
db, db,
@ -1331,7 +1370,7 @@ pub(crate) fn fetch_and_handle_events<'a>(
.await .await
{ {
Ok(res) => { Ok(res) => {
debug!("Got {} over federation: {:?}", id, res); debug!("Got {} over federation", id);
let (event_id, mut value) = let (event_id, mut value) =
crate::pdu::gen_event_id_canonical_json(&res.pdu)?; crate::pdu::gen_event_id_canonical_json(&res.pdu)?;
// This will also fetch the auth chain // This will also fetch the auth chain
@ -1358,12 +1397,14 @@ pub(crate) fn fetch_and_handle_events<'a>(
} }
Err(e) => { Err(e) => {
warn!("Authentication of event {} failed: {:?}", id, e); warn!("Authentication of event {} failed: {:?}", id, e);
back_off(id.clone());
continue; continue;
} }
} }
} }
Err(_) => { Err(_) => {
warn!("Failed to fetch event: {}", id); warn!("Failed to fetch event: {}", id);
back_off(id.clone());
continue; continue;
} }
} }
@ -1383,10 +1424,67 @@ pub(crate) fn fetch_and_handle_events<'a>(
pub(crate) async fn fetch_signing_keys( pub(crate) async fn fetch_signing_keys(
db: &Database, db: &Database,
origin: &ServerName, origin: &ServerName,
signature_ids: Vec<&String>, signature_ids: Vec<String>,
) -> Result<BTreeMap<String, String>> { ) -> Result<BTreeMap<String, String>> {
let contains_all_ids = let contains_all_ids =
|keys: &BTreeMap<String, String>| signature_ids.iter().all(|&id| keys.contains_key(id)); |keys: &BTreeMap<String, String>| signature_ids.iter().all(|id| keys.contains_key(id));
let permit = db
.globals
.servername_ratelimiter
.read()
.unwrap()
.get(origin)
.map(|s| Arc::clone(s).acquire_owned());
let permit = match permit {
Some(p) => p,
None => {
let mut write = db.globals.servername_ratelimiter.write().unwrap();
let s = Arc::clone(
write
.entry(origin.to_owned())
.or_insert_with(|| Arc::new(Semaphore::new(1))),
);
s.acquire_owned()
}
}
.await;
let back_off = |id| match db
.globals
.bad_signature_ratelimiter
.write()
.unwrap()
.entry(id)
{
Entry::Vacant(e) => {
e.insert((Instant::now(), 1));
}
Entry::Occupied(mut e) => *e.get_mut() = (Instant::now(), e.get().1 + 1),
};
if let Some((time, tries)) = db
.globals
.bad_signature_ratelimiter
.read()
.unwrap()
.get(&signature_ids)
{
// Exponential backoff
let mut min_elapsed_duration = Duration::from_secs(30) * (*tries) * (*tries);
if min_elapsed_duration > Duration::from_secs(60 * 60 * 24) {
min_elapsed_duration = Duration::from_secs(60 * 60 * 24);
}
if time.elapsed() < min_elapsed_duration {
debug!("Backing off from {:?}", signature_ids);
return Err(Error::BadServerResponse("bad signature, still backing off"));
}
}
debug!("Loading signing keys for {}", origin);
let mut result = db let mut result = db
.globals .globals
@ -1399,6 +1497,8 @@ pub(crate) async fn fetch_signing_keys(
return Ok(result); return Ok(result);
} }
debug!("Fetching signing keys for {} over federation", origin);
if let Ok(get_keys_response) = db if let Ok(get_keys_response) = db
.sending .sending
.send_federation_request(&db.globals, origin, get_server_keys::v2::Request::new()) .send_federation_request(&db.globals, origin, get_server_keys::v2::Request::new())
@ -1436,14 +1536,17 @@ pub(crate) async fn fetch_signing_keys(
&server, &server,
get_remote_server_keys::v2::Request::new( get_remote_server_keys::v2::Request::new(
origin, origin,
SystemTime::now() MilliSecondsSinceUnixEpoch::from_system_time(
.checked_add(Duration::from_secs(3600)) SystemTime::now()
.expect("SystemTime to large"), .checked_add(Duration::from_secs(3600))
.expect("SystemTime to large"),
)
.expect("time is valid"),
), ),
) )
.await .await
{ {
debug!("Got signing keys: {:?}", keys); trace!("Got signing keys: {:?}", keys);
for k in keys.server_keys { for k in keys.server_keys {
db.globals.add_signing_key(origin, &k)?; db.globals.add_signing_key(origin, &k)?;
result.extend( result.extend(
@ -1464,6 +1567,10 @@ pub(crate) async fn fetch_signing_keys(
} }
} }
drop(permit);
back_off(signature_ids);
warn!("Failed to find public key for server: {}", origin); warn!("Failed to find public key for server: {}", origin);
Err(Error::BadServerResponse( Err(Error::BadServerResponse(
"Failed to find public key for server", "Failed to find public key for server",
@ -1581,7 +1688,7 @@ pub fn get_event_route<'a>(
Ok(get_event::v1::Response { Ok(get_event::v1::Response {
origin: db.globals.server_name().to_owned(), origin: db.globals.server_name().to_owned(),
origin_server_ts: SystemTime::now(), origin_server_ts: MilliSecondsSinceUnixEpoch::now(),
pdu: PduEvent::convert_to_outgoing_federation_event( pdu: PduEvent::convert_to_outgoing_federation_event(
db.rooms db.rooms
.get_pdu_json(&body.event_id)? .get_pdu_json(&body.event_id)?
@ -2186,6 +2293,34 @@ pub fn get_profile_information_route<'a>(
.into()) .into())
} }
#[cfg_attr(
feature = "conduit_bin",
post("/_matrix/federation/v1/user/keys/query", data = "<body>")
)]
#[tracing::instrument(skip(db, body))]
pub fn get_keys_route<'a>(
db: State<'a, Database>,
body: Ruma<get_keys::v1::Request>,
) -> ConduitResult<get_keys::v1::Response> {
if !db.globals.allow_federation() {
return Err(Error::bad_config("Federation is disabled."));
}
let result = get_keys_helper(
None,
&body.device_keys,
|u| Some(u.server_name()) == body.sender_servername.as_deref(),
&db,
)?;
Ok(get_keys::v1::Response {
device_keys: result.device_keys,
master_keys: result.master_keys,
self_signing_keys: result.self_signing_keys,
}
.into())
}
pub async fn fetch_required_signing_keys( pub async fn fetch_required_signing_keys(
event: &BTreeMap<String, CanonicalJsonValue>, event: &BTreeMap<String, CanonicalJsonValue>,
pub_key_map: &RwLock<BTreeMap<String, BTreeMap<String, String>>>, pub_key_map: &RwLock<BTreeMap<String, BTreeMap<String, String>>>,
@ -2208,9 +2343,8 @@ pub async fn fetch_required_signing_keys(
"Invalid signatures content object in server response pdu.", "Invalid signatures content object in server response pdu.",
))?; ))?;
let signature_ids = signature_object.keys().collect::<Vec<_>>(); let signature_ids = signature_object.keys().cloned().collect::<Vec<_>>();
debug!("Fetching signing keys for {}", signature_server);
let fetch_res = fetch_signing_keys( let fetch_res = fetch_signing_keys(
db, db,
&Box::<ServerName>::try_from(&**signature_server).map_err(|_| { &Box::<ServerName>::try_from(&**signature_server).map_err(|_| {