🏡 index : ~doyle/titanirc.git

author Jordan Doyle <jordan@doyle.la> 2021-02-03 0:28:26.0 +00:00:00
committer Jordan Doyle <jordan@doyle.la> 2021-02-03 0:28:26.0 +00:00:00
commit
64f4743053dc7efcfb2ecdf391c652877f2e0abc [patch]
tree
f4753dbe8ac2a3b2c3aec445281bbf76b60e76f0
parent
6f724edc12b3dbf7c76b27525d74516227d4ec5b
download
64f4743053dc7efcfb2ecdf391c652877f2e0abc.tar.gz

Implement user authentication



Diff

 Cargo.lock                                    | 403 +++++++++------------------
 config.toml                                   |   3 +-
 titanirc-server/Cargo.toml                    |   3 +-
 titanirc-server/migrations/001_initial.sql    |  35 ++-
 titanirc-server/src/config.rs                 |   1 +-
 titanirc-server/src/entities/user/commands.rs |  18 +-
 titanirc-server/src/entities/user/mod.rs      |  15 +-
 titanirc-server/src/main.rs                   |  18 +-
 titanirc-server/src/models/mod.rs             |   3 +-
 titanirc-server/src/models/user.rs            |  48 +++-
 titanirc-server/src/server.rs                 |  62 +++-
 titanirc-types/src/protocol/commands.rs       |   1 +-
 titanirc-types/src/protocol/primitives.rs     |  27 ++-
 13 files changed, 363 insertions(+), 274 deletions(-)

