add initial chat server stuff

This commit is contained in:
sam 2024-01-16 22:20:19 +01:00
parent 3025f1380c
commit 0e71e9dc5f
18 changed files with 722 additions and 40 deletions

496
Cargo.lock generated
View file

@ -30,6 +30,21 @@ dependencies = [
"zerocopy", "zerocopy",
] ]
[[package]]
name = "alloc-no-stdlib"
version = "2.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cc7bb162ec39d46ab1ca8c77bf72e890535becd1751bb45f64c597edb4c8c6b3"
[[package]]
name = "alloc-stdlib"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "94fb8275041c72129eb51b7d0322c29b8387a0386127718b096429201a5d6ece"
dependencies = [
"alloc-no-stdlib",
]
[[package]] [[package]]
name = "allocator-api2" name = "allocator-api2"
version = "0.2.16" version = "0.2.16"
@ -99,6 +114,20 @@ dependencies = [
"windows-sys 0.52.0", "windows-sys 0.52.0",
] ]
[[package]]
name = "async-compression"
version = "0.4.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bc2d0cfb2a7388d34f590e76686704c494ed7aaceed62ee1ba35cbf363abc2a5"
dependencies = [
"brotli",
"flate2",
"futures-core",
"memchr",
"pin-project-lite",
"tokio",
]
[[package]] [[package]]
name = "async-trait" name = "async-trait"
version = "0.1.77" version = "0.1.77"
@ -153,10 +182,10 @@ dependencies = [
"base64", "base64",
"bytes", "bytes",
"futures-util", "futures-util",
"http", "http 1.0.0",
"http-body", "http-body 1.0.0",
"http-body-util", "http-body-util",
"hyper", "hyper 1.1.0",
"hyper-util", "hyper-util",
"itoa", "itoa",
"matchit", "matchit",
@ -188,8 +217,8 @@ dependencies = [
"async-trait", "async-trait",
"bytes", "bytes",
"futures-util", "futures-util",
"http", "http 1.0.0",
"http-body", "http-body 1.0.0",
"http-body-util", "http-body-util",
"mime", "mime",
"pin-project-lite", "pin-project-lite",
@ -286,6 +315,27 @@ dependencies = [
"cipher", "cipher",
] ]
[[package]]
name = "brotli"
version = "3.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "516074a47ef4bce09577a3b379392300159ce5b1ba2e501ff1c819950066100f"
dependencies = [
"alloc-no-stdlib",
"alloc-stdlib",
"brotli-decompressor",
]
[[package]]
name = "brotli-decompressor"
version = "2.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4e2e4afe60d7dd600fdd3de8d0f08c2b7ec039712e3b6137ff98b7004e82de4f"
dependencies = [
"alloc-no-stdlib",
"alloc-stdlib",
]
[[package]] [[package]]
name = "bumpalo" name = "bumpalo"
version = "3.14.0" version = "3.14.0"
@ -322,6 +372,24 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]] [[package]]
name = "chat" name = "chat"
version = "0.1.0" version = "0.1.0"
dependencies = [
"axum",
"clap",
"color-eyre",
"eyre",
"foxchat",
"rand",
"rsa",
"serde",
"serde_json",
"sqlx",
"tokio",
"toml",
"tower-http",
"tracing",
"tracing-subscriber",
"ulid",
]
[[package]] [[package]]
name = "chrono" name = "chrono"
@ -424,6 +492,16 @@ version = "0.9.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8"
[[package]]
name = "core-foundation"
version = "0.9.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f"
dependencies = [
"core-foundation-sys",
"libc",
]
[[package]] [[package]]
name = "core-foundation-sys" name = "core-foundation-sys"
version = "0.8.6" version = "0.8.6"
@ -454,6 +532,15 @@ version = "2.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "19d374276b40fb8bbdee95aef7c7fa6b5316ec764510eb64b8dd0e2ed0d7e7f5" checksum = "19d374276b40fb8bbdee95aef7c7fa6b5316ec764510eb64b8dd0e2ed0d7e7f5"
[[package]]
name = "crc32fast"
version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d"
dependencies = [
"cfg-if",
]
[[package]] [[package]]
name = "crossbeam-queue" name = "crossbeam-queue"
version = "0.3.11" version = "0.3.11"
@ -523,6 +610,15 @@ dependencies = [
"serde", "serde",
] ]
[[package]]
name = "encoding_rs"
version = "0.8.33"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7268b386296a025e474d5140678f75d6de9493ae55a5d709eeb9dd08149945e1"
dependencies = [
"cfg-if",
]
[[package]] [[package]]
name = "equivalent" name = "equivalent"
version = "1.0.1" version = "1.0.1"
@ -578,6 +674,16 @@ 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 = "8fcfdc7a0362c9f4444381a9e697c79d435fe65b52a37466fc2c1184cee9edc6" checksum = "8fcfdc7a0362c9f4444381a9e697c79d435fe65b52a37466fc2c1184cee9edc6"
[[package]]
name = "flate2"
version = "1.0.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "46303f565772937ffe1d394a4fac6f411c6013172fadde9dcdb1e147a086940e"
dependencies = [
"crc32fast",
"miniz_oxide",
]
[[package]] [[package]]
name = "flume" name = "flume"
version = "0.11.0" version = "0.11.0"
@ -595,6 +701,21 @@ version = "1.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
[[package]]
name = "foreign-types"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1"
dependencies = [
"foreign-types-shared",
]
[[package]]
name = "foreign-types-shared"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b"
[[package]] [[package]]
name = "form_urlencoded" name = "form_urlencoded"
version = "1.2.1" version = "1.2.1"
@ -613,6 +734,7 @@ dependencies = [
"serde", "serde",
"serde_json", "serde_json",
"sqlx", "sqlx",
"thiserror",
"tracing", "tracing",
"uuid", "uuid",
] ]
@ -716,6 +838,25 @@ version = "0.28.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253"
[[package]]
name = "h2"
version = "0.3.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b553656127a00601c8ae5590fcfdc118e4083a7924b6cf4ffc1ea4b99dc429d7"
dependencies = [
"bytes",
"fnv",
"futures-core",
"futures-sink",
"futures-util",
"http 0.2.11",
"indexmap",
"slab",
"tokio",
"tokio-util",
"tracing",
]
[[package]] [[package]]
name = "h2" name = "h2"
version = "0.4.1" version = "0.4.1"
@ -727,7 +868,7 @@ dependencies = [
"futures-core", "futures-core",
"futures-sink", "futures-sink",
"futures-util", "futures-util",
"http", "http 1.0.0",
"indexmap", "indexmap",
"slab", "slab",
"tokio", "tokio",
@ -802,6 +943,17 @@ dependencies = [
"windows-sys 0.52.0", "windows-sys 0.52.0",
] ]
[[package]]
name = "http"
version = "0.2.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8947b1a6fad4393052c7ba1f4cd97bed3e953a95c79c92ad9b051a04611d9fbb"
dependencies = [
"bytes",
"fnv",
"itoa",
]
[[package]] [[package]]
name = "http" name = "http"
version = "1.0.0" version = "1.0.0"
@ -813,6 +965,17 @@ dependencies = [
"itoa", "itoa",
] ]
[[package]]
name = "http-body"
version = "0.4.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2"
dependencies = [
"bytes",
"http 0.2.11",
"pin-project-lite",
]
[[package]] [[package]]
name = "http-body" name = "http-body"
version = "1.0.0" version = "1.0.0"
@ -820,7 +983,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1cac85db508abc24a2e48553ba12a996e87244a0395ce011e62b37158745d643" checksum = "1cac85db508abc24a2e48553ba12a996e87244a0395ce011e62b37158745d643"
dependencies = [ dependencies = [
"bytes", "bytes",
"http", "http 1.0.0",
] ]
[[package]] [[package]]
@ -831,8 +994,8 @@ checksum = "41cb79eb393015dadd30fc252023adb0b2400a0caee0fa2a077e6e21a551e840"
dependencies = [ dependencies = [
"bytes", "bytes",
"futures-util", "futures-util",
"http", "http 1.0.0",
"http-body", "http-body 1.0.0",
"pin-project-lite", "pin-project-lite",
] ]
@ -848,6 +1011,30 @@ version = "1.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9"
[[package]]
name = "hyper"
version = "0.14.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bf96e135eb83a2a8ddf766e426a841d8ddd7449d5f00d34ea02b41d2f19eef80"
dependencies = [
"bytes",
"futures-channel",
"futures-core",
"futures-util",
"h2 0.3.23",
"http 0.2.11",
"http-body 0.4.6",
"httparse",
"httpdate",
"itoa",
"pin-project-lite",
"socket2",
"tokio",
"tower-service",
"tracing",
"want",
]
[[package]] [[package]]
name = "hyper" name = "hyper"
version = "1.1.0" version = "1.1.0"
@ -857,9 +1044,9 @@ dependencies = [
"bytes", "bytes",
"futures-channel", "futures-channel",
"futures-util", "futures-util",
"h2", "h2 0.4.1",
"http", "http 1.0.0",
"http-body", "http-body 1.0.0",
"httparse", "httparse",
"httpdate", "httpdate",
"itoa", "itoa",
@ -867,6 +1054,19 @@ dependencies = [
"tokio", "tokio",
] ]
[[package]]
name = "hyper-tls"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905"
dependencies = [
"bytes",
"hyper 0.14.28",
"native-tls",
"tokio",
"tokio-native-tls",
]
[[package]] [[package]]
name = "hyper-util" name = "hyper-util"
version = "0.1.2" version = "0.1.2"
@ -876,9 +1076,9 @@ dependencies = [
"bytes", "bytes",
"futures-channel", "futures-channel",
"futures-util", "futures-util",
"http", "http 1.0.0",
"http-body", "http-body 1.0.0",
"hyper", "hyper 1.1.0",
"pin-project-lite", "pin-project-lite",
"socket2", "socket2",
"tokio", "tokio",
@ -913,16 +1113,18 @@ name = "identity"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"axum", "axum",
"base64",
"bcrypt", "bcrypt",
"clap", "clap",
"color-eyre", "color-eyre",
"dotenvy",
"eyre", "eyre",
"foxchat", "foxchat",
"rand", "rand",
"reqwest",
"rsa", "rsa",
"serde", "serde",
"serde_json", "serde_json",
"sha256",
"sqlx", "sqlx",
"tokio", "tokio",
"toml", "toml",
@ -930,7 +1132,6 @@ dependencies = [
"tracing", "tracing",
"tracing-subscriber", "tracing-subscriber",
"ulid", "ulid",
"uuid",
] ]
[[package]] [[package]]
@ -968,6 +1169,12 @@ dependencies = [
"generic-array", "generic-array",
] ]
[[package]]
name = "ipnet"
version = "2.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3"
[[package]] [[package]]
name = "itertools" name = "itertools"
version = "0.12.0" version = "0.12.0"
@ -1074,6 +1281,16 @@ version = "0.3.17"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a"
[[package]]
name = "mime_guess"
version = "2.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4192263c238a5f0d0c6bfd21f336a313a4ce1c450542449ca191bb657b4642ef"
dependencies = [
"mime",
"unicase",
]
[[package]] [[package]]
name = "minimal-lexical" name = "minimal-lexical"
version = "0.2.1" version = "0.2.1"
@ -1100,6 +1317,24 @@ dependencies = [
"windows-sys 0.48.0", "windows-sys 0.48.0",
] ]
[[package]]
name = "native-tls"
version = "0.2.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "07226173c32f2926027b63cce4bcd8076c3552846cbe7925f3aaffeac0a3b92e"
dependencies = [
"lazy_static",
"libc",
"log",
"openssl",
"openssl-probe",
"openssl-sys",
"schannel",
"security-framework",
"security-framework-sys",
"tempfile",
]
[[package]] [[package]]
name = "nix" name = "nix"
version = "0.27.1" version = "0.27.1"
@ -1205,6 +1440,50 @@ version = "1.19.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92"
[[package]]
name = "openssl"
version = "0.10.62"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8cde4d2d9200ad5909f8dac647e29482e07c3a35de8a13fce7c9c7747ad9f671"
dependencies = [
"bitflags 2.4.1",
"cfg-if",
"foreign-types",
"libc",
"once_cell",
"openssl-macros",
"openssl-sys",
]
[[package]]
name = "openssl-macros"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.48",
]
[[package]]
name = "openssl-probe"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf"
[[package]]
name = "openssl-sys"
version = "0.9.98"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c1665caf8ab2dc9aef43d1c0023bd904633a6a05cb30b0ad59bec2ae986e57a7"
dependencies = [
"cc",
"libc",
"pkg-config",
"vcpkg",
]
[[package]] [[package]]
name = "overload" name = "overload"
version = "0.1.1" version = "0.1.1"
@ -1383,6 +1662,47 @@ dependencies = [
"bitflags 1.3.2", "bitflags 1.3.2",
] ]
[[package]]
name = "reqwest"
version = "0.11.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "37b1ae8d9ac08420c66222fb9096fc5de435c3c48542bc5336c51892cffafb41"
dependencies = [
"async-compression",
"base64",
"bytes",
"encoding_rs",
"futures-core",
"futures-util",
"h2 0.3.23",
"http 0.2.11",
"http-body 0.4.6",
"hyper 0.14.28",
"hyper-tls",
"ipnet",
"js-sys",
"log",
"mime",
"mime_guess",
"native-tls",
"once_cell",
"percent-encoding",
"pin-project-lite",
"serde",
"serde_json",
"serde_urlencoded",
"system-configuration",
"tokio",
"tokio-native-tls",
"tokio-util",
"tower-service",
"url",
"wasm-bindgen",
"wasm-bindgen-futures",
"web-sys",
"winreg",
]
[[package]] [[package]]
name = "ring" name = "ring"
version = "0.17.7" version = "0.17.7"
@ -1480,6 +1800,15 @@ version = "1.0.16"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f98d2aa92eebf49b69786be48e4477826b256916e84a57ff2a4f21923b48eb4c" checksum = "f98d2aa92eebf49b69786be48e4477826b256916e84a57ff2a4f21923b48eb4c"
[[package]]
name = "schannel"
version = "0.1.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fbc91545643bcf3a0bbb6569265615222618bdf33ce4ffbbd13c4bbd4c093534"
dependencies = [
"windows-sys 0.52.0",
]
[[package]] [[package]]
name = "scopeguard" name = "scopeguard"
version = "1.2.0" version = "1.2.0"
@ -1496,6 +1825,29 @@ dependencies = [
"untrusted", "untrusted",
] ]
[[package]]
name = "security-framework"
version = "2.9.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "05b64fb303737d99b81884b2c63433e9ae28abebe5eb5045dcdd175dc2ecf4de"
dependencies = [
"bitflags 1.3.2",
"core-foundation",
"core-foundation-sys",
"libc",
"security-framework-sys",
]
[[package]]
name = "security-framework-sys"
version = "2.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e932934257d3b408ed8f30db49d85ea163bfe74961f017f405b025af298f0c7a"
dependencies = [
"core-foundation-sys",
"libc",
]
[[package]] [[package]]
name = "serde" name = "serde"
version = "1.0.195" version = "1.0.195"
@ -1580,6 +1932,19 @@ dependencies = [
"digest", "digest",
] ]
[[package]]
name = "sha256"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "18278f6a914fa3070aa316493f7d2ddfb9ac86ebc06fa3b83bffda487e9065b0"
dependencies = [
"async-trait",
"bytes",
"hex",
"sha2",
"tokio",
]
[[package]] [[package]]
name = "sharded-slab" name = "sharded-slab"
version = "0.1.7" version = "0.1.7"
@ -1714,7 +2079,6 @@ dependencies = [
"tokio-stream", "tokio-stream",
"tracing", "tracing",
"url", "url",
"uuid",
"webpki-roots", "webpki-roots",
] ]
@ -1798,7 +2162,6 @@ dependencies = [
"stringprep", "stringprep",
"thiserror", "thiserror",
"tracing", "tracing",
"uuid",
"whoami", "whoami",
] ]
@ -1839,7 +2202,6 @@ dependencies = [
"stringprep", "stringprep",
"thiserror", "thiserror",
"tracing", "tracing",
"uuid",
"whoami", "whoami",
] ]
@ -1865,7 +2227,6 @@ dependencies = [
"tracing", "tracing",
"url", "url",
"urlencoding", "urlencoding",
"uuid",
] ]
[[package]] [[package]]
@ -1919,6 +2280,27 @@ version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160"
[[package]]
name = "system-configuration"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7"
dependencies = [
"bitflags 1.3.2",
"core-foundation",
"system-configuration-sys",
]
[[package]]
name = "system-configuration-sys"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a75fb188eb626b924683e3b95e3a48e63551fcfb51949de2f06a9d91dbee93c9"
dependencies = [
"core-foundation-sys",
"libc",
]
[[package]] [[package]]
name = "tempfile" name = "tempfile"
version = "3.9.0" version = "3.9.0"
@ -2005,6 +2387,16 @@ dependencies = [
"syn 2.0.48", "syn 2.0.48",
] ]
[[package]]
name = "tokio-native-tls"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2"
dependencies = [
"native-tls",
"tokio",
]
[[package]] [[package]]
name = "tokio-stream" name = "tokio-stream"
version = "0.1.14" version = "0.1.14"
@ -2100,8 +2492,8 @@ checksum = "0da193277a4e2c33e59e09b5861580c33dd0a637c3883d0fa74ba40c0374af2e"
dependencies = [ dependencies = [
"bitflags 2.4.1", "bitflags 2.4.1",
"bytes", "bytes",
"http", "http 1.0.0",
"http-body", "http-body 1.0.0",
"http-body-util", "http-body-util",
"pin-project-lite", "pin-project-lite",
"tower-layer", "tower-layer",
@ -2189,6 +2581,12 @@ dependencies = [
"tracing-log", "tracing-log",
] ]
[[package]]
name = "try-lock"
version = "0.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b"
[[package]] [[package]]
name = "tungstenite" name = "tungstenite"
version = "0.21.0" version = "0.21.0"
@ -2198,7 +2596,7 @@ dependencies = [
"byteorder", "byteorder",
"bytes", "bytes",
"data-encoding", "data-encoding",
"http", "http 1.0.0",
"httparse", "httparse",
"log", "log",
"rand", "rand",
@ -2224,6 +2622,15 @@ dependencies = [
"serde", "serde",
] ]
[[package]]
name = "unicase"
version = "2.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f7d2d4dafb69621809a81864c9c1b864479e1235c0dd4e199924b9742439ed89"
dependencies = [
"version_check",
]
[[package]] [[package]]
name = "unicode-bidi" name = "unicode-bidi"
version = "0.3.14" version = "0.3.14"
@ -2320,6 +2727,15 @@ version = "0.9.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
[[package]]
name = "want"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e"
dependencies = [
"try-lock",
]
[[package]] [[package]]
name = "wasi" name = "wasi"
version = "0.11.0+wasi-snapshot-preview1" version = "0.11.0+wasi-snapshot-preview1"
@ -2351,6 +2767,18 @@ dependencies = [
"wasm-bindgen-shared", "wasm-bindgen-shared",
] ]
[[package]]
name = "wasm-bindgen-futures"
version = "0.4.40"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bde2032aeb86bdfaecc8b261eef3cba735cc426c1f3a3416d1e0791be95fc461"
dependencies = [
"cfg-if",
"js-sys",
"wasm-bindgen",
"web-sys",
]
[[package]] [[package]]
name = "wasm-bindgen-macro" name = "wasm-bindgen-macro"
version = "0.2.90" version = "0.2.90"
@ -2380,6 +2808,16 @@ version = "0.2.90"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4d91413b1c31d7539ba5ef2451af3f0b833a005eb27a631cec32bc0635a8602b" checksum = "4d91413b1c31d7539ba5ef2451af3f0b833a005eb27a631cec32bc0635a8602b"
[[package]]
name = "web-sys"
version = "0.3.67"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "58cd2333b6e0be7a39605f0e255892fd7418a682d8da8fe042fe25128794d2ed"
dependencies = [
"js-sys",
"wasm-bindgen",
]
[[package]] [[package]]
name = "webpki-roots" name = "webpki-roots"
version = "0.25.3" version = "0.25.3"
@ -2564,6 +3002,16 @@ dependencies = [
"memchr", "memchr",
] ]
[[package]]
name = "winreg"
version = "0.50.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1"
dependencies = [
"cfg-if",
"windows-sys 0.48.0",
]
[[package]] [[package]]
name = "zerocopy" name = "zerocopy"
version = "0.7.32" version = "0.7.32"

