compiler error I guess?
This commit is contained in:
parent
10d48a91c3
commit
165d8bb729
12 changed files with 536 additions and 37 deletions
283
Cargo.lock
generated
283
Cargo.lock
generated
|
@ -17,6 +17,41 @@ version = "1.0.2"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
|
||||
|
||||
[[package]]
|
||||
name = "aead"
|
||||
version = "0.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d122413f284cf2d62fb1b7db97e02edb8cda96d769b16e443a4f6195e35662b0"
|
||||
dependencies = [
|
||||
"crypto-common",
|
||||
"generic-array",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "aes"
|
||||
version = "0.8.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ac1f845298e95f983ff1944b728ae08b8cebab80d684f0a832ed0fc74dfa27e2"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"cipher",
|
||||
"cpufeatures",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "aes-gcm"
|
||||
version = "0.10.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "831010a0f742e1209b3bcea8fab6a8e149051ba6099432c8cb2cc117dec3ead1"
|
||||
dependencies = [
|
||||
"aead",
|
||||
"aes",
|
||||
"cipher",
|
||||
"ctr",
|
||||
"ghash",
|
||||
"subtle",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "aho-corasick"
|
||||
version = "1.1.2"
|
||||
|
@ -32,6 +67,18 @@ version = "1.0.75"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6"
|
||||
|
||||
[[package]]
|
||||
name = "argon2"
|
||||
version = "0.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "17ba4cac0a46bc1d2912652a751c47f2a9f3a7fe89bcae2275d418f5270402f9"
|
||||
dependencies = [
|
||||
"base64ct",
|
||||
"blake2",
|
||||
"cpufeatures",
|
||||
"password-hash",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "async-trait"
|
||||
version = "0.1.74"
|
||||
|
@ -99,6 +146,26 @@ dependencies = [
|
|||
"tower-service",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "axum_csrf"
|
||||
version = "0.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7c0ccdf64283e19f1ee0c4180f216ba28eedef4696dc3ee947e1dc01b3486960"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"axum-core",
|
||||
"base64ct",
|
||||
"cookie",
|
||||
"hmac",
|
||||
"http",
|
||||
"rand",
|
||||
"sha2",
|
||||
"thiserror",
|
||||
"time",
|
||||
"tower-layer",
|
||||
"tower-service",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "backtrace"
|
||||
version = "0.3.69"
|
||||
|
@ -120,6 +187,12 @@ version = "0.21.5"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "35636a1494ede3b646cc98f74f8e62c773a38a659ebc777a2cf26b9b74171df9"
|
||||
|
||||
[[package]]
|
||||
name = "base64ct"
|
||||
version = "1.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b"
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "1.3.2"
|
||||
|
@ -132,6 +205,15 @@ version = "2.4.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07"
|
||||
|
||||
[[package]]
|
||||
name = "blake2"
|
||||
version = "0.10.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "46502ad458c9a52b69d4d4d32775c788b7a1b85e8bc9d482d92250fc0e3f8efe"
|
||||
dependencies = [
|
||||
"digest",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "block-buffer"
|
||||
version = "0.10.4"
|
||||
|
@ -162,6 +244,33 @@ version = "1.0.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||
|
||||
[[package]]
|
||||
name = "cipher"
|
||||
version = "0.4.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad"
|
||||
dependencies = [
|
||||
"crypto-common",
|
||||
"inout",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cookie"
|
||||
version = "0.18.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3cd91cf61412820176e137621345ee43b3f4423e589e7ae4e50d601d93e35ef8"
|
||||
dependencies = [
|
||||
"aes-gcm",
|
||||
"base64",
|
||||
"hmac",
|
||||
"percent-encoding",
|
||||
"rand",
|
||||
"sha2",
|
||||
"subtle",
|
||||
"time",
|
||||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cpufeatures"
|
||||
version = "0.2.11"
|
||||
|
@ -197,9 +306,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3"
|
||||
dependencies = [
|
||||
"generic-array",
|
||||
"rand_core",
|
||||
"typenum",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ctr"
|
||||
version = "0.9.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0369ee1ad671834580515889b80f2ea915f23b8be8d0daa4bbaf2ac5c7590835"
|
||||
dependencies = [
|
||||
"cipher",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "deadpool"
|
||||
version = "0.10.0"
|
||||
|
@ -261,6 +380,7 @@ dependencies = [
|
|||
"diesel_derives",
|
||||
"libsqlite3-sys",
|
||||
"time",
|
||||
"uuid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -303,6 +423,7 @@ checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292"
|
|||
dependencies = [
|
||||
"block-buffer",
|
||||
"crypto-common",
|
||||
"subtle",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -396,6 +517,27 @@ dependencies = [
|
|||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "getrandom"
|
||||
version = "0.2.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fe9006bed769170c11f845cf00c7c1e9092aeb3f268e007c3e760ac68008070f"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"wasi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ghash"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d930750de5717d2dd0b8c0d42c076c0e884c81a73e6cab859bbd2339c71e3e40"
|
||||
dependencies = [
|
||||
"opaque-debug",
|
||||
"polyval",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gimli"
|
||||
version = "0.28.0"
|
||||
|
@ -438,6 +580,15 @@ version = "0.3.3"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d77f7ec81a6d05a3abb01ab6eb7590f6083d08449fe5a1c8b1e620283546ccb7"
|
||||
|
||||
[[package]]
|
||||
name = "hmac"
|
||||
version = "0.12.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e"
|
||||
dependencies = [
|
||||
"digest",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "http"
|
||||
version = "0.2.10"
|
||||
|
@ -531,6 +682,15 @@ dependencies = [
|
|||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "inout"
|
||||
version = "0.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5"
|
||||
dependencies = [
|
||||
"generic-array",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "1.0.9"
|
||||
|
@ -600,7 +760,11 @@ name = "lyrs"
|
|||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"argon2",
|
||||
"axum",
|
||||
"axum_csrf",
|
||||
"base64",
|
||||
"cookie",
|
||||
"deadpool",
|
||||
"deadpool-diesel",
|
||||
"diesel",
|
||||
|
@ -608,6 +772,7 @@ dependencies = [
|
|||
"maud",
|
||||
"notify",
|
||||
"serde",
|
||||
"thiserror",
|
||||
"tokio",
|
||||
"tower-http",
|
||||
"tower-livereload",
|
||||
|
@ -770,6 +935,12 @@ version = "1.18.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d"
|
||||
|
||||
[[package]]
|
||||
name = "opaque-debug"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5"
|
||||
|
||||
[[package]]
|
||||
name = "overload"
|
||||
version = "0.1.1"
|
||||
|
@ -799,6 +970,17 @@ dependencies = [
|
|||
"windows-targets",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "password-hash"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "346f04948ba92c43e8469c1ee6736c7563d71012b17d40745260fe106aac2166"
|
||||
dependencies = [
|
||||
"base64ct",
|
||||
"rand_core",
|
||||
"subtle",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "percent-encoding"
|
||||
version = "2.3.0"
|
||||
|
@ -843,12 +1025,30 @@ version = "0.3.27"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964"
|
||||
|
||||
[[package]]
|
||||
name = "polyval"
|
||||
version = "0.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d52cff9d1d4dee5fe6d03729099f4a310a41179e0a10dbf542039873f2e826fb"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"cpufeatures",
|
||||
"opaque-debug",
|
||||
"universal-hash",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "powerfmt"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391"
|
||||
|
||||
[[package]]
|
||||
name = "ppv-lite86"
|
||||
version = "0.2.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro-error"
|
||||
version = "1.0.4"
|
||||
|
@ -891,6 +1091,36 @@ dependencies = [
|
|||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand"
|
||||
version = "0.8.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"rand_chacha",
|
||||
"rand_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_chacha"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
|
||||
dependencies = [
|
||||
"ppv-lite86",
|
||||
"rand_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_core"
|
||||
version = "0.6.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
|
||||
dependencies = [
|
||||
"getrandom",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "redox_syscall"
|
||||
version = "0.3.5"
|
||||
|
@ -1059,6 +1289,17 @@ dependencies = [
|
|||
"digest",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sha2"
|
||||
version = "0.10.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"cpufeatures",
|
||||
"digest",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sharded-slab"
|
||||
version = "0.1.7"
|
||||
|
@ -1103,6 +1344,12 @@ dependencies = [
|
|||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "subtle"
|
||||
version = "2.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc"
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "1.0.109"
|
||||
|
@ -1131,6 +1378,26 @@ version = "0.1.2"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160"
|
||||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "1.0.50"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f9a7210f5c9a7156bb50aa36aed4c95afb51df0df00713949448cf9e97d382d2"
|
||||
dependencies = [
|
||||
"thiserror-impl",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror-impl"
|
||||
version = "1.0.50"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "266b2e40bc00e5a6c09c3584011e08b06f123c00362c92b975ba9843aaaa14b8"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.39",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thread_local"
|
||||
version = "1.1.7"
|
||||
|
@ -1403,6 +1670,22 @@ version = "1.0.12"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
|
||||
|
||||
[[package]]
|
||||
name = "universal-hash"
|
||||
version = "0.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fc1de2c688dc15305988b563c3854064043356019f97a4b46276fe734c4f07ea"
|
||||
dependencies = [
|
||||
"crypto-common",
|
||||
"subtle",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "uuid"
|
||||
version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "88ad59a7560b41a70d191093a945f0b87bc1deeda46fb237479708a1d6b6cdfc"
|
||||
|
||||
[[package]]
|
||||
name = "valuable"
|
||||
version = "0.1.0"
|
||||
|
|
26
Cargo.toml
26
Cargo.toml
|
@ -5,16 +5,30 @@ edition = "2021"
|
|||
|
||||
[dependencies]
|
||||
anyhow = "1.0.75"
|
||||
|
||||
# web
|
||||
axum = { version = "0.6.20", features = ["headers"] }
|
||||
deadpool = "0.10.0"
|
||||
deadpool-diesel = { version = "0.5.0", features = ["rt_tokio_1", "sqlite", "tracing", "serde"] }
|
||||
diesel = { version = "2.1.3", features = ["sqlite"] }
|
||||
diesel_migrations = { version = "2.1.0", features = ["sqlite"] }
|
||||
axum_csrf = { version = "0.8.0", features = ["layer"] }
|
||||
base64 = "0.21.5"
|
||||
cookie = "0.18.0"
|
||||
maud = "0.25.0"
|
||||
notify = "6.1.1"
|
||||
serde = { version = "1.0.192", features = ["derive"] }
|
||||
tokio = { version = "1.34.0", features = ["full", "macros", "rt-multi-thread"] }
|
||||
tower-http = { version = "0.4.4", features = ["fs"] }
|
||||
tower-livereload = "0.8.2"
|
||||
|
||||
# instrumentation
|
||||
tracing = "0.1.40"
|
||||
tracing-subscriber = { version = "0.3.17", features = ["env-filter"] }
|
||||
|
||||
# database
|
||||
deadpool = "0.10.0"
|
||||
deadpool-diesel = { version = "0.5.0", features = ["rt_tokio_1", "sqlite", "tracing", "serde"] }
|
||||
diesel = { version = "2.1.3", features = ["sqlite", "uuid"] }
|
||||
diesel_migrations = { version = "2.1.0", features = ["sqlite"] }
|
||||
|
||||
# fancy during-development stuff
|
||||
notify = "6.1.1"
|
||||
tower-livereload = "0.8.2"
|
||||
argon2 = { version = "0.5.2", features = ["std"] }
|
||||
thiserror = "1.0.50"
|
||||
|
||||
|
|
|
@ -98,6 +98,7 @@ textarea:not([rows]) {
|
|||
|
||||
:root {
|
||||
--font: monospace;
|
||||
--br: 3px;
|
||||
|
||||
/* catppuccin latte */
|
||||
--Rosewater: #dc8a78;
|
||||
|
@ -171,6 +172,32 @@ ol {
|
|||
padding-left: 2ex;
|
||||
}
|
||||
|
||||
input {
|
||||
padding: 1ex 2ex;
|
||||
background-color: var(--Surface0);
|
||||
border: solid 1px var(--Surface2);
|
||||
border-radius: var(--br);
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
input:hover {
|
||||
border: solid 1px var(--Overlay0);
|
||||
/* background-color: var(--Surface0); */
|
||||
}
|
||||
|
||||
button {
|
||||
cursor: pointer;
|
||||
padding: 1ex 2ex;
|
||||
background-color: var(--Surface0);
|
||||
border: 0;
|
||||
border-radius: var(--br);
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
button:hover {
|
||||
background-color: var(--Surface1);
|
||||
}
|
||||
|
||||
html {
|
||||
background-color: var(--bg);
|
||||
color: var(--text);
|
||||
|
@ -197,7 +224,7 @@ body>header a:not([class]) {
|
|||
display: flex;
|
||||
align-items: center;
|
||||
padding: 1ex 2ex;
|
||||
transition: color 0.1s ease-out, background-color 0.1s ease-out;
|
||||
/* transition: color 0.1s ease-out, background-color 0.1s ease-out; */
|
||||
text-decoration: none;
|
||||
color: var(--primary);
|
||||
gap: 0.5ex;
|
||||
|
@ -214,7 +241,7 @@ main.prose {
|
|||
text-decoration: none;
|
||||
color: currentColor;
|
||||
box-shadow: 0 -1px 1px var(--Mantle);
|
||||
border-radius: 2px;
|
||||
border-radius: var(--br);
|
||||
}
|
||||
|
||||
body>header a:hover {
|
||||
|
@ -225,4 +252,16 @@ body>header a:hover {
|
|||
.bg-primary {
|
||||
background-color: var(--primary);
|
||||
color: var(--bg);
|
||||
}
|
||||
|
||||
form {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 2ex;
|
||||
}
|
||||
|
||||
form>label {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.5ex;
|
||||
}
|
|
@ -59,6 +59,7 @@
|
|||
RUST_SRC_PATH = rustPlatform.rustLibSrc;
|
||||
shellHook = ''
|
||||
export DATABASE_URL="sqlite://./data/lyrs.sqlitedb";
|
||||
export COOKIE_KEY="2z49_8yfKUkoTOo0cjzzjwufCfhKvfOIc1CGleuTXC5zRqY4U0Xhkd34ipREQN5iHRH62tt5O7y6U5mmFBH3MA"
|
||||
'';
|
||||
};
|
||||
});
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
create table users (
|
||||
id text primary key,
|
||||
username text
|
||||
name text,
|
||||
hashed_password binary
|
||||
)
|
||||
password_digest binary
|
||||
);
|
||||
create unique index users_username on users(username);
|
||||
|
|
25
src/error.rs
Normal file
25
src/error.rs
Normal file
|
@ -0,0 +1,25 @@
|
|||
use axum::{
|
||||
http::StatusCode,
|
||||
response::{IntoResponse, Response},
|
||||
};
|
||||
|
||||
pub struct AppError(anyhow::Error);
|
||||
|
||||
impl IntoResponse for AppError {
|
||||
fn into_response(self) -> Response {
|
||||
(
|
||||
StatusCode::INTERNAL_SERVER_ERROR,
|
||||
format!("Something went wrong: {}", self.0),
|
||||
)
|
||||
.into_response()
|
||||
}
|
||||
}
|
||||
|
||||
impl<E> From<E> for AppError
|
||||
where
|
||||
E: Into<anyhow::Error>,
|
||||
{
|
||||
fn from(err: E) -> Self {
|
||||
Self(err.into())
|
||||
}
|
||||
}
|
|
@ -5,8 +5,10 @@
|
|||
|
||||
mod app;
|
||||
mod database;
|
||||
mod error;
|
||||
mod feather_icons;
|
||||
mod instrumentation;
|
||||
mod models;
|
||||
mod partials;
|
||||
mod router;
|
||||
mod schema;
|
||||
|
|
23
src/models.rs
Normal file
23
src/models.rs
Normal file
|
@ -0,0 +1,23 @@
|
|||
use diesel::prelude::*;
|
||||
|
||||
#[derive(Queryable, Selectable)]
|
||||
#[diesel(table_name = crate::schema::users)]
|
||||
#[diesel(check_for_backend(diesel::sqlite::Sqlite))]
|
||||
pub struct User {
|
||||
// pub id: Text,
|
||||
// pub username: sql_types::Text,
|
||||
// pub name: sql_types::Text,
|
||||
// pub password_digest: sql_types::Binary,
|
||||
pub id: Vec<u8>,
|
||||
pub username: String,
|
||||
pub name: Option<String>,
|
||||
pub password_digest: Vec<u8>,
|
||||
}
|
||||
|
||||
#[derive(Insertable)]
|
||||
#[diesel(table_name = crate::schema::users)]
|
||||
pub struct NewUser<'a> {
|
||||
pub username: &'a str,
|
||||
pub name: Option<&'a str>,
|
||||
pub password_digest: &'a [u8],
|
||||
}
|
|
@ -1,12 +1,26 @@
|
|||
use std::{path::Path, sync::Arc};
|
||||
use std::{env, path::Path, sync::Arc};
|
||||
|
||||
use axum::{http::StatusCode, routing::get, Router};
|
||||
use argon2::{
|
||||
password_hash::{rand_core::OsRng, SaltString},
|
||||
Argon2, PasswordHasher,
|
||||
};
|
||||
use axum::{
|
||||
http::StatusCode,
|
||||
response::{Html, IntoResponse, Response},
|
||||
routing::get,
|
||||
Form, Router,
|
||||
};
|
||||
use axum_csrf::{CsrfConfig, CsrfLayer, CsrfToken};
|
||||
use maud::html;
|
||||
use notify::Watcher;
|
||||
use serde::Deserialize;
|
||||
use tower_http::services::ServeDir;
|
||||
use tower_livereload::LiveReloadLayer;
|
||||
use tracing::instrument;
|
||||
|
||||
use crate::{state::State, views};
|
||||
use base64::prelude::*;
|
||||
|
||||
use crate::{error::AppError, models::NewUser, state::State, views};
|
||||
|
||||
#[instrument]
|
||||
pub async fn new() -> Result<Router, anyhow::Error> {
|
||||
|
@ -23,14 +37,73 @@ pub async fn new() -> Result<Router, anyhow::Error> {
|
|||
let mut watcher = notify::recommended_watcher(move |_| reloader.reload())?;
|
||||
watcher.watch(Path::new("assets"), notify::RecursiveMode::Recursive)?;
|
||||
|
||||
let cookie_key_bytes: Vec<u8> = BASE64_URL_SAFE_NO_PAD
|
||||
.decode(env::var("COOKIE_KEY").expect("COOKIE_KEY not set"))
|
||||
.expect("COOKIE_KEY not base64 URL-safe encoded");
|
||||
let cookie_key = cookie::Key::from(&cookie_key_bytes);
|
||||
let csrf_config = CsrfConfig::default().with_key(Some(cookie_key));
|
||||
|
||||
let router = Router::new()
|
||||
.fallback(|| async { (StatusCode::NOT_FOUND, "404 page not found") })
|
||||
.nest("/app", app_router)
|
||||
.nest_service("/assets", assets_dir)
|
||||
.route("/", get(views::index))
|
||||
.route("/register", get(views::register))
|
||||
.route("/register", get(views::register).post(register))
|
||||
.with_state(state)
|
||||
.layer(CsrfLayer::new(csrf_config))
|
||||
.layer(live_reload_layer);
|
||||
|
||||
Ok(router)
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
struct Register {
|
||||
authenticity_token: String,
|
||||
username: String,
|
||||
password: String,
|
||||
}
|
||||
|
||||
impl<'a> TryInto<NewUser<'a>> for Register {
|
||||
type Error = ();
|
||||
|
||||
fn try_into(self) -> Result<NewUser<'a>, Self::Error> {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
async fn register(
|
||||
csrf_token: CsrfToken,
|
||||
Form(register): Form<Register>,
|
||||
) -> Result<impl IntoResponse, AppError> {
|
||||
// TODO: https://docs.rs/axum_csrf/latest/axum_csrf/#prevent-post-replay-attacks-with-csrf
|
||||
|
||||
let v = csrf_token.verify(®ister.authenticity_token);
|
||||
println!("{:?} {:?}", register.authenticity_token, v);
|
||||
if v.is_err() {
|
||||
return Ok((
|
||||
StatusCode::BAD_REQUEST,
|
||||
Html(html! { "invalid request" }.into_string()),
|
||||
));
|
||||
}
|
||||
|
||||
let salt = SaltString::generate(&mut OsRng);
|
||||
let argon2 = Argon2::default();
|
||||
let password_digest = argon2.hash_password(register.password.as_bytes(), &salt)?;
|
||||
|
||||
let new_user = NewUser {
|
||||
username: ®ister.username,
|
||||
name: None,
|
||||
password_digest: password_digest.to_string().as_bytes(),
|
||||
};
|
||||
|
||||
Ok((
|
||||
StatusCode::CREATED,
|
||||
Html(
|
||||
html! {
|
||||
h1 { (register.username) }
|
||||
h1 { (register.password) }
|
||||
}
|
||||
.into_string(),
|
||||
),
|
||||
))
|
||||
}
|
||||
|
|
|
@ -2,8 +2,9 @@
|
|||
|
||||
diesel::table! {
|
||||
users (id) {
|
||||
id -> Nullable<Text>,
|
||||
id -> Binary,
|
||||
username -> Text,
|
||||
name -> Nullable<Text>,
|
||||
hashed_password -> Nullable<Binary>,
|
||||
password_digest -> Binary,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@ impl State {
|
|||
pub async fn new() -> Result<Self, anyhow::Error> {
|
||||
let database_url = env::var("DATABASE_URL").expect("DATABASE_URL must be set");
|
||||
let database = database::Database::new(database_url).await?;
|
||||
|
||||
Ok(State { database })
|
||||
}
|
||||
}
|
||||
|
|
77
src/views.rs
77
src/views.rs
|
@ -1,4 +1,5 @@
|
|||
use axum::response::Html;
|
||||
use axum::response::{Html, IntoResponse};
|
||||
use axum_csrf::CsrfToken;
|
||||
use maud::html;
|
||||
use tracing::instrument;
|
||||
|
||||
|
@ -21,7 +22,7 @@ pub async fn index() -> Html<String> {
|
|||
li { "Lightweight and fast" }
|
||||
}
|
||||
section class="flex gap" {
|
||||
button hx-get="/register" hx-target="body>main" hx-push-url="true" class="button bg-primary" { "Try now" }
|
||||
a href="/register" class="button bg-primary" { "Try now" }
|
||||
a class="button" href="/login" { "Login" }
|
||||
}
|
||||
}
|
||||
|
@ -31,27 +32,61 @@ pub async fn index() -> Html<String> {
|
|||
)
|
||||
}
|
||||
|
||||
#[instrument]
|
||||
pub async fn register() -> Html<String> {
|
||||
Html(
|
||||
html! {
|
||||
h1 { "Register an account" }
|
||||
p { "Stop struggling to share the same messy set of PowerPoint files or Google Presentations. Make editing and controlling your live lyrics and music displays easy and simple." }
|
||||
ul {
|
||||
li { "Live collaboration with your team" }
|
||||
li { "Fully compatible with any device" }
|
||||
li { "Simple workflow" }
|
||||
li { "Dark theme and light theme" }
|
||||
li { "Generous free plan" }
|
||||
li { "Lightweight and fast" }
|
||||
pub async fn register(csrf: CsrfToken) -> impl IntoResponse {
|
||||
let token = csrf.authenticity_token().unwrap();
|
||||
(
|
||||
csrf,
|
||||
Html(
|
||||
html! {
|
||||
(header())
|
||||
main class="prose" {
|
||||
h1 { "Register an account" }
|
||||
form method="post" {
|
||||
input type="hidden" name="authenticity_token" value=(token) {}
|
||||
label {
|
||||
"Username:"
|
||||
input name="username" {}
|
||||
}
|
||||
label {
|
||||
"Password:"
|
||||
input type="password" name="password" {}
|
||||
}
|
||||
button type="submit" { "Create Account" }
|
||||
}
|
||||
}
|
||||
(footer())
|
||||
}
|
||||
section class="flex gap" {
|
||||
a class="button bg-primary" href="/register/anonymous" { "Try now" }
|
||||
a class="button" href="/login" { "Login" }
|
||||
}
|
||||
}
|
||||
.into_string(),
|
||||
.into_string(),
|
||||
),
|
||||
)
|
||||
.into_response()
|
||||
}
|
||||
|
||||
pub async fn login(csrf: CsrfToken) -> impl IntoResponse {
|
||||
let token = csrf.authenticity_token().unwrap();
|
||||
(
|
||||
csrf,
|
||||
Html(
|
||||
html! {
|
||||
(header())
|
||||
main class="prose" {
|
||||
h1 { "Login" }
|
||||
form method="post" {
|
||||
input type="hidden" name="authenticity_token" value=(token) {}
|
||||
label {
|
||||
input {}
|
||||
}
|
||||
label {
|
||||
input {}
|
||||
}
|
||||
}
|
||||
}
|
||||
(footer())
|
||||
}
|
||||
.into_string(),
|
||||
),
|
||||
)
|
||||
.into_response()
|
||||
}
|
||||
|
||||
#[instrument]
|
||||
|
|
Loading…
Reference in a new issue