diff --git a/Cargo.lock b/Cargo.lock
index dcd6b0f..22fe269 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -9,7 +9,7 @@ dependencies = [
 "actix-rt",
 "actix_derive",
 "bitflags",
 "bytes 1.0.1",
 "bytes",
 "crossbeam-channel",
 "futures-core",
 "futures-sink",
@@ -17,9 +17,9 @@ dependencies = [
 "log",
 "once_cell",
 "parking_lot",
 "pin-project-lite 0.2.4",
 "pin-project-lite",
 "smallvec",
 "tokio 1.1.1",
 "tokio",
 "tokio-util",
 "trust-dns-proto",
 "trust-dns-resolver",
@@ -52,7 +52,22 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac24f3f660d4c394cc6d24272e526083c257d6045d3be76a9d0a76be5cb56515"
dependencies = [
 "actix-macros 0.2.0-beta.1",
 "tokio 1.1.1",
 "tokio",
]

[[package]]
name = "actix-threadpool"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d209f04d002854b9afd3743032a27b066158817965bf5d036824d19ac2cc0e30"
dependencies = [
 "derive_more",
 "futures-channel",
 "lazy_static",
 "log",
 "num_cpus",
 "parking_lot",
 "threadpool",
]

[[package]]
@@ -153,7 +168,7 @@ checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
dependencies = [
 "hermit-abi",
 "libc",
 "winapi 0.3.9",
 "winapi",
]

[[package]]
@@ -164,9 +179,20 @@ checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"

[[package]]
name = "base64"
version = "0.12.3"
version = "0.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3441f0f7b02788e948e47f457ca01f1d7e6d92c693bc132c22b087d3141c03ff"
checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd"

[[package]]
name = "bcrypt"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a4d0faafe9e089674fc3efdb311ff5253d445c79d85d1d28bd3ace76d45e7164"
dependencies = [
 "base64",
 "blowfish",
 "getrandom",
]

[[package]]
name = "bitflags"
@@ -196,6 +222,17 @@ dependencies = [
]

[[package]]
name = "blowfish"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "32fa6a061124e37baba002e496d203e23ba3d7b73750be82dbfbc92913048a5b"
dependencies = [
 "byteorder",
 "cipher",
 "opaque-debug",
]

[[package]]
name = "build_const"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -215,39 +252,11 @@ checksum = "ae44d1a3d5a19df61dd0c8beb138458ac2a53a7ac09eba97d55592540004306b"

[[package]]
name = "bytes"
version = "0.5.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0e4cec68f03f32e44924783795810fa50a7035d8c8ebe78580ad7e6c703fba38"

[[package]]
name = "bytes"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b700ce4376041dcd0a327fd0097c41095743c4c8af8887265942faf1100bd040"

[[package]]
name = "cargo-platform"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0226944a63d1bf35a3b5f948dd7c59e263db83695c9e8bffc4037de02e30f1d7"
dependencies = [
 "serde",
]

[[package]]
name = "cargo_metadata"
version = "0.12.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7714a157da7991e23d90686b9524b9e12e0407a108647f52e9328f4b3d51ac7f"
dependencies = [
 "cargo-platform",
 "semver",
 "semver-parser",
 "serde",
 "serde_json",
]

[[package]]
name = "cc"
version = "1.0.66"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -266,6 +275,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"

[[package]]
name = "cipher"
version = "0.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "12f8e7987cbd042a63249497f41aed09f8e65add917ea6566effbc56578d6801"
dependencies = [
 "generic-array",
]

[[package]]
name = "clap"
version = "3.0.0-beta.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -415,22 +433,6 @@ dependencies = [
]

[[package]]
name = "fuchsia-zircon"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82"
dependencies = [
 "bitflags",
 "fuchsia-zircon-sys",
]

[[package]]
name = "fuchsia-zircon-sys"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7"

[[package]]
name = "funty"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -524,7 +526,7 @@ dependencies = [
 "futures-sink",
 "futures-task",
 "memchr",
 "pin-project-lite 0.2.4",
 "pin-project-lite",
 "pin-utils",
 "proc-macro-hack",
 "proc-macro-nested",
@@ -602,7 +604,7 @@ checksum = "3c731c3e10504cc8ed35cfe2f1db4c9274c3d35fa486e3b31df46f068ef3e867"
dependencies = [
 "libc",
 "match_cfg",
 "winapi 0.3.9",
 "winapi",
]

[[package]]
@@ -636,15 +638,6 @@ dependencies = [
]

[[package]]
name = "iovec"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b2b3ea6ff95e175473f8ffe6a7eb7c00d054240321b84c57051175fe3c1e075e"
dependencies = [
 "libc",
]

[[package]]
name = "ipconfig"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -652,7 +645,7 @@ checksum = "f7e2f18aece9709094573a9f24f483c4f65caa4298e2f7ae1b71cc65d853fad7"
dependencies = [
 "socket2",
 "widestring",
 "winapi 0.3.9",
 "winapi",
 "winreg",
]

@@ -678,16 +671,6 @@ dependencies = [
]

[[package]]
name = "kernel32-sys"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d"
dependencies = [
 "winapi 0.2.8",
 "winapi-build",
]

[[package]]
name = "lazy_static"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -713,6 +696,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1cca32fa0182e8c0989459524dc356b8f2b5c10f1b9eb521b7d182c03cf8c5ff"

[[package]]
name = "libsqlite3-sys"
version = "0.20.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "64d31059f22935e6c31830db5249ba2b7ecd54fd73a9909286f0a67aa55c2fbd"
dependencies = [
 "cc",
 "pkg-config",
 "vcpkg",
]

[[package]]
name = "linked-hash-map"
version = "0.5.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -771,57 +765,15 @@ checksum = "0ee1c47aaa256ecabcaea351eae4a9b01ef39ed810004e298d2511ed284b1525"

[[package]]
name = "mio"
version = "0.6.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4afd66f5b91bf2a3bc13fad0e21caedac168ca4c707504e75585648ae80e4cc4"
dependencies = [
 "cfg-if 0.1.10",
 "fuchsia-zircon",
 "fuchsia-zircon-sys",
 "iovec",
 "kernel32-sys",
 "libc",
 "log",
 "miow 0.2.2",
 "net2",
 "slab",
 "winapi 0.2.8",
]

[[package]]
name = "mio"
version = "0.7.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e50ae3f04d169fcc9bde0b547d1c205219b7157e07ded9c5aff03e0637cb3ed7"
dependencies = [
 "libc",
 "log",
 "miow 0.3.6",
 "miow",
 "ntapi",
 "winapi 0.3.9",
]

[[package]]
name = "mio-uds"
version = "0.6.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "afcb699eb26d4332647cc848492bbc15eafb26f08d0304550d5aa1f612e066f0"
dependencies = [
 "iovec",
 "libc",
 "mio 0.6.23",
]

[[package]]
name = "miow"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ebd808424166322d4a38da87083bfddd3ac4c131334ed55856112eb06d46944d"
dependencies = [
 "kernel32-sys",
 "net2",
 "winapi 0.2.8",
 "ws2_32-sys",
 "winapi",
]

[[package]]
@@ -831,18 +783,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5a33c1b55807fbed163481b5ba66db4b2fa6cde694a5027be10fb724206c5897"
dependencies = [
 "socket2",
 "winapi 0.3.9",
]

[[package]]
name = "net2"
version = "0.2.37"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "391630d12b68002ae1e25e8f974306474966550ad82dac6886fb8910c19568ae"
dependencies = [
 "cfg-if 0.1.10",
 "libc",
 "winapi 0.3.9",
 "winapi",
]

[[package]]
@@ -862,7 +803,7 @@ name = "nom-bytes"
version = "0.1.0"
source = "git+https://github.com/w4/nom-bytes#7e44afde2e53f447fc9c77297eb513186b8fb0da"
dependencies = [
 "bytes 1.0.1",
 "bytes",
 "nom",
]

@@ -872,7 +813,7 @@ version = "0.3.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3f6bb902e437b6d86e03cce10a7e2af662292c5dfef23b65899ea3ac9354ad44"
dependencies = [
 "winapi 0.3.9",
 "winapi",
]

[[package]]
@@ -934,7 +875,7 @@ dependencies = [
 "libc",
 "redox_syscall",
 "smallvec",
 "winapi 0.3.9",
 "winapi",
]

[[package]]
@@ -950,21 +891,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e"

[[package]]
name = "pest"
version = "2.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "10f4872ae94d7b90ae48754df22fd42ad52ce740b8f370b03da4835417403e53"
dependencies = [
 "ucd-trie",
]

[[package]]
name = "pin-project-lite"
version = "0.1.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c917123afa01924fc84bb20c4c03f004d9c38e5127e3c039bbf7f4b9c76a2f6b"

[[package]]
name = "pin-project-lite"
version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -977,6 +903,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"

[[package]]
name = "pkg-config"
version = "0.3.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3831453b3449ceb48b6d9c7ad7c96d5ea673e9b470a1dc578c2ce6521230884c"

[[package]]
name = "ppv-lite86"
version = "0.2.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1134,14 +1066,14 @@ dependencies = [
 "spin",
 "untrusted",
 "web-sys",
 "winapi 0.3.9",
 "winapi",
]

[[package]]
name = "rustls"
version = "0.18.1"
version = "0.19.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5d1126dcf58e93cee7d098dbda643b5f92ed724f1f6a63007c1116eed6700c81"
checksum = "064fd21ff87c6e87ed4506e68beb42459caa4a0e2eb144932e6776768556980b"
dependencies = [
 "base64",
 "log",
@@ -1173,25 +1105,6 @@ dependencies = [
]

[[package]]
name = "semver"
version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f301af10236f6df4160f7c3f04eec6dbc70ace82d23326abad5edee88801c6b6"
dependencies = [
 "semver-parser",
 "serde",
]

[[package]]
name = "semver-parser"
version = "0.10.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "00b0bef5b7f9e0df16536d3961cfb6e84331c065b4066afb39768d0e319411f7"
dependencies = [
 "pest",
]

[[package]]
name = "serde"
version = "1.0.123"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1212,17 +1125,6 @@ dependencies = [
]

[[package]]
name = "serde_json"
version = "1.0.61"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4fceb2595057b6891a4ee808f70054bd2d12f0e97f1cbb78689b59f676df325a"
dependencies = [
 "itoa",
 "ryu",
 "serde",
]

[[package]]
name = "sha2"
version = "0.9.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1264,7 +1166,7 @@ checksum = "122e570113d28d773067fab24266b66753f6ea915758651696b6e35e49f88d6e"
dependencies = [
 "cfg-if 1.0.0",
 "libc",
 "winapi 0.3.9",
 "winapi",
]

[[package]]
@@ -1289,8 +1191,7 @@ dependencies = [
[[package]]
name = "sqlx"
version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e1a98f9bf17b690f026b6fec565293a995b46dfbd6293debcb654dcffd2d1b34"
source = "git+https://github.com/launchbadge/sqlx#31abe22e348d6ac668c140de32612f0930c2abec"
dependencies = [
 "sqlx-core",
 "sqlx-macros",
@@ -1299,14 +1200,13 @@ dependencies = [
[[package]]
name = "sqlx-core"
version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "36bb6a2ca3345a86493bc3b71eabc2c6c16a8bb1aa476cf5303bee27f67627d7"
source = "git+https://github.com/launchbadge/sqlx#31abe22e348d6ac668c140de32612f0930c2abec"
dependencies = [
 "ahash 0.6.3",
 "atoi",
 "bitflags",
 "byteorder",
 "bytes 0.5.6",
 "bytes",
 "crc",
 "crossbeam-channel",
 "crossbeam-queue",
@@ -1319,6 +1219,7 @@ dependencies = [
 "hex",
 "itoa",
 "libc",
 "libsqlite3-sys",
 "log",
 "memchr",
 "once_cell",
@@ -1331,6 +1232,7 @@ dependencies = [
 "sqlx-rt",
 "stringprep",
 "thiserror",
 "tokio-stream",
 "url",
 "webpki",
 "webpki-roots",
@@ -1340,15 +1242,12 @@ dependencies = [
[[package]]
name = "sqlx-macros"
version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2b5ada8b3b565331275ce913368565a273a74faf2a34da58c4dc010ce3286844"
source = "git+https://github.com/launchbadge/sqlx#31abe22e348d6ac668c140de32612f0930c2abec"
dependencies = [
 "cargo_metadata",
 "dotenv",
 "either",
 "futures",
 "heck",
 "lazy_static",
 "proc-macro2",
 "quote",
 "sha2",
@@ -1361,11 +1260,12 @@ dependencies = [
[[package]]
name = "sqlx-rt"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "63fc5454c9dd7aaea3a0eeeb65ca40d06d0d8e7413a8184f7c3a3ffa5056190b"
source = "git+https://github.com/launchbadge/sqlx#31abe22e348d6ac668c140de32612f0930c2abec"
dependencies = [
 "actix-rt",
 "actix-threadpool",
 "once_cell",
 "tokio 0.2.25",
 "tokio",
 "tokio-rustls",
]

@@ -1456,6 +1356,15 @@ dependencies = [
]

[[package]]
name = "threadpool"
version = "1.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d050e60b33d41c19108b32cea32164033a9013fe3b46cbd4457559bfbf77afaa"
dependencies = [
 "num_cpus",
]

[[package]]
name = "tinyvec"
version = "1.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1474,7 +1383,7 @@ checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c"
name = "titanirc-codec"
version = "0.1.0"
dependencies = [
 "bytes 1.0.1",
 "bytes",
 "nom",
 "titanirc-types",
 "tokio-util",
@@ -1488,7 +1397,8 @@ dependencies = [
 "actix-rt",
 "arc-swap",
 "async-stream",
 "bytes 1.0.1",
 "bcrypt",
 "bytes",
 "clap",
 "derive_more",
 "displaydoc",
@@ -1498,7 +1408,7 @@ dependencies = [
 "thiserror",
 "titanirc-codec",
 "titanirc-types",
 "tokio 1.1.1",
 "tokio",
 "tokio-util",
 "toml",
 "uuid",
@@ -1509,7 +1419,7 @@ name = "titanirc-types"
version = "0.1.0"
dependencies = [
 "arc-swap",
 "bytes 1.0.1",
 "bytes",
 "derive_more",
 "nom",
 "nom-bytes",
@@ -1518,64 +1428,43 @@ dependencies = [

[[package]]
name = "tokio"
version = "0.2.25"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6703a273949a90131b290be1fe7b039d0fc884aa1935860dfcbe056f28cd8092"
dependencies = [
 "bytes 0.5.6",
 "futures-core",
 "iovec",
 "lazy_static",
 "libc",
 "memchr",
 "mio 0.6.23",
 "mio-uds",
 "num_cpus",
 "pin-project-lite 0.1.11",
 "slab",
 "tokio-macros",
]

[[package]]
name = "tokio"
version = "1.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6714d663090b6b0acb0fa85841c6d66233d150cdb2602c8f9b8abb03370beb3f"
dependencies = [
 "autocfg",
 "bytes 1.0.1",
 "bytes",
 "libc",
 "memchr",
 "mio 0.7.7",
 "mio",
 "num_cpus",
 "once_cell",
 "parking_lot",
 "pin-project-lite 0.2.4",
 "pin-project-lite",
 "signal-hook-registry",
 "winapi 0.3.9",
 "winapi",
]

[[package]]
name = "tokio-macros"
version = "0.2.6"
name = "tokio-rustls"
version = "0.22.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e44da00bfc73a25f814cd8d7e57a68a5c31b74b3152a0a1d1f590c97ed06265a"
checksum = "bc6844de72e57df1980054b38be3a9f4702aba4858be64dd700181a8a6d0e1b6"
dependencies = [
 "proc-macro2",
 "quote",
 "syn",
 "rustls",
 "tokio",
 "webpki",
]

[[package]]
name = "tokio-rustls"
version = "0.14.1"
name = "tokio-stream"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e12831b255bcfa39dc0436b01e19fea231a37db570686c06ee72c423479f889a"
checksum = "76066865172052eb8796c686f0b441a93df8b08d40a950b062ffb9a426f00edd"
dependencies = [
 "futures-core",
 "rustls",
 "tokio 0.2.25",
 "webpki",
 "pin-project-lite",
 "tokio",
]

[[package]]
@@ -1584,12 +1473,12 @@ version = "0.6.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ebb7cb2f00c5ae8df755b252306272cd1790d39728363936e01827e11f0b017b"
dependencies = [
 "bytes 1.0.1",
 "bytes",
 "futures-core",
 "futures-sink",
 "log",
 "pin-project-lite 0.2.4",
 "tokio 1.1.1",
 "pin-project-lite",
 "tokio",
]

[[package]]
@@ -1621,7 +1510,7 @@ dependencies = [
 "rand",
 "smallvec",
 "thiserror",
 "tokio 1.1.1",
 "tokio",
 "url",
]

@@ -1641,7 +1530,7 @@ dependencies = [
 "resolv-conf",
 "smallvec",
 "thiserror",
 "tokio 1.1.1",
 "tokio",
 "trust-dns-proto",
]

@@ -1652,12 +1541,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "373c8a200f9e67a0c95e62a4f52fbf80c23b4381c05a17845531982fa99e6b33"

[[package]]
name = "ucd-trie"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "56dee185309b50d1f11bfedef0fe6d036842e3fb77413abef29f8f8d1c5d4c1c"

[[package]]
name = "unicode-bidi"
version = "0.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1727,6 +1610,12 @@ dependencies = [
]

[[package]]
name = "vcpkg"
version = "0.2.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b00bca6106a5e23f3eee943593759b7fcddb00554332e856d990c893966879fb"

[[package]]
name = "vec_map"
version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1845,12 +1734,6 @@ checksum = "c168940144dd21fd8046987c16a46a33d5fc84eec29ef9dcddc2ac9e31526b7c"

[[package]]
name = "winapi"
version = "0.2.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a"

[[package]]
name = "winapi"
version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
@@ -1860,12 +1743,6 @@ dependencies = [
]

[[package]]
name = "winapi-build"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc"

[[package]]
name = "winapi-i686-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1877,7 +1754,7 @@ version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178"
dependencies = [
 "winapi 0.3.9",
 "winapi",
]

[[package]]
@@ -1892,17 +1769,7 @@ version = "0.6.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b2986deb581c4fe11b621998a5e53361efe6b48a151178d0cd9eeffa4dc6acc9"
dependencies = [
 "winapi 0.3.9",
]

[[package]]
name = "ws2_32-sys"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d59cefebd0c892fa2dd6de581e937301d8552cb44489cdff035c6187cb63fa5e"
dependencies = [
 "winapi 0.2.8",
 "winapi-build",
 "winapi",
]

[[package]]
diff --git a/config.toml b/config.toml
index 0c2a001..696f018 100644
--- a/config.toml
+++ b/config.toml
@@ -1 +1,2 @@
socket_address = "0.0.0.0:6667"
\ No newline at end of file
socket_address = "0.0.0.0:6667"
database_uri = "sqlite::memory:"
\ No newline at end of file
diff --git a/titanirc-server/Cargo.toml b/titanirc-server/Cargo.toml
index 0bcf1c8..e054699 100644
--- a/titanirc-server/Cargo.toml
+++ b/titanirc-server/Cargo.toml
@@ -22,7 +22,8 @@ displaydoc = "0.1"
clap = "3.0.0-beta.2"
futures-util = "0.3"
bytes = "1.0"
bcrypt = "0.9"
uuid = { version = "0.8", features = ["v4"] }
derive_more = "0.99"
arc-swap = "1.2"
sqlx = { version = "0.4", features = [ "runtime-tokio-rustls", "any", "macros", "migrate" ] }
sqlx = { git = "https://github.com/launchbadge/sqlx", features = [ "runtime-actix-rustls", "sqlite" ] }
diff --git a/titanirc-server/migrations/001_initial.sql b/titanirc-server/migrations/001_initial.sql
new file mode 100644
index 0000000..807629f
--- /dev/null
+++ b/titanirc-server/migrations/001_initial.sql
@@ -0,0 +1,35 @@
CREATE TABLE channels (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    name TEXT UNIQUE
);

CREATE TABLE channel_opers (
    channel_id INTEGER NOT NULL,
    user_id INTEGER NOT NULL,
    level INTEGER NOT NULL,
    FOREIGN KEY (channel_id)
        REFERENCES channels (id),
    FOREIGN KEY (user_id)
        REFERENCES users (id)
);

CREATE TABLE bans (
    mask BINARY PRIMARY KEY,
    expires INTEGER,
    created INTEGER DEFAULT CURRENT_TIMESTAMP,
    revoked BOOLEAN DEFAULT false
);

CREATE TABLE users (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    password BINARY(60),
    op BOOLEAN DEFAULT false
);

CREATE TABLE users_aliases (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    nick TEXT UNIQUE,
    user_id INT NOT NULL,
    FOREIGN KEY (user_id)
        REFERENCES users (id)
);
\ No newline at end of file
diff --git a/titanirc-server/src/config.rs b/titanirc-server/src/config.rs
index 22c66cb..0d4711e 100644
--- a/titanirc-server/src/config.rs
+++ b/titanirc-server/src/config.rs
@@ -4,4 +4,5 @@ use std::net::SocketAddr;
#[derive(Debug, Deserialize)]
pub struct Config {
    pub socket_address: SocketAddr,
    pub database_uri: String,
}
diff --git a/titanirc-server/src/entities/user/commands.rs b/titanirc-server/src/entities/user/commands.rs
index af48848..a2a826d 100644
--- a/titanirc-server/src/entities/user/commands.rs
+++ b/titanirc-server/src/entities/user/commands.rs
@@ -5,7 +5,8 @@ use std::{sync::Arc, time::Instant};
use actix::{Actor, AsyncContext, StreamHandler};
use titanirc_types::protocol::{
    commands::{
        Command, JoinCommand, ModeCommand, MotdCommand, NickCommand, PrivmsgCommand, VersionCommand,
        Command, JoinCommand, ModeCommand, MotdCommand, NickCommand, PassCommand, PrivmsgCommand,
        VersionCommand,
    },
    primitives,
    replies::Reply,
@@ -24,6 +25,7 @@ impl StreamHandler<Result<Command<'static>, std::io::Error>> for super::User {
            Ok(Command::Join(v)) => self.handle_cmd(v, ctx),
            Ok(Command::Mode(v)) => self.handle_cmd(v, ctx),
            Ok(Command::Motd(v)) => self.handle_cmd(v, ctx),
            Ok(Command::Pass(v)) => self.handle_cmd(v, ctx),
            Ok(Command::Privmsg(v)) => self.handle_cmd(v, ctx),
            Ok(Command::Version(v)) => self.handle_cmd(v, ctx),
            Ok(Command::Pong(_)) => {}
@@ -36,16 +38,28 @@ impl StreamHandler<Result<Command<'static>, std::io::Error>> for super::User {
// TODO: all the 'raw' writes using byte strings below probably need to
//  be wrapped in something a bit more friendly.

impl CommandHandler<PassCommand<'static>> for super::User {
    fn handle_cmd(&mut self, command: PassCommand<'static>, _ctx: &mut Self::Context) {
        self.password_auth_in_progress = Some(command.password.to_bytes());
    }
}

impl CommandHandler<NickCommand<'static>> for super::User {
    fn handle_cmd(
        &mut self,
        NickCommand { nick, .. }: NickCommand<'static>,
        _ctx: &mut Self::Context,
        ctx: &mut Self::Context,
    ) {
        // TODO: when authenticated, the user should only be allowed to /NICK themselves
        //  to unregistered nicks or aliases.
        self.nick.set(Arc::new(nick.to_bytes()));

        self.server.do_send(crate::server::events::UserAuth {
            nick: nick.to_bytes(),
            user: ctx.address(),
            password: self.password_auth_in_progress.clone().unwrap(),
        });

        self.writer.write(Reply::RplWelcome.into());
        self.writer.write(Reply::RplYourHost.into());
        self.writer.write(Reply::RplCreated.into());
diff --git a/titanirc-server/src/entities/user/mod.rs b/titanirc-server/src/entities/user/mod.rs
index 388c2ac..9657cdc 100644
--- a/titanirc-server/src/entities/user/mod.rs
+++ b/titanirc-server/src/entities/user/mod.rs
@@ -39,6 +39,8 @@ pub struct User {
    pub last_active: Instant,
    pub nick: RegisteredNick,

    pub password_auth_in_progress: Option<bytes::Bytes>,

    pub channels: HashMap<ChannelName, crate::entities::channel::Handle>,
}

@@ -54,6 +56,7 @@ impl User {
            session_id: UserUuid(Uuid::new_v4()),
            server,
            writer,
            password_auth_in_progress: None,
            last_active: Instant::now(),
            nick,
            channels: HashMap::new(),
@@ -87,6 +90,18 @@ impl Actor for User {
/// Handles errors from our socket Writer.
impl WriteHandler<std::io::Error> for User {}

impl actix::Handler<crate::server::events::UserAuthResponse> for User {
    type Result = ();

    fn handle(
        &mut self,
        msg: crate::server::events::UserAuthResponse,
        ctx: &mut Self::Context,
    ) -> Self::Result {
        todo!()
    }
}

impl actix::Handler<crate::entities::channel::Handle> for User {
    type Result = ();

diff --git a/titanirc-server/src/main.rs b/titanirc-server/src/main.rs
index 60522fe..95b5935 100644
--- a/titanirc-server/src/main.rs
+++ b/titanirc-server/src/main.rs
@@ -4,6 +4,7 @@
mod config;
mod entities;
mod error;
mod models;
mod server;

use std::path::PathBuf;
@@ -16,9 +17,12 @@ use crate::{
use actix::{Actor, AsyncContext, System};
use clap::Clap;
use displaydoc::Display;
use sqlx::migrate::Migrator;
use thiserror::Error;
use tokio::net::TcpListener;

static MIGRATOR: Migrator = sqlx::migrate!();

#[derive(Error, Debug, Display)]
pub enum InitError {
    /// Failed to bind to socket: {0}
@@ -27,6 +31,10 @@ pub enum InitError {
    ConfigRead(std::io::Error),
    /// Failed to parse config file: {0}
    ConfigParse(toml::de::Error),
    /// Failed to connect to database: {0}
    SqlConnect(sqlx::Error),
    /// Failed to run migrations against the database: {0}
    SqlMigrate(sqlx::migrate::MigrateError),
}

#[derive(Clap)]
@@ -44,6 +52,14 @@ async fn main() -> Result<()> {
    let config = std::fs::read(&opts.config).map_err(InitError::ConfigRead)?;
    let config: config::Config = toml::from_slice(&config).map_err(InitError::ConfigParse)?;

    let sql_pool = sqlx::SqlitePool::connect(&config.database_uri)
        .await
        .map_err(InitError::SqlConnect)?;
    MIGRATOR
        .run(&sql_pool)
        .await
        .map_err(InitError::SqlMigrate)?;

    let listener = TcpListener::bind(&config.socket_address)
        .await
        .map_err(InitError::TcpBind)?;
@@ -61,7 +77,7 @@ async fn main() -> Result<()> {
    // Spawn the server and pass connections from `stream` to `Handler<Connection>`.
    Server::create(move |ctx| {
        ctx.add_message_stream(stream);
        Server::new()
        Server::new(sql_pool)
    });

    println!("Running IRC server on {}", &config.socket_address);
diff --git a/titanirc-server/src/models/mod.rs b/titanirc-server/src/models/mod.rs
new file mode 100644
index 0000000..4d941e2
--- /dev/null
+++ b/titanirc-server/src/models/mod.rs
@@ -0,0 +1,3 @@
//! Database access models

pub mod user;
diff --git a/titanirc-server/src/models/user.rs b/titanirc-server/src/models/user.rs
new file mode 100644
index 0000000..18f8c27
--- /dev/null
+++ b/titanirc-server/src/models/user.rs
@@ -0,0 +1,48 @@
#[derive(sqlx::FromRow)]
pub struct User {
    id: u64,
    password: String,
    op: bool,
}

impl User {
    pub async fn create_user(
        conn: &sqlx::SqlitePool,
        nick: &[u8],
        password: bytes::Bytes,
    ) -> Result<(), sqlx::Error> {
        let mut tx = conn.begin().await?;

        sqlx::query("INSERT INTO users (password) VALUES (?)")
            .bind(
                tokio::task::spawn_blocking(move || bcrypt::hash(&password, 10).unwrap())
                    .await
                    .unwrap(),
            )
            .execute(&mut tx)
            .await?;

        sqlx::query("INSERT INTO users_aliases (nick, user_id) VALUES (?, LAST_INSERT_ROWID())")
            .bind(nick)
            .execute(&mut tx)
            .await?;

        tx.commit().await?;

        Ok(())
    }

    pub async fn fetch_by_nick(
        conn: &sqlx::SqlitePool,
        nick: &[u8],
    ) -> Result<Option<User>, sqlx::Error> {
        sqlx::query_as::<_, Self>("SELECT * FROM users WHERE users.id = (SELECT user_id FROM users_aliases WHERE nick = ?)")
            .bind(&nick)
            .fetch_optional(conn)
            .await
    }

    pub fn password_matches(&self, password: &[u8]) -> bool {
        bcrypt::verify(password, &self.password).unwrap()
    }
}
diff --git a/titanirc-server/src/server.rs b/titanirc-server/src/server.rs
index 756db93..b3226be 100644
--- a/titanirc-server/src/server.rs
+++ b/titanirc-server/src/server.rs
@@ -17,6 +17,8 @@ use tokio_util::codec::FramedRead;
///
/// Essentially acts as the middleman for each entity communicating with each other.
pub struct Server {
    sql_pool: sqlx::SqlitePool,

    /// A list of known channels and the addresses to them.
    pub channels: HashMap<ChannelName, Addr<Channel>>,
    // A list of known connected users.
@@ -24,8 +26,9 @@ pub struct Server {
}

impl Server {
    pub fn new() -> Self {
    pub fn new(sql_pool: sqlx::SqlitePool) -> Self {
        Self {
            sql_pool,
            channels: HashMap::new(),
            // users: Vec::new(),
        }
@@ -109,3 +112,60 @@ impl Handler<crate::entities::common_events::UserMessage> for Server {
        todo!()
    }
}

impl Handler<events::UserAuth> for Server {
    type Result = ();

    fn handle(&mut self, msg: events::UserAuth, ctx: &mut Self::Context) -> Self::Result {
        let conn = self.sql_pool.clone();

        ctx.spawn(
            async move {
                match crate::models::user::User::fetch_by_nick(&conn, &msg.nick).await {
                    Ok(Some(user)) => {
                        if user.password_matches(&msg.password) {
                            eprintln!("user authed");
                        } else {
                            eprintln!("user not authed");
                        }
                    }
                    Ok(None) => {
                        let passwd = msg.password.clone();
                        if let Err(e) =
                            crate::models::user::User::create_user(&conn, &msg.nick, passwd).await
                        {
                            eprintln!("failed to create user: {:?}", e);
                        } else {
                            eprintln!("successfully registered");
                        }
                    }
                    Err(e) => {
                        eprintln!("failed to fetch by nick: {:?} ", e)
                    }
                }
            }
            .into_actor(self),
        );
    }
}

pub mod events {
    use actix::{Addr, Message};

    use crate::entities::user::User;

    #[derive(Message)]
    #[rtype(result = "")]
    pub struct UserAuth {
        pub user: Addr<User>,
        pub nick: bytes::Bytes,
        pub password: bytes::Bytes,
    }

    #[derive(Message)]
    #[rtype(result = "")]
    pub enum UserAuthResponse {
        Valid,
        InvalidPassword,
    }
}
diff --git a/titanirc-types/src/protocol/commands.rs b/titanirc-types/src/protocol/commands.rs
index dd3e732..45448c9 100644
--- a/titanirc-types/src/protocol/commands.rs
+++ b/titanirc-types/src/protocol/commands.rs
@@ -115,6 +115,7 @@ macro_rules! define_commands {
}

define_commands! {
    PASS(Password<'a>),
    USER(Username<'a>, HostName<'a>, ServerName<'a>, RealName<'a>),
    NICK(Nick<'a>),

diff --git a/titanirc-types/src/protocol/primitives.rs b/titanirc-types/src/protocol/primitives.rs
index 66cf347..9f4cb38 100644
--- a/titanirc-types/src/protocol/primitives.rs
+++ b/titanirc-types/src/protocol/primitives.rs
@@ -95,6 +95,28 @@ macro_rules! free_text_primitive {
    };
}

macro_rules! free_text_primitive_no_colon {
    ($name:ty) => {
        impl PrimitiveParser for $name {
            fn parse(bytes: BytesWrapper) -> IResult<BytesWrapper, Self> {
                Ok((Bytes::new().into(), Self(bytes.into())))
            }
        }

        impl std::fmt::Display for $name {
            fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
                match std::str::from_utf8(&self.0[..]) {
                    Ok(v) => f.write_str(v),
                    Err(_e) => {
                        eprintln!("Invalid utf-8 in {}", stringify!($name));
                        Err(std::fmt::Error)
                    }
                }
            }
        }
    };
}

macro_rules! space_terminated_primitive {
    ($name:ty) => {
        impl PrimitiveParser for $name {
@@ -180,6 +202,11 @@ impl ValidatingParser for Special {
}

#[derive(Debug, Deref, Clone, From)]
pub struct Password<'a>(pub BytesCow<'a>);
free_text_primitive_no_colon!(Password<'_>);
noop_validator!(Password<'_>);

#[derive(Debug, Deref, Clone, From)]
pub struct Username<'a>(pub BytesCow<'a>);
space_terminated_primitive!(Username<'_>);
noop_validator!(Username<'_>);