View file

@ -6,3 +6,19 @@ edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies] [dependencies]
foxchat = { path = "../foxchat" }
axum = { version = "0.7.4", features = ["macros", "query", "tracing", "ws"] }
clap = { version = "4.4.16", features = ["env", "derive"] }
sqlx = { version = "0.7.3", features = ["runtime-tokio", "tls-rustls", "postgres", "migrate", "chrono", "json"] }
serde = { version = "1.0.195", features = ["derive"] }
serde_json = "1.0.111"
ulid = { version = "1.1.0", features = ["serde"] }
eyre = "0.6.11"
color-eyre = "0.6.2"
rsa = { version = "0.9.6", features = ["serde", "sha2"] }
rand = "0.8.5"
toml = "0.8.8"
tokio = { version = "1.35.1", features = ["macros", "rt-multi-thread"] }
tracing-subscriber = "0.3.18"
tracing = "0.1.40"
tower-http = { version = "0.5.1", features = ["trace"] }

View file

@ -0,0 +1,51 @@
create type instance_status as enum ('active', 'suspended');
create table identity_instances (
id text primary key,
domain text not null unique,
base_url text not null,
public_key text not null,
status instance_status not null default 'active',
reason text
);
create table users (
id text primary key,
instance_id text not null references identity_instances (id) on delete cascade,
remote_user_id text not null,
username text not null,
avatar text -- URL, not hash, as this is a remote file
);
create unique index users_remote_user_id_idx on users (instance_id, remote_user_id);
create unique index users_username_idx on users (instance_id, lower(username));
create table guilds (
id text primary key,
owner_id text not null references users (id) on delete cascade,
name text not null
);
create table guilds_users (
guild_id text not null references guilds (id) on delete cascade,
user_id text not null references users (id) on delete cascade,
primary key (guild_id, user_id)
);
create table channels (
id text primary key,
guild_id text not null references guilds (id) on delete cascade,
name text not null,
topic text
);
create table messages (
id text primary key,
channel_id text not null references channels (id) on delete cascade,
author_id text not null,
updated_at timestamptz not null default now(),
content text not null
);

3
config.chat.toml Normal file
View file

@ -0,0 +1,3 @@
database_url = "postgresql://foxchat:password@localhost/foxchat_chat_dev"
port = 3001
log_level = "DEBUG"

View file

@ -1,3 +1,4 @@
database_url = "postgresql://foxchat:password@localhost/foxchat_ident_dev" database_url = "postgresql://foxchat:password@localhost/foxchat_ident_dev"
port = 3000 port = 3000
log_level = "DEBUG" log_level = "DEBUG"
insecure_requests = true

View file

@ -11,5 +11,6 @@ eyre = "0.6.11"
serde = { version = "1.0.195", features = ["derive"] } serde = { version = "1.0.195", features = ["derive"] }
serde_json = "1.0.111" serde_json = "1.0.111"
sqlx = "0.7.3" sqlx = "0.7.3"
thiserror = "1.0.56"
tracing = "0.1.40" tracing = "0.1.40"
uuid = { version = "1.6.1", features = ["v7"] } uuid = { version = "1.6.1", features = ["v7"] }

7
foxchat/src/error/mod.rs Normal file
View file

@ -0,0 +1,7 @@
use thiserror::Error;
#[derive(Error, Debug, Copy, Clone)]
pub enum QueryError {
#[error("object not found")]
NotFound,
}

View file

@ -8,6 +8,8 @@ use serde::Serialize;
use serde_json::json; use serde_json::json;
use tracing::error; use tracing::error;
use crate::QueryError;
pub struct ApiError { pub struct ApiError {
status: StatusCode, status: StatusCode,
code: ErrorCode, code: ErrorCode,
@ -32,6 +34,7 @@ impl IntoResponse for ApiError {
#[serde(rename_all = "SCREAMING_SNAKE_CASE")] #[serde(rename_all = "SCREAMING_SNAKE_CASE")]
pub enum ErrorCode { pub enum ErrorCode {
InternalServerError, InternalServerError,
ObjectNotFound,
} }
impl From<sqlx::Error> for ApiError { impl From<sqlx::Error> for ApiError {
@ -50,6 +53,11 @@ impl From<sqlx::Error> for ApiError {
impl From<Report> for ApiError { impl From<Report> for ApiError {
fn from(err: Report) -> Self { fn from(err: Report) -> Self {
match err.downcast_ref::<QueryError>() {
Some(e) => return (*e).into(),
None => {}
};
error!("Error in handler: {}", err); error!("Error in handler: {}", err);
ApiError { ApiError {
status: StatusCode::INTERNAL_SERVER_ERROR, status: StatusCode::INTERNAL_SERVER_ERROR,
@ -62,3 +70,15 @@ impl From<Report> for ApiError {
} }
} }
} }
impl From<QueryError> for ApiError {
fn from(err: QueryError) -> Self {
match err {
QueryError::NotFound => ApiError {
status: StatusCode::NOT_FOUND,
code: ErrorCode::ObjectNotFound,
message: "Object not found".into(),
},
}
}
}

View file

@ -1,2 +1,5 @@
pub mod s2s; pub mod error;
pub mod http; pub mod http;
pub mod s2s;
pub use error::QueryError;

View file

@ -9,9 +9,7 @@ edition = "2021"
foxchat = { path = "../foxchat" } foxchat = { path = "../foxchat" }
axum = { version = "0.7.4", features = ["macros", "query", "tracing", "ws"] } axum = { version = "0.7.4", features = ["macros", "query", "tracing", "ws"] }
clap = { version = "4.4.16", features = ["env", "derive"] } clap = { version = "4.4.16", features = ["env", "derive"] }
dotenvy = "0.15.7" sqlx = { version = "0.7.3", features = ["runtime-tokio", "tls-rustls", "postgres", "migrate", "chrono", "json"] }
sqlx = { version = "0.7.3", features = ["runtime-tokio", "tls-rustls", "postgres", "migrate", "uuid", "chrono", "json"] }
uuid = { version = "1.6.1", features = ["v7"] }
serde = { version = "1.0.195", features = ["derive"] } serde = { version = "1.0.195", features = ["derive"] }
serde_json = "1.0.111" serde_json = "1.0.111"
ulid = { version = "1.1.0", features = ["serde"] } ulid = { version = "1.1.0", features = ["serde"] }
@ -25,3 +23,6 @@ tracing-subscriber = "0.3.18"
tracing = "0.1.40" tracing = "0.1.40"
tower-http = { version = "0.5.1", features = ["trace"] } tower-http = { version = "0.5.1", features = ["trace"] }
bcrypt = "0.15.0" bcrypt = "0.15.0"
base64 = "0.21.7"
sha256 = "1.5.0"
reqwest = { version = "0.11.23", features = ["json", "gzip", "brotli", "multipart"] }

View file

@ -0,0 +1,4 @@
create table tokens (
token text primary key,
account_id text not null references accounts (id) on delete cascade
);

View file

@ -12,6 +12,9 @@ pub struct Config {
pub port: u16, pub port: u16,
pub auto_migrate: Option<bool>, pub auto_migrate: Option<bool>,
pub log_level: Option<String>, pub log_level: Option<String>,
/// Whether to try HTTP if a server is not served over HTTPS.
/// This should only be set to `true` in development.
pub insecure_requests: Option<bool>,
} }
impl Config { impl Config {
@ -40,6 +43,11 @@ impl Config {
_ => None _ => None
} }
} }
/// If true, the server will try to identify remote servers over HTTP if they are not available over HTTPS
pub fn should_try_insecure(&self) -> bool {
self.insecure_requests.unwrap_or(false)
}
} }
impl Default for Config { impl Default for Config {
@ -49,6 +57,7 @@ impl Default for Config {
port: 3000, port: 3000,
auto_migrate: None, auto_migrate: None,
log_level: None, log_level: None,
insecure_requests: None,
} }
} }
} }

View file

@ -0,0 +1,83 @@
use base64::prelude::{Engine, BASE64_URL_SAFE_NO_PAD};
use eyre::{Context, Report, Result};
use foxchat::QueryError;
use rand::RngCore;
use sqlx::{PgExecutor, Pool, Postgres};
use crate::model::account::{Account, Role};
pub async fn get_user_by_username_and_password(
pool: Pool<Postgres>,
username: String,
password: String,
) -> Result<Account> {
let account = sqlx::query_as!(
Account,
r#"select
id, username, email, password, role as "role: Role", avatar
from accounts where username = $1"#,
username
)
.fetch_one(&pool)
.await
.map_err(|e| -> Report {
match e {
sqlx::Error::RowNotFound => QueryError::NotFound.into(),
_ => e.into(),
}
})?;
if bcrypt::verify(password, &account.password).map_err(|_| QueryError::NotFound)? {
return Ok(account);
}
Err(QueryError::NotFound.into())
}
pub async fn check_token(pool: &Pool<Postgres>, token: String) -> Result<Account> {
let hash = sha256::digest(token);
let account = sqlx::query_as!(
Account,
r#"select
a.id, a.username, a.email, a.password, a.role as "role: Role", a.avatar
from accounts a
join tokens t on t.account_id = a.id
where t.account_id = $1"#,
hash
)
.fetch_optional(pool)
.await?;
match account {
Some(a) => Ok(a),
None => Err(QueryError::NotFound.into()),
}
}
pub async fn create_token(executor: impl PgExecutor<'_>, user_id: &String) -> Result<String> {
let token = generate_token_string();
let hash = sha256::digest(&token);
sqlx::query!(
"insert into tokens (token, account_id) values ($1, $2)",
hash,
user_id
)
.execute(executor)
.await?;
Ok(token)
}
fn generate_token_string() -> String {
let mut data = [0u8; 32];
rand::thread_rng().fill_bytes(&mut data);
BASE64_URL_SAFE_NO_PAD.encode(data)
}
const PASSWORD_COST: u32 = 12;
pub fn hash_password(password: String) -> Result<String> {
bcrypt::hash(password, PASSWORD_COST).wrap_err("failed to hash password")
}

View file

@ -1,5 +1,9 @@
pub mod account;
pub use account::{check_token, create_token, get_user_by_username_and_password};
use eyre::{OptionExt, Result}; use eyre::{OptionExt, Result};
use rsa::pkcs1::{LineEnding, EncodeRsaPublicKey, EncodeRsaPrivateKey}; use rsa::pkcs1::{EncodeRsaPrivateKey, EncodeRsaPublicKey, LineEnding};
use rsa::{RsaPrivateKey, RsaPublicKey}; use rsa::{RsaPrivateKey, RsaPublicKey};
use sqlx::postgres::PgPoolOptions; use sqlx::postgres::PgPoolOptions;
use sqlx::{Pool, Postgres}; use sqlx::{Pool, Postgres};

View file

@ -1,31 +1,34 @@
use std::sync::Arc; use std::sync::Arc;
use axum::{Extension, Json}; use axum::{Extension, Json};
use eyre::{Context, Result}; use eyre::Result;
use foxchat::http::ApiError; use foxchat::http::ApiError;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use ulid::Ulid; use ulid::Ulid;
use crate::app_state::AppState; use crate::{app_state::AppState, db::{create_token, account::hash_password}};
const PASSWORD_COST: u32 = 12;
pub async fn create_user( pub async fn create_user(
Extension(state): Extension<Arc<AppState>>, Extension(state): Extension<Arc<AppState>>,
Json(data): Json<CreateUserRequest>, Json(data): Json<CreateUserRequest>,
) -> Result<Json<CreateUserResponse>, ApiError> { ) -> Result<Json<CreateUserResponse>, ApiError> {
let password_hash = let mut tx = state.pool.begin().await?;
bcrypt::hash(data.password, PASSWORD_COST).wrap_err("failed to hash password")?;
let password_hash = hash_password(data.password)?;
let account = sqlx::query!( let account = sqlx::query!(
"insert into accounts (id, username, email, password) values ($1, $2, $3, $4) returning id, username", "insert into accounts (id, username, email, password) values ($1, $2, $3, $4) returning id, username",
Ulid::new().to_string(), data.username, data.email, password_hash) Ulid::new().to_string(), data.username, data.email, password_hash)
.fetch_one(&state.pool) .fetch_one(&mut *tx)
.await?; .await?;
let token = create_token(&mut *tx, &account.id).await?;
tx.commit().await?;
Ok(Json(CreateUserResponse { Ok(Json(CreateUserResponse {
id: account.id, id: account.id,
username: account.username, username: account.username,
token,
})) }))
} }
@ -40,4 +43,5 @@ pub struct CreateUserRequest {
pub struct CreateUserResponse { pub struct CreateUserResponse {
pub id: String, pub id: String,
pub username: String, pub username: String,
pub token: String,
} }

View file

@ -1,8 +1,7 @@
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use ulid::Ulid;
pub struct Account { pub struct Account {
pub id: Ulid, pub id: String,
pub username: String, pub username: String,
pub email: String, pub email: String,
pub password: String, pub password: String,

View file

@ -1,8 +1,12 @@
use std::sync::Arc;
use eyre::Result;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use ulid::Ulid;
use crate::app_state::AppState;
pub struct ChatInstance { pub struct ChatInstance {
pub id: Ulid, pub id: String,
pub domain: String, pub domain: String,
pub base_url: String, pub base_url: String,
pub public_key: String, pub public_key: String,
@ -16,3 +20,25 @@ pub enum InstanceStatus {
Active, Active,
Suspended, Suspended,
} }
impl ChatInstance {
pub async fn get(state: Arc<AppState>, domain: String) -> Result<Self> {
if let Some(instance) = sqlx::query_as!(
Self,
r#"select id, domain, base_url, public_key,
status as "status: InstanceStatus", reason
from chat_instances where domain = $1"#,
domain
)
.fetch_optional(&state.pool)
.await?
{
return Ok(instance);
}
// TODO: identify server process
// only try HTTP if `state.config.should_try_insecure()`
todo!()
}
}

View file

@ -9,6 +9,8 @@ pub struct Instance {
} }
impl Instance { impl Instance {
/// Gets the instance's configuration.
/// This is a singleton row that is always present.
pub async fn get(pool: &Pool<Postgres>) -> Result<Self> { pub async fn get(pool: &Pool<Postgres>) -> Result<Self> {
let instance = sqlx::query!("SELECT * FROM instance WHERE id = 1") let instance = sqlx::query!("SELECT * FROM instance WHERE id = 1")
.fetch_one(pool) .fetch_one(pool)