finished move from warp to axum, added nav
This commit is contained in:
		
							parent
							
								
									a5eef831c7
								
							
						
					
					
						commit
						779e4aa2ea
					
				| 
						 | 
				
			
			@ -170,16 +170,6 @@ dependencies = [
 | 
			
		|||
 "generic-array",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "buf_redux"
 | 
			
		||||
version = "0.8.4"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "b953a6887648bb07a535631f2bc00fbdb2a2216f135552cb3f534ed136b9c07f"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "memchr",
 | 
			
		||||
 "safemem",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "bumpalo"
 | 
			
		||||
version = "3.11.0"
 | 
			
		||||
| 
						 | 
				
			
			@ -210,6 +200,17 @@ version = "1.0.0"
 | 
			
		|||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "cookie"
 | 
			
		||||
version = "0.16.0"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "94d4706de1b0fa5b132270cddffa8585166037822e260a944fe161acd137ca05"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "percent-encoding",
 | 
			
		||||
 "time",
 | 
			
		||||
 "version_check",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "cpufeatures"
 | 
			
		||||
version = "0.2.5"
 | 
			
		||||
| 
						 | 
				
			
			@ -277,15 +278,6 @@ version = "0.2.0"
 | 
			
		|||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7"
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "fastrand"
 | 
			
		||||
version = "1.8.0"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "a7a407cfaa3385c4ae6b23e84623d48c2798d06e3e6a1878f7f59f17b3f86499"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "instant",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "flabk"
 | 
			
		||||
version = "0.0.1"
 | 
			
		||||
| 
						 | 
				
			
			@ -304,7 +296,7 @@ dependencies = [
 | 
			
		|||
 "serde_json",
 | 
			
		||||
 "tokio",
 | 
			
		||||
 "tokio-postgres",
 | 
			
		||||
 "warp",
 | 
			
		||||
 "tower-cookies",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
| 
						 | 
				
			
			@ -403,25 +395,6 @@ version = "0.26.2"
 | 
			
		|||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "22030e2c5a68ec659fde1e949a745124b48e6fa8b045b7ed5bd1fe4ccc5c4e5d"
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "h2"
 | 
			
		||||
version = "0.3.14"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "5ca32592cf21ac7ccab1825cd87f6c9b3d9022c44d086172ed0966bec8af30be"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "bytes",
 | 
			
		||||
 "fnv",
 | 
			
		||||
 "futures-core",
 | 
			
		||||
 "futures-sink",
 | 
			
		||||
 "futures-util",
 | 
			
		||||
 "http",
 | 
			
		||||
 "indexmap",
 | 
			
		||||
 "slab",
 | 
			
		||||
 "tokio",
 | 
			
		||||
 "tokio-util 0.7.4",
 | 
			
		||||
 "tracing",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "handlebars"
 | 
			
		||||
version = "4.3.3"
 | 
			
		||||
| 
						 | 
				
			
			@ -436,37 +409,6 @@ dependencies = [
 | 
			
		|||
 "thiserror",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "hashbrown"
 | 
			
		||||
version = "0.12.3"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "headers"
 | 
			
		||||
version = "0.3.8"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "f3e372db8e5c0d213e0cd0b9be18be2aca3d44cf2fe30a9d46a65581cd454584"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "base64",
 | 
			
		||||
 "bitflags",
 | 
			
		||||
 "bytes",
 | 
			
		||||
 "headers-core",
 | 
			
		||||
 "http",
 | 
			
		||||
 "httpdate",
 | 
			
		||||
 "mime",
 | 
			
		||||
 "sha1",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "headers-core"
 | 
			
		||||
version = "0.2.0"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "e7f66481bfee273957b1f20485a4ff3362987f85b2c236580d81b4eb7a326429"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "http",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "hermit-abi"
 | 
			
		||||
version = "0.1.19"
 | 
			
		||||
| 
						 | 
				
			
			@ -535,7 +477,6 @@ dependencies = [
 | 
			
		|||
 "futures-channel",
 | 
			
		||||
 "futures-core",
 | 
			
		||||
 "futures-util",
 | 
			
		||||
 "h2",
 | 
			
		||||
 "http",
 | 
			
		||||
 "http-body",
 | 
			
		||||
 "httparse",
 | 
			
		||||
| 
						 | 
				
			
			@ -549,35 +490,6 @@ dependencies = [
 | 
			
		|||
 "want",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "idna"
 | 
			
		||||
version = "0.3.0"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "e14ddfc70884202db2244c223200c204c2bda1bc6e0998d11b5e024d657209e6"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "unicode-bidi",
 | 
			
		||||
 "unicode-normalization",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "indexmap"
 | 
			
		||||
version = "1.9.1"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "10a35a97730320ffe8e2d410b5d3b69279b98d2c14bdb8b70ea89ecf7888d41e"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "autocfg",
 | 
			
		||||
 "hashbrown",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "instant"
 | 
			
		||||
version = "0.1.12"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "cfg-if",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "itoa"
 | 
			
		||||
version = "1.0.3"
 | 
			
		||||
| 
						 | 
				
			
			@ -690,24 +602,6 @@ dependencies = [
 | 
			
		|||
 "windows-sys",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "multipart"
 | 
			
		||||
version = "0.18.0"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "00dec633863867f29cb39df64a397cdf4a6354708ddd7759f70c7fb51c5f9182"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "buf_redux",
 | 
			
		||||
 "httparse",
 | 
			
		||||
 "log",
 | 
			
		||||
 "mime",
 | 
			
		||||
 "mime_guess",
 | 
			
		||||
 "quick-error",
 | 
			
		||||
 "rand",
 | 
			
		||||
 "safemem",
 | 
			
		||||
 "tempfile",
 | 
			
		||||
 "twoway",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "num-bigint"
 | 
			
		||||
version = "0.2.6"
 | 
			
		||||
| 
						 | 
				
			
			@ -879,7 +773,7 @@ checksum = "1538eb784f07615c6d9a8ab061089c6c54a344c5b4301db51990ca1c241e8c04"
 | 
			
		|||
dependencies = [
 | 
			
		||||
 "once_cell",
 | 
			
		||||
 "pest",
 | 
			
		||||
 "sha-1 0.10.0",
 | 
			
		||||
 "sha-1",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
| 
						 | 
				
			
			@ -978,12 +872,6 @@ dependencies = [
 | 
			
		|||
 "unicode-ident",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "quick-error"
 | 
			
		||||
version = "1.2.3"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0"
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "quote"
 | 
			
		||||
version = "1.0.21"
 | 
			
		||||
| 
						 | 
				
			
			@ -1032,15 +920,6 @@ dependencies = [
 | 
			
		|||
 "bitflags",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "remove_dir_all"
 | 
			
		||||
version = "0.5.3"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "winapi",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "ring"
 | 
			
		||||
version = "0.16.20"
 | 
			
		||||
| 
						 | 
				
			
			@ -1102,12 +981,6 @@ version = "1.0.11"
 | 
			
		|||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "4501abdff3ae82a1c1b477a17252eb69cee9e66eb915c1abaa4f44d873df9f09"
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "safemem"
 | 
			
		||||
version = "0.3.3"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "ef703b7cb59335eae2eb93ceb664c0eb7ea6bf567079d843e09420219668e072"
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "same-file"
 | 
			
		||||
version = "1.0.6"
 | 
			
		||||
| 
						 | 
				
			
			@ -1117,12 +990,6 @@ dependencies = [
 | 
			
		|||
 "winapi-util",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "scoped-tls"
 | 
			
		||||
version = "1.0.0"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "ea6a9290e3c9cf0f18145ef7ffa62d68ee0bf5fcd651017e586dc7fd5da448c2"
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "scopeguard"
 | 
			
		||||
version = "1.1.0"
 | 
			
		||||
| 
						 | 
				
			
			@ -1172,19 +1039,6 @@ dependencies = [
 | 
			
		|||
 "serde",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "sha-1"
 | 
			
		||||
version = "0.9.8"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "99cd6713db3cf16b6c84e06321e049a9b9f699826e16096d23bbcc44d15d51a6"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "block-buffer 0.9.0",
 | 
			
		||||
 "cfg-if",
 | 
			
		||||
 "cpufeatures",
 | 
			
		||||
 "digest 0.9.0",
 | 
			
		||||
 "opaque-debug",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "sha-1"
 | 
			
		||||
version = "0.10.0"
 | 
			
		||||
| 
						 | 
				
			
			@ -1196,17 +1050,6 @@ dependencies = [
 | 
			
		|||
 "digest 0.10.3",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "sha1"
 | 
			
		||||
version = "0.10.4"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "006769ba83e921b3085caa8334186b00cf92b4cb1a6cf4632fbccc8eff5c7549"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "cfg-if",
 | 
			
		||||
 "cpufeatures",
 | 
			
		||||
 "digest 0.10.3",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "sha2"
 | 
			
		||||
version = "0.9.9"
 | 
			
		||||
| 
						 | 
				
			
			@ -1334,20 +1177,6 @@ dependencies = [
 | 
			
		|||
 "unicode-xid",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "tempfile"
 | 
			
		||||
version = "3.3.0"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "5cdb1ef4eaeeaddc8fbd371e5017057064af0911902ef36b39801f67cc6d79e4"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "cfg-if",
 | 
			
		||||
 "fastrand",
 | 
			
		||||
 "libc",
 | 
			
		||||
 "redox_syscall",
 | 
			
		||||
 "remove_dir_all",
 | 
			
		||||
 "winapi",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "thiserror"
 | 
			
		||||
version = "1.0.34"
 | 
			
		||||
| 
						 | 
				
			
			@ -1454,45 +1283,7 @@ dependencies = [
 | 
			
		|||
 "postgres-types",
 | 
			
		||||
 "socket2",
 | 
			
		||||
 "tokio",
 | 
			
		||||
 "tokio-util 0.7.4",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "tokio-stream"
 | 
			
		||||
version = "0.1.9"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "df54d54117d6fdc4e4fea40fe1e4e566b3505700e148a6827e59b34b0d2600d9"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "futures-core",
 | 
			
		||||
 "pin-project-lite",
 | 
			
		||||
 "tokio",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "tokio-tungstenite"
 | 
			
		||||
version = "0.15.0"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "511de3f85caf1c98983545490c3d09685fa8eb634e57eec22bb4db271f46cbd8"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "futures-util",
 | 
			
		||||
 "log",
 | 
			
		||||
 "pin-project",
 | 
			
		||||
 "tokio",
 | 
			
		||||
 "tungstenite",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "tokio-util"
 | 
			
		||||
version = "0.6.10"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "36943ee01a6d67977dd3f84a5a1d2efeb4ada3a1ae771cadfaa535d9d9fc6507"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "bytes",
 | 
			
		||||
 "futures-core",
 | 
			
		||||
 "futures-sink",
 | 
			
		||||
 "log",
 | 
			
		||||
 "pin-project-lite",
 | 
			
		||||
 "tokio",
 | 
			
		||||
 "tokio-util",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
| 
						 | 
				
			
			@ -1525,6 +1316,23 @@ dependencies = [
 | 
			
		|||
 "tracing",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "tower-cookies"
 | 
			
		||||
version = "0.7.0"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "19833e336396f3953e5ab1513d72b5e5ea51d5ad39b78d306766a05740b48b97"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "async-trait",
 | 
			
		||||
 "axum-core",
 | 
			
		||||
 "cookie",
 | 
			
		||||
 "futures-util",
 | 
			
		||||
 "http",
 | 
			
		||||
 "parking_lot",
 | 
			
		||||
 "pin-project-lite",
 | 
			
		||||
 "tower-layer",
 | 
			
		||||
 "tower-service",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "tower-http"
 | 
			
		||||
version = "0.3.4"
 | 
			
		||||
| 
						 | 
				
			
			@ -1583,34 +1391,6 @@ version = "0.2.3"
 | 
			
		|||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642"
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "tungstenite"
 | 
			
		||||
version = "0.14.0"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "a0b2d8558abd2e276b0a8df5c05a2ec762609344191e5fd23e292c910e9165b5"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "base64",
 | 
			
		||||
 "byteorder",
 | 
			
		||||
 "bytes",
 | 
			
		||||
 "http",
 | 
			
		||||
 "httparse",
 | 
			
		||||
 "log",
 | 
			
		||||
 "rand",
 | 
			
		||||
 "sha-1 0.9.8",
 | 
			
		||||
 "thiserror",
 | 
			
		||||
 "url",
 | 
			
		||||
 "utf-8",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "twoway"
 | 
			
		||||
version = "0.1.8"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "59b11b2b5241ba34be09c3cc85a36e56e48f9888862e19cedf23336d35316ed1"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "memchr",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "typenum"
 | 
			
		||||
version = "1.15.0"
 | 
			
		||||
| 
						 | 
				
			
			@ -1665,23 +1445,6 @@ version = "0.7.1"
 | 
			
		|||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a"
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "url"
 | 
			
		||||
version = "2.3.1"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "0d68c799ae75762b8c3fe375feb6600ef5602c883c5d21eb51c09f22b83c4643"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "form_urlencoded",
 | 
			
		||||
 "idna",
 | 
			
		||||
 "percent-encoding",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "utf-8"
 | 
			
		||||
version = "0.7.6"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9"
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "version_check"
 | 
			
		||||
version = "0.9.4"
 | 
			
		||||
| 
						 | 
				
			
			@ -1709,36 +1472,6 @@ dependencies = [
 | 
			
		|||
 "try-lock",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "warp"
 | 
			
		||||
version = "0.3.2"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "3cef4e1e9114a4b7f1ac799f16ce71c14de5778500c5450ec6b7b920c55b587e"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "bytes",
 | 
			
		||||
 "futures-channel",
 | 
			
		||||
 "futures-util",
 | 
			
		||||
 "headers",
 | 
			
		||||
 "http",
 | 
			
		||||
 "hyper",
 | 
			
		||||
 "log",
 | 
			
		||||
 "mime",
 | 
			
		||||
 "mime_guess",
 | 
			
		||||
 "multipart",
 | 
			
		||||
 "percent-encoding",
 | 
			
		||||
 "pin-project",
 | 
			
		||||
 "scoped-tls",
 | 
			
		||||
 "serde",
 | 
			
		||||
 "serde_json",
 | 
			
		||||
 "serde_urlencoded",
 | 
			
		||||
 "tokio",
 | 
			
		||||
 "tokio-stream",
 | 
			
		||||
 "tokio-tungstenite",
 | 
			
		||||
 "tokio-util 0.6.10",
 | 
			
		||||
 "tower-service",
 | 
			
		||||
 "tracing",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "wasi"
 | 
			
		||||
version = "0.11.0+wasi-snapshot-preview1"
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -20,4 +20,4 @@ serde = { version = "1.0.144", features = ["derive", "std", "serde_derive"]}
 | 
			
		|||
serde_json = "1.0.85"
 | 
			
		||||
tokio = { version = "1", features = ["full"] }
 | 
			
		||||
tokio-postgres = { version = "0.7.7", features = ["with-serde_json-1"] }
 | 
			
		||||
warp = { version = "0.3.2" }
 | 
			
		||||
tower-cookies = "0.7.0"
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,148 @@
 | 
			
		|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
 | 
			
		||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
 | 
			
		||||
 | 
			
		||||
<svg
 | 
			
		||||
   width="130.52438mm"
 | 
			
		||||
   height="130.52438mm"
 | 
			
		||||
   viewBox="0 0 130.52438 130.52438"
 | 
			
		||||
   version="1.1"
 | 
			
		||||
   id="svg5"
 | 
			
		||||
   inkscape:version="1.2.1 (9c6d41e410, 2022-07-14, custom)"
 | 
			
		||||
   sodipodi:docname="flabk_icon_placeholder.svg"
 | 
			
		||||
   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
 | 
			
		||||
   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
 | 
			
		||||
   xmlns="http://www.w3.org/2000/svg"
 | 
			
		||||
   xmlns:svg="http://www.w3.org/2000/svg">
 | 
			
		||||
  <sodipodi:namedview
 | 
			
		||||
     id="namedview7"
 | 
			
		||||
     pagecolor="#ffffff"
 | 
			
		||||
     bordercolor="#666666"
 | 
			
		||||
     borderopacity="1.0"
 | 
			
		||||
     inkscape:showpageshadow="2"
 | 
			
		||||
     inkscape:pageopacity="0.0"
 | 
			
		||||
     inkscape:pagecheckerboard="0"
 | 
			
		||||
     inkscape:deskcolor="#d1d1d1"
 | 
			
		||||
     inkscape:document-units="mm"
 | 
			
		||||
     showgrid="false"
 | 
			
		||||
     inkscape:zoom="0.54866744"
 | 
			
		||||
     inkscape:cx="-78.371699"
 | 
			
		||||
     inkscape:cy="260.63147"
 | 
			
		||||
     inkscape:window-width="1914"
 | 
			
		||||
     inkscape:window-height="1041"
 | 
			
		||||
     inkscape:window-x="0"
 | 
			
		||||
     inkscape:window-y="16"
 | 
			
		||||
     inkscape:window-maximized="0"
 | 
			
		||||
     inkscape:current-layer="layer2" />
 | 
			
		||||
  <defs
 | 
			
		||||
     id="defs2">
 | 
			
		||||
    <rect
 | 
			
		||||
       x="238.94496"
 | 
			
		||||
       y="545.79144"
 | 
			
		||||
       width="291.11197"
 | 
			
		||||
       height="295.74161"
 | 
			
		||||
       id="rect1130" />
 | 
			
		||||
    <filter
 | 
			
		||||
       style="color-interpolation-filters:sRGB"
 | 
			
		||||
       inkscape:label="Roughen"
 | 
			
		||||
       id="filter1273"
 | 
			
		||||
       x="0"
 | 
			
		||||
       y="0"
 | 
			
		||||
       width="1"
 | 
			
		||||
       height="1">
 | 
			
		||||
      <feTurbulence
 | 
			
		||||
         type="fractalNoise"
 | 
			
		||||
         numOctaves="5"
 | 
			
		||||
         seed="145"
 | 
			
		||||
         baseFrequency="0.001 10"
 | 
			
		||||
         result="turbulence"
 | 
			
		||||
         id="feTurbulence1269" />
 | 
			
		||||
      <feDisplacementMap
 | 
			
		||||
         in="SourceGraphic"
 | 
			
		||||
         in2="turbulence"
 | 
			
		||||
         scale="1.68439"
 | 
			
		||||
         yChannelSelector="G"
 | 
			
		||||
         xChannelSelector="R"
 | 
			
		||||
         id="feDisplacementMap1271" />
 | 
			
		||||
    </filter>
 | 
			
		||||
    <rect
 | 
			
		||||
       x="238.94496"
 | 
			
		||||
       y="545.79144"
 | 
			
		||||
       width="291.11197"
 | 
			
		||||
       height="295.74161"
 | 
			
		||||
       id="rect1130-3" />
 | 
			
		||||
    <filter
 | 
			
		||||
       style="color-interpolation-filters:sRGB"
 | 
			
		||||
       inkscape:label="Roughen"
 | 
			
		||||
       id="filter1273-6"
 | 
			
		||||
       x="0"
 | 
			
		||||
       y="0"
 | 
			
		||||
       width="1"
 | 
			
		||||
       height="1">
 | 
			
		||||
      <feTurbulence
 | 
			
		||||
         type="fractalNoise"
 | 
			
		||||
         numOctaves="5"
 | 
			
		||||
         seed="145"
 | 
			
		||||
         baseFrequency="0.001 10"
 | 
			
		||||
         result="turbulence"
 | 
			
		||||
         id="feTurbulence1269-7" />
 | 
			
		||||
      <feDisplacementMap
 | 
			
		||||
         in="SourceGraphic"
 | 
			
		||||
         in2="turbulence"
 | 
			
		||||
         scale="1.68439"
 | 
			
		||||
         yChannelSelector="G"
 | 
			
		||||
         xChannelSelector="R"
 | 
			
		||||
         id="feDisplacementMap1271-5" />
 | 
			
		||||
    </filter>
 | 
			
		||||
  </defs>
 | 
			
		||||
  <g
 | 
			
		||||
     inkscape:label="Layer 1"
 | 
			
		||||
     inkscape:groupmode="layer"
 | 
			
		||||
     id="layer1"
 | 
			
		||||
     style="display:inline"
 | 
			
		||||
     transform="translate(-38.320595,-110.90324)">
 | 
			
		||||
    <circle
 | 
			
		||||
       style="display:inline;fill:#663399;fill-opacity:1;stroke-width:0.264583"
 | 
			
		||||
       id="path1074"
 | 
			
		||||
       cx="103.58279"
 | 
			
		||||
       cy="176.16544"
 | 
			
		||||
       r="65.262192" />
 | 
			
		||||
  </g>
 | 
			
		||||
  <g
 | 
			
		||||
     inkscape:groupmode="layer"
 | 
			
		||||
     id="layer2"
 | 
			
		||||
     inkscape:label="Layer 2"
 | 
			
		||||
     transform="translate(-38.320595,-110.90324)">
 | 
			
		||||
    <circle
 | 
			
		||||
       style="display:inline;fill:#0f0617;fill-opacity:1;stroke-width:0.224394;stroke-dasharray:none"
 | 
			
		||||
       id="path1074-5"
 | 
			
		||||
       cx="103.58279"
 | 
			
		||||
       cy="176.16544"
 | 
			
		||||
       r="55.262001" />
 | 
			
		||||
  </g>
 | 
			
		||||
  <g
 | 
			
		||||
     inkscape:groupmode="layer"
 | 
			
		||||
     id="layer3"
 | 
			
		||||
     inkscape:label="Layer 3"
 | 
			
		||||
     transform="translate(-38.320595,-110.90324)">
 | 
			
		||||
    <g
 | 
			
		||||
       id="g2829"
 | 
			
		||||
       transform="matrix(0.88602282,0,0,0.87606946,13.533885,21.962211)">
 | 
			
		||||
      <text
 | 
			
		||||
         xml:space="preserve"
 | 
			
		||||
         transform="matrix(2.0837961,0,0,2.645293,-442.06366,-1321.3309)"
 | 
			
		||||
         id="text1128-3"
 | 
			
		||||
         style="font-style:normal;font-weight:normal;font-size:40px;line-height:1.25;font-family:sans-serif;white-space:pre;shape-inside:url(#rect1130-3);display:inline;fill:#482464;fill-opacity:1;stroke:none;stroke-width:1.00008;stroke-dasharray:none;filter:url(#filter1273-6)"><tspan
 | 
			
		||||
           x="238.94531"
 | 
			
		||||
           y="581.18164"
 | 
			
		||||
           id="tspan2868">fK</tspan></text>
 | 
			
		||||
      <text
 | 
			
		||||
         xml:space="preserve"
 | 
			
		||||
         transform="matrix(2.0837961,0,0,2.645293,-438.16349,-1321.0342)"
 | 
			
		||||
         id="text1128"
 | 
			
		||||
         style="font-style:normal;font-weight:normal;font-size:40px;line-height:1.25;font-family:sans-serif;white-space:pre;shape-inside:url(#rect1130);fill:#ffffff;fill-opacity:1;stroke:none;filter:url(#filter1273)"><tspan
 | 
			
		||||
           x="238.94531"
 | 
			
		||||
           y="581.18164"
 | 
			
		||||
           id="tspan2870">fK</tspan></text>
 | 
			
		||||
    </g>
 | 
			
		||||
  </g>
 | 
			
		||||
</svg>
 | 
			
		||||
| 
		 After Width: | Height: | Size: 4.5 KiB  | 
| 
						 | 
				
			
			@ -52,7 +52,7 @@ impl Users {
 | 
			
		|||
            .await
 | 
			
		||||
            .query(
 | 
			
		||||
                format!(
 | 
			
		||||
                    "select id, username, host, display_name, password_hash from users where {}",
 | 
			
		||||
                    "select id, username, host, display_name, password_hash, email from users where {}",
 | 
			
		||||
                    where_clause
 | 
			
		||||
                )
 | 
			
		||||
                .as_str(),
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,20 +0,0 @@
 | 
			
		|||
use warp::hyper::StatusCode;
 | 
			
		||||
 | 
			
		||||
pub(crate) fn html_with_status(body: String, status: StatusCode) -> warp::http::Response<String> {
 | 
			
		||||
    warp::http::Response::builder()
 | 
			
		||||
        .header("Content-Type", "text/html; charset=utf-8")
 | 
			
		||||
        .status(status)
 | 
			
		||||
        .body(body)
 | 
			
		||||
        .expect("failed marshalling html response")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub(crate) fn html(body: String) -> warp::http::Response<String> {
 | 
			
		||||
    html_with_status(body, StatusCode::OK)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// pub(crate) fn html(body: String) -> Result<warp::http::Response<String>, warp::http::Error> {
 | 
			
		||||
//     warp::http::Response::builder()
 | 
			
		||||
//         .header("Content-Type", "text/html; charset=utf-8")
 | 
			
		||||
//         .status(StatusCode::OK)
 | 
			
		||||
//         .body(body)
 | 
			
		||||
// }
 | 
			
		||||
| 
						 | 
				
			
			@ -1,5 +1,4 @@
 | 
			
		|||
mod database;
 | 
			
		||||
mod model;
 | 
			
		||||
mod sec;
 | 
			
		||||
mod servek;
 | 
			
		||||
mod svc;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1 +0,0 @@
 | 
			
		|||
 | 
			
		||||
| 
						 | 
				
			
			@ -4,52 +4,114 @@ use axum::{
 | 
			
		|||
    body::Full,
 | 
			
		||||
    extract::Path,
 | 
			
		||||
    handler::Handler,
 | 
			
		||||
    http::{header, StatusCode},
 | 
			
		||||
    response::{self, Html, IntoResponse, Redirect, Response},
 | 
			
		||||
    http::{header, HeaderValue, StatusCode},
 | 
			
		||||
    response::{self, Html, IntoResponse, Response},
 | 
			
		||||
    routing, Extension, Form, Json, Router,
 | 
			
		||||
};
 | 
			
		||||
use warp::{http::HeaderValue, hyper::Uri, path::Tail, Filter, Rejection, Reply};
 | 
			
		||||
use mime_guess::mime;
 | 
			
		||||
use tower_cookies::{Cookie, Cookies};
 | 
			
		||||
 | 
			
		||||
use crate::svc::auth::AuthError;
 | 
			
		||||
use crate::svc::{
 | 
			
		||||
    auth::{AuthError, Claims},
 | 
			
		||||
    profiles,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
use super::{
 | 
			
		||||
    servek::{Server, ServerError},
 | 
			
		||||
    CreateProfileRequest, LoginRequest, Notification,
 | 
			
		||||
    CreateProfileRequest, LoginRequest, NavType, Notification, Redirect, WithNav,
 | 
			
		||||
};
 | 
			
		||||
use rust_embed::RustEmbed;
 | 
			
		||||
 | 
			
		||||
const AUTH_COOKIE_NAME: &str = "flabk_token";
 | 
			
		||||
 | 
			
		||||
#[derive(RustEmbed)]
 | 
			
		||||
#[folder = "static"]
 | 
			
		||||
struct StaticData;
 | 
			
		||||
 | 
			
		||||
impl Server {
 | 
			
		||||
    async fn index() -> impl IntoResponse {
 | 
			
		||||
        (
 | 
			
		||||
            StatusCode::OK,
 | 
			
		||||
            response::Html(include_str!("../../templates/html/index.html")),
 | 
			
		||||
        )
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub(super) fn register_html(&self, router: &Router) -> Router {
 | 
			
		||||
        router
 | 
			
		||||
            .clone()
 | 
			
		||||
            .route("/favicon.svg", routing::get(Self::favicon))
 | 
			
		||||
            .route("/", routing::get(Self::index))
 | 
			
		||||
            .route("/login", routing::get(Self::login_page))
 | 
			
		||||
            .route("/login", routing::get(Self::login_page).post(Self::login))
 | 
			
		||||
            .route("/logout", routing::get(Self::logout))
 | 
			
		||||
            .route(
 | 
			
		||||
                "/signup",
 | 
			
		||||
                routing::get(Self::signup_page).post(Self::create_user),
 | 
			
		||||
            )
 | 
			
		||||
            .route("/@/:username", routing::get(Self::profile))
 | 
			
		||||
            .route("/static/*file", routing::get(Self::static_handler))
 | 
			
		||||
            .fallback(routing::get(Self::handler_404))
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    async fn handler_404() -> impl IntoResponse {
 | 
			
		||||
    fn from_cookie(&self, cookie: Option<Cookie>) -> Result<WithNav<Option<Claims>>, ServerError> {
 | 
			
		||||
        if let Some(cookie) = cookie {
 | 
			
		||||
            let claims = self.auth.get_claims(cookie.value().to_owned())?;
 | 
			
		||||
            Ok(WithNav::new(Some(claims.clone()), claims.into()))
 | 
			
		||||
        } else {
 | 
			
		||||
            Ok(WithNav {
 | 
			
		||||
                nav_type: NavType::LoggedOut,
 | 
			
		||||
                obj: None,
 | 
			
		||||
            })
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    async fn index(
 | 
			
		||||
        Extension(srv): Extension<Server>,
 | 
			
		||||
        cookies: Cookies,
 | 
			
		||||
    ) -> Result<impl IntoResponse, ServerError> {
 | 
			
		||||
        let user = srv.from_cookie(cookies.get(AUTH_COOKIE_NAME))?;
 | 
			
		||||
        Ok((
 | 
			
		||||
            StatusCode::OK,
 | 
			
		||||
            response::Html(srv.hb.render("index", &user)?),
 | 
			
		||||
        ))
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    async fn favicon() -> impl IntoResponse {
 | 
			
		||||
        (
 | 
			
		||||
            StatusCode::OK,
 | 
			
		||||
            response::Html(include_str!("../../templates/html/404.html")),
 | 
			
		||||
            (
 | 
			
		||||
                [(
 | 
			
		||||
                    header::CONTENT_TYPE,
 | 
			
		||||
                    HeaderValue::from_static(mime::IMAGE_SVG.as_ref()),
 | 
			
		||||
                )],
 | 
			
		||||
                axum::body::boxed(Full::from(
 | 
			
		||||
                    include_bytes!("../../flabk_icon_placeholder.svg").as_ref(),
 | 
			
		||||
                )),
 | 
			
		||||
            ),
 | 
			
		||||
        )
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    async fn handler_404(
 | 
			
		||||
        Extension(srv): Extension<Server>,
 | 
			
		||||
        cookies: Cookies,
 | 
			
		||||
    ) -> Result<impl IntoResponse, ServerError> {
 | 
			
		||||
        Ok((
 | 
			
		||||
            StatusCode::OK,
 | 
			
		||||
            response::Html(
 | 
			
		||||
                srv.hb
 | 
			
		||||
                    .render("404", &srv.from_cookie(cookies.get(AUTH_COOKIE_NAME))?)?,
 | 
			
		||||
            ),
 | 
			
		||||
        ))
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    async fn logout(
 | 
			
		||||
        Extension(srv): Extension<Server>,
 | 
			
		||||
        cookies: Cookies,
 | 
			
		||||
    ) -> Result<impl IntoResponse, ServerError> {
 | 
			
		||||
        cookies.remove(Cookie::new(AUTH_COOKIE_NAME, ""));
 | 
			
		||||
        Ok((
 | 
			
		||||
            StatusCode::OK,
 | 
			
		||||
            response::Html(srv.hb.render(
 | 
			
		||||
                "redirect",
 | 
			
		||||
                &Redirect {
 | 
			
		||||
                    location: "/".to_owned(),
 | 
			
		||||
                },
 | 
			
		||||
            )?),
 | 
			
		||||
        ))
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn login_page_with(
 | 
			
		||||
        &self,
 | 
			
		||||
        tag_name: String,
 | 
			
		||||
| 
						 | 
				
			
			@ -73,68 +135,54 @@ impl Server {
 | 
			
		|||
        ))
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // async fn login(
 | 
			
		||||
    //     Extension(srv): Extension<Server>,
 | 
			
		||||
    //     Form(login): Form<LoginRequest>,
 | 
			
		||||
    // ) -> Result<impl IntoResponse, ServerError> {
 | 
			
		||||
    //     if login.username == "" || login.password == "" {
 | 
			
		||||
    //         return srv.login_page_with(
 | 
			
		||||
    //             "error-partial".to_owned(),
 | 
			
		||||
    //             "credentials required".to_owned(),
 | 
			
		||||
    //         );
 | 
			
		||||
    //     }
 | 
			
		||||
    //     let token = srv.auth.login(login.username, login.password).await?;
 | 
			
		||||
    // }
 | 
			
		||||
    async fn login(
 | 
			
		||||
        cookies: Cookies,
 | 
			
		||||
        Extension(srv): Extension<Server>,
 | 
			
		||||
        Form(login): Form<LoginRequest>,
 | 
			
		||||
    ) -> Result<impl IntoResponse, ServerError> {
 | 
			
		||||
        if login.username == "" || login.password == "" {
 | 
			
		||||
            return Ok((
 | 
			
		||||
                StatusCode::BAD_REQUEST,
 | 
			
		||||
                srv.login_page_with(
 | 
			
		||||
                    "error-partial".to_owned(),
 | 
			
		||||
                    "credentials required".to_owned(),
 | 
			
		||||
                )?,
 | 
			
		||||
            ));
 | 
			
		||||
        }
 | 
			
		||||
        let token = srv.auth.login(login.username, login.password).await?;
 | 
			
		||||
 | 
			
		||||
    // async fn login(
 | 
			
		||||
    //     srv: Server,
 | 
			
		||||
    //     Form(body): Form<HashMap<String, String>>,
 | 
			
		||||
    // ) -> Result<response::Html<String>, ServerError> {
 | 
			
		||||
    //     let user = body
 | 
			
		||||
    //         .get("username")
 | 
			
		||||
    //         .ok_or(ServerError::BadRequest("no username provided".to_owned()))?;
 | 
			
		||||
    //     let pass = body
 | 
			
		||||
    //         .get("password")
 | 
			
		||||
    //         .ok_or(ServerError::BadRequest("no password provided".to_owned()))?;
 | 
			
		||||
        if cookies.get(AUTH_COOKIE_NAME).is_some() {
 | 
			
		||||
            cookies.remove(Cookie::new(AUTH_COOKIE_NAME, ""));
 | 
			
		||||
        }
 | 
			
		||||
        cookies.add(Cookie::new(AUTH_COOKIE_NAME, token));
 | 
			
		||||
 | 
			
		||||
    //     let token = srv
 | 
			
		||||
    //         .auth
 | 
			
		||||
    //         .login(user.clone(), pass.clone())
 | 
			
		||||
    //         .await
 | 
			
		||||
    //         .map(|html| response::Html(html));
 | 
			
		||||
    //     if let Err(e) = &token {
 | 
			
		||||
    //         if let AuthError::InvalidCredentials = e {
 | 
			
		||||
    //             return srv.login_with_error("invalid credentials".to_owned());
 | 
			
		||||
    //         }
 | 
			
		||||
    //     }
 | 
			
		||||
    //     Ok(token?)
 | 
			
		||||
    // }
 | 
			
		||||
 | 
			
		||||
    fn with_server(
 | 
			
		||||
        srv: Server,
 | 
			
		||||
    ) -> impl Filter<Extract = (Server,), Error = std::convert::Infallible> + Clone {
 | 
			
		||||
        warp::any().map(move || srv.clone())
 | 
			
		||||
        Ok((
 | 
			
		||||
            StatusCode::OK,
 | 
			
		||||
            response::Html(srv.hb.render(
 | 
			
		||||
                "redirect",
 | 
			
		||||
                &Redirect {
 | 
			
		||||
                    location: "/".to_owned(),
 | 
			
		||||
                },
 | 
			
		||||
            )?),
 | 
			
		||||
        ))
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // fn profile(&self) -> impl Filter<Extract = impl Reply, Error = Rejection> + Clone {
 | 
			
		||||
    //     warp::get().and(
 | 
			
		||||
    //         warp::path!("@" / String)
 | 
			
		||||
    //             .and(Self::with_server(self.clone()))
 | 
			
		||||
    //             .and_then(|username: String, srv: Server| async move {
 | 
			
		||||
    //                 srv.hb
 | 
			
		||||
    //                     .render(
 | 
			
		||||
    //                         "profile",
 | 
			
		||||
    //                         &serde_json::json!(srv
 | 
			
		||||
    //                             .profiler
 | 
			
		||||
    //                             .profile(username)
 | 
			
		||||
    //                             .await
 | 
			
		||||
    //                             .map_err(|e| ServerError::from(e))?),
 | 
			
		||||
    //                     )
 | 
			
		||||
    //                     .map(|html| warp::reply::html(html))
 | 
			
		||||
    //                     .map_err(|e| ServerError::from(e).rejection())
 | 
			
		||||
    //             }),
 | 
			
		||||
    //     )
 | 
			
		||||
    // }
 | 
			
		||||
    async fn profile(
 | 
			
		||||
        cookies: Cookies,
 | 
			
		||||
        Extension(srv): Extension<Server>,
 | 
			
		||||
        Path(username): Path<String>,
 | 
			
		||||
    ) -> Result<impl IntoResponse, ServerError> {
 | 
			
		||||
        Ok((
 | 
			
		||||
            StatusCode::OK,
 | 
			
		||||
            response::Html(srv.hb.render(
 | 
			
		||||
                "profile",
 | 
			
		||||
                &WithNav::new(
 | 
			
		||||
                    srv.profiler.profile(username).await?,
 | 
			
		||||
                    srv.from_cookie(cookies.get(AUTH_COOKIE_NAME))?.nav_type,
 | 
			
		||||
                ),
 | 
			
		||||
            )?),
 | 
			
		||||
        ))
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    async fn create_user(
 | 
			
		||||
        Extension(srv): Extension<Server>,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,4 +1,11 @@
 | 
			
		|||
use axum::response::{Html, IntoResponse};
 | 
			
		||||
use serde::{Deserialize, Serialize};
 | 
			
		||||
use tower_cookies::{Cookie, Cookies};
 | 
			
		||||
 | 
			
		||||
use crate::svc::{
 | 
			
		||||
    auth::{Auth, AuthError, Claims},
 | 
			
		||||
    profiles::User,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
mod html;
 | 
			
		||||
pub mod servek;
 | 
			
		||||
| 
						 | 
				
			
			@ -22,7 +29,59 @@ pub struct CreateProfileRequest {
 | 
			
		|||
    pub email: String,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// pub enum HtmlOrRedirect {
 | 
			
		||||
//     Html(Html<String>),
 | 
			
		||||
//     Redirect(()),
 | 
			
		||||
// }
 | 
			
		||||
 | 
			
		||||
#[derive(Debug, Clone, Serialize)]
 | 
			
		||||
pub struct Login {
 | 
			
		||||
    pub token: String,
 | 
			
		||||
pub struct Redirect {
 | 
			
		||||
    pub location: String,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Debug, Clone, Serialize)]
 | 
			
		||||
pub enum NavType {
 | 
			
		||||
    LoggedIn,
 | 
			
		||||
    LoggedOut,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl From<Result<Claims, AuthError>> for NavType {
 | 
			
		||||
    fn from(claims: Result<Claims, AuthError>) -> Self {
 | 
			
		||||
        if claims.map(|c| c.expired()).unwrap_or(true) {
 | 
			
		||||
            NavType::LoggedOut
 | 
			
		||||
        } else {
 | 
			
		||||
            NavType::LoggedIn
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl From<Claims> for NavType {
 | 
			
		||||
    fn from(c: Claims) -> Self {
 | 
			
		||||
        if c.expired() {
 | 
			
		||||
            NavType::LoggedOut
 | 
			
		||||
        } else {
 | 
			
		||||
            NavType::LoggedIn
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Debug, Clone, Serialize)]
 | 
			
		||||
pub struct WithNav<T> {
 | 
			
		||||
    pub nav_type: NavType,
 | 
			
		||||
    pub obj: T,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl<T> WithNav<T> {
 | 
			
		||||
    pub fn new(obj: T, nav_type: NavType) -> WithNav<T> {
 | 
			
		||||
        WithNav { nav_type, obj }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl<T> Into<serde_json::Value> for WithNav<T>
 | 
			
		||||
where
 | 
			
		||||
    T: Serialize,
 | 
			
		||||
{
 | 
			
		||||
    fn into(self) -> serde_json::Value {
 | 
			
		||||
        serde_json::json!(self)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,23 +2,16 @@ use core::panic;
 | 
			
		|||
use std::{convert::Infallible, fmt::Display, net::SocketAddr};
 | 
			
		||||
 | 
			
		||||
use axum::{
 | 
			
		||||
    http::uri::InvalidUri,
 | 
			
		||||
    http::{uri::InvalidUri, StatusCode},
 | 
			
		||||
    response::{self, IntoResponse, Response},
 | 
			
		||||
    routing, Extension, Router,
 | 
			
		||||
};
 | 
			
		||||
use handlebars::{Handlebars, RenderError};
 | 
			
		||||
use warp::{
 | 
			
		||||
    hyper::StatusCode,
 | 
			
		||||
    reject::{MethodNotAllowed, Reject},
 | 
			
		||||
    Filter, Rejection, Reply,
 | 
			
		||||
};
 | 
			
		||||
use tower_cookies::CookieManagerLayer;
 | 
			
		||||
 | 
			
		||||
use crate::{
 | 
			
		||||
    model,
 | 
			
		||||
    svc::{
 | 
			
		||||
        auth::{Auth, AuthError},
 | 
			
		||||
        profiles::{Profiler, UserError},
 | 
			
		||||
    },
 | 
			
		||||
use crate::svc::{
 | 
			
		||||
    auth::{Auth, AuthError},
 | 
			
		||||
    profiles::{Profiler, UserError},
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#[derive(Clone)]
 | 
			
		||||
| 
						 | 
				
			
			@ -37,10 +30,29 @@ impl Server {
 | 
			
		|||
            .expect("login template");
 | 
			
		||||
        hb.register_template_string("signup", include_str!("../../templates/html/signup.html"))
 | 
			
		||||
            .expect("login template");
 | 
			
		||||
        hb.register_template_string(
 | 
			
		||||
            "redirect",
 | 
			
		||||
            include_str!("../../templates/html/html-redirect.html"),
 | 
			
		||||
        )
 | 
			
		||||
        .expect("redirect template");
 | 
			
		||||
        hb.register_template_string("error-partial", r#"<h2 class="error">{{message}}</h2>"#)
 | 
			
		||||
            .expect("error-partial");
 | 
			
		||||
        hb.register_template_string("success-partial", r#"<h2 class="success">{{message}}</h2>"#)
 | 
			
		||||
            .expect("success-partial");
 | 
			
		||||
        hb.register_template_string("index", include_str!("../../templates/html/index.html"))
 | 
			
		||||
            .expect("index");
 | 
			
		||||
        hb.register_template_string("404", include_str!("../../templates/html/404.html"))
 | 
			
		||||
            .expect("404");
 | 
			
		||||
        hb.register_partial(
 | 
			
		||||
            "LoggedOut",
 | 
			
		||||
            include_str!("../../templates/html/nav-loggedout.html"),
 | 
			
		||||
        )
 | 
			
		||||
        .expect("LoggedOut");
 | 
			
		||||
        hb.register_partial(
 | 
			
		||||
            "LoggedIn",
 | 
			
		||||
            include_str!("../../templates/html/nav-loggedin.html"),
 | 
			
		||||
        )
 | 
			
		||||
        .expect("LoggedIn");
 | 
			
		||||
        Self { hb, profiler, auth }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -48,7 +60,8 @@ impl Server {
 | 
			
		|||
        let router = Router::new();
 | 
			
		||||
        let router = self
 | 
			
		||||
            .register_html(&router)
 | 
			
		||||
            .layer(Extension::<Server>(self.clone()));
 | 
			
		||||
            .layer(Extension::<Server>(self.clone()))
 | 
			
		||||
            .layer(CookieManagerLayer::new());
 | 
			
		||||
 | 
			
		||||
        let addr = SocketAddr::from(([127, 0, 0, 1], port));
 | 
			
		||||
        println!("listening on {}", addr);
 | 
			
		||||
| 
						 | 
				
			
			@ -69,8 +82,6 @@ pub(super) enum ServerError {
 | 
			
		|||
    BadRequest(String),
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Reject for ServerError {}
 | 
			
		||||
 | 
			
		||||
impl From<RenderError> for ServerError {
 | 
			
		||||
    fn from(r: RenderError) -> Self {
 | 
			
		||||
        Self::Internal(r.to_string())
 | 
			
		||||
| 
						 | 
				
			
			@ -108,7 +119,11 @@ impl IntoResponse for ServerError {
 | 
			
		|||
    fn into_response(self) -> axum::response::Response {
 | 
			
		||||
        match self {
 | 
			
		||||
            ServerError::Internal(err) => (StatusCode::INTERNAL_SERVER_ERROR, err).into_response(),
 | 
			
		||||
            ServerError::NotFound => (StatusCode::NOT_FOUND, "").into_response(),
 | 
			
		||||
            ServerError::NotFound => (
 | 
			
		||||
                StatusCode::NOT_FOUND,
 | 
			
		||||
                response::Html(include_str!("../../templates/html/404.html")),
 | 
			
		||||
            )
 | 
			
		||||
                .into_response(),
 | 
			
		||||
            ServerError::BadRequest(err) => (StatusCode::BAD_REQUEST, err).into_response(),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,7 +1,8 @@
 | 
			
		|||
use std::time::SystemTime;
 | 
			
		||||
 | 
			
		||||
use jsonwebtoken::{EncodingKey, Header};
 | 
			
		||||
use jsonwebtoken::{Algorithm, DecodingKey, EncodingKey, Header, TokenData, Validation};
 | 
			
		||||
use serde::{Deserialize, Serialize};
 | 
			
		||||
use tower_cookies::Cookie;
 | 
			
		||||
 | 
			
		||||
use crate::{
 | 
			
		||||
    database::{
 | 
			
		||||
| 
						 | 
				
			
			@ -47,18 +48,38 @@ impl Auth {
 | 
			
		|||
        Ok(jsonwebtoken::encode(
 | 
			
		||||
            &Header::default(),
 | 
			
		||||
            &Claims::from(user),
 | 
			
		||||
            &EncodingKey::from_secret("secret".as_ref()),
 | 
			
		||||
            &EncodingKey::from_secret(self.secret.as_ref()),
 | 
			
		||||
        )?)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn get_claims(&self, token: String) -> Result<Claims, AuthError> {
 | 
			
		||||
        Ok(jsonwebtoken::decode::<Claims>(
 | 
			
		||||
            token.as_str(),
 | 
			
		||||
            &DecodingKey::from_secret(self.secret.as_ref()),
 | 
			
		||||
            &Validation::new(Algorithm::HS256),
 | 
			
		||||
        )?
 | 
			
		||||
        .claims)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Debug, Clone, Serialize, Deserialize)]
 | 
			
		||||
pub struct Claims {
 | 
			
		||||
    pub sub: String,
 | 
			
		||||
    pub username: String,
 | 
			
		||||
    pub exp: u64,
 | 
			
		||||
    pub iat: u64,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Claims {
 | 
			
		||||
    pub fn expired(&self) -> bool {
 | 
			
		||||
        SystemTime::now()
 | 
			
		||||
            .duration_since(SystemTime::UNIX_EPOCH)
 | 
			
		||||
            .unwrap()
 | 
			
		||||
            .as_secs()
 | 
			
		||||
            >= self.exp
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl From<users::User> for Claims {
 | 
			
		||||
    fn from(u: users::User) -> Self {
 | 
			
		||||
        let now = SystemTime::now()
 | 
			
		||||
| 
						 | 
				
			
			@ -67,6 +88,7 @@ impl From<users::User> for Claims {
 | 
			
		|||
            .as_secs();
 | 
			
		||||
        Claims {
 | 
			
		||||
            sub: u.id,
 | 
			
		||||
            username: u.username,
 | 
			
		||||
            exp: now + SECS_JWT_EXPIRE,
 | 
			
		||||
            iat: now,
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,5 +1,4 @@
 | 
			
		|||
use serde::Serialize;
 | 
			
		||||
use warp::{reject::Reject, Rejection};
 | 
			
		||||
 | 
			
		||||
use crate::{
 | 
			
		||||
    database::{
 | 
			
		||||
| 
						 | 
				
			
			@ -95,5 +94,3 @@ impl ToString for UserError {
 | 
			
		|||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Reject for UserError {}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -3,10 +3,26 @@ body {
 | 
			
		|||
	color: rebeccapurple;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
p,
 | 
			
		||||
h1,
 | 
			
		||||
h2,
 | 
			
		||||
label {
 | 
			
		||||
	font-size: 160%;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
h1 {
 | 
			
		||||
	text-align: center;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* .big {
 | 
			
		||||
	font-size: 200%;
 | 
			
		||||
} */
 | 
			
		||||
 | 
			
		||||
.big>input {
 | 
			
		||||
	font-size: 180%;
 | 
			
		||||
	margin: 5%;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
input {
 | 
			
		||||
	background-color: black;
 | 
			
		||||
| 
						 | 
				
			
			@ -14,10 +30,6 @@ input {
 | 
			
		|||
	border-color: rebeccapurple;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
form>div {
 | 
			
		||||
	width: 80%;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.error {
 | 
			
		||||
	color: rgba(255, 0, 0, 0.7);
 | 
			
		||||
	font-weight: bold;
 | 
			
		||||
| 
						 | 
				
			
			@ -33,7 +45,7 @@ form>div {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
#central {
 | 
			
		||||
	width: 30%;
 | 
			
		||||
	width: 40%;
 | 
			
		||||
	border: 5px solid rebeccapurple;
 | 
			
		||||
	height: 30vw;
 | 
			
		||||
	padding: 10px;
 | 
			
		||||
| 
						 | 
				
			
			@ -43,10 +55,35 @@ form>div {
 | 
			
		|||
	justify-content: center;
 | 
			
		||||
	align-items: center;
 | 
			
		||||
	background-color: rgba(13, 6, 19, 0.4);
 | 
			
		||||
	font-size: large;
 | 
			
		||||
	font-weight: bold;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
a {
 | 
			
		||||
	color: rebeccapurple;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
nav {
 | 
			
		||||
	/* background-color: #333; */
 | 
			
		||||
	margin: 0;
 | 
			
		||||
	overflow: hidden;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
nav ul {
 | 
			
		||||
	margin: 0;
 | 
			
		||||
	padding: 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
nav ul li {
 | 
			
		||||
	display: inline-block;
 | 
			
		||||
	list-style-type: none;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
nav>ul>li>a {
 | 
			
		||||
	/* color: #aaa; */
 | 
			
		||||
	/* background-color:#FF0; */
 | 
			
		||||
	display: block;
 | 
			
		||||
	line-height: 2em;
 | 
			
		||||
	padding: 0.5em 0.5em;
 | 
			
		||||
	text-decoration: none;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -4,9 +4,11 @@
 | 
			
		|||
<head>
 | 
			
		||||
	<title>flabk - not found</title>
 | 
			
		||||
	<link rel="stylesheet" href="/static/style/main.css">
 | 
			
		||||
	<link rel="icon" type="image/svg+xml" href="/favicon.svg">
 | 
			
		||||
</head>
 | 
			
		||||
 | 
			
		||||
<body>
 | 
			
		||||
	{{> (lookup this "nav_type") }}
 | 
			
		||||
	<h1>404 not found</h1>
 | 
			
		||||
	<br />
 | 
			
		||||
	<h1><a href="/">return</a></h1>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,18 @@
 | 
			
		|||
<!DOCTYPE html>
 | 
			
		||||
<html>
 | 
			
		||||
 | 
			
		||||
<head>
 | 
			
		||||
	<title>redirecting</title>
 | 
			
		||||
	<style>
 | 
			
		||||
		body {
 | 
			
		||||
			background-color: black;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
	</style>
 | 
			
		||||
	<meta http-equiv="refresh" content="time; URL={{location}}" />
 | 
			
		||||
</head>
 | 
			
		||||
 | 
			
		||||
<body>
 | 
			
		||||
</body>
 | 
			
		||||
 | 
			
		||||
</html>
 | 
			
		||||
| 
						 | 
				
			
			@ -4,12 +4,12 @@
 | 
			
		|||
<head>
 | 
			
		||||
	<title>flabk</title>
 | 
			
		||||
	<link rel="stylesheet" href="/static/style/main.css">
 | 
			
		||||
	<link rel="icon" type="image/svg+xml" href="/favicon.svg">
 | 
			
		||||
</head>
 | 
			
		||||
 | 
			
		||||
<body>
 | 
			
		||||
	<h1>hi</h1>
 | 
			
		||||
	<h1><a href="/login">login</a></h1>
 | 
			
		||||
	<h1><a href="/signup">sign up</a></h1>
 | 
			
		||||
	{{> (lookup this "nav_type") }}
 | 
			
		||||
	<h1>hi {{obj.username}}</h1>
 | 
			
		||||
</body>
 | 
			
		||||
 | 
			
		||||
</html>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -4,14 +4,16 @@
 | 
			
		|||
<head>
 | 
			
		||||
	<title>flabk - login</title>
 | 
			
		||||
	<link rel="stylesheet" href="/static/style/main.css">
 | 
			
		||||
	<link rel="icon" type="image/svg+xml" href="/favicon.svg">
 | 
			
		||||
</head>
 | 
			
		||||
 | 
			
		||||
<body>
 | 
			
		||||
	{{> LoggedOut }}
 | 
			
		||||
	<h1>login</h1>
 | 
			
		||||
	<div id="central">
 | 
			
		||||
		<p>login form</p>
 | 
			
		||||
		{{> (lookup this "tag_name")}}
 | 
			
		||||
		<form id="login" method="post" action="/login">
 | 
			
		||||
		<form class="big" id="login" method="post" action="/login">
 | 
			
		||||
			<input type="text" name="username">
 | 
			
		||||
			<input type="password" name="password">
 | 
			
		||||
			<input type="submit" value="Submit" hidden>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,13 @@
 | 
			
		|||
<nav>
 | 
			
		||||
	<ul>
 | 
			
		||||
		<li>
 | 
			
		||||
			<a href="/">home</a>
 | 
			
		||||
		</li>
 | 
			
		||||
		<li>
 | 
			
		||||
			<a href="/@/{{obj.username}}">me</a>
 | 
			
		||||
		</li>
 | 
			
		||||
		<li>
 | 
			
		||||
			<a href="/logout">log out</a>
 | 
			
		||||
		</li>
 | 
			
		||||
	</ul>
 | 
			
		||||
</nav>
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,13 @@
 | 
			
		|||
<nav>
 | 
			
		||||
	<ul>
 | 
			
		||||
		<li>
 | 
			
		||||
			<a href="/">home</a>
 | 
			
		||||
		</li>
 | 
			
		||||
		<li>
 | 
			
		||||
			<a href="/login">login</a>
 | 
			
		||||
		</li>
 | 
			
		||||
		<li>
 | 
			
		||||
			<a href="/signup">sign up</a>
 | 
			
		||||
		</li>
 | 
			
		||||
	</ul>
 | 
			
		||||
</nav>
 | 
			
		||||
| 
						 | 
				
			
			@ -1,15 +0,0 @@
 | 
			
		|||
<!DOCTYPE html>
 | 
			
		||||
<html>
 | 
			
		||||
 | 
			
		||||
<head>
 | 
			
		||||
	<title>logging in</title>
 | 
			
		||||
</head>
 | 
			
		||||
 | 
			
		||||
<body>
 | 
			
		||||
	<script>
 | 
			
		||||
		window.localStorage.setItem('token', '{{token}}');
 | 
			
		||||
		document.location.href = "/";
 | 
			
		||||
	</script>
 | 
			
		||||
</body>
 | 
			
		||||
 | 
			
		||||
</html>
 | 
			
		||||
| 
						 | 
				
			
			@ -4,10 +4,12 @@
 | 
			
		|||
<head>
 | 
			
		||||
	<title>@{{username}}</title>
 | 
			
		||||
	<link rel="stylesheet" href="/static/style/main.css">
 | 
			
		||||
	<link rel="icon" type="image/svg+xml" href="/favicon.svg">
 | 
			
		||||
</head>
 | 
			
		||||
 | 
			
		||||
<body>
 | 
			
		||||
	<h1>hi {{username}}, your id is {{id}}</h1>
 | 
			
		||||
	{{> (lookup this "nav_type") }}
 | 
			
		||||
	<h1>hi {{obj.username}}, your id is {{obj.id}}</h1>
 | 
			
		||||
</body>
 | 
			
		||||
 | 
			
		||||
</html>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -4,28 +4,21 @@
 | 
			
		|||
<head>
 | 
			
		||||
	<title>flabk - signup</title>
 | 
			
		||||
	<link rel="stylesheet" href="/static/style/main.css">
 | 
			
		||||
	<link rel="icon" type="image/svg+xml" href="/favicon.svg">
 | 
			
		||||
</head>
 | 
			
		||||
 | 
			
		||||
<body>
 | 
			
		||||
	{{> LoggedOut }}
 | 
			
		||||
	<h1>signup</h1>
 | 
			
		||||
	<div id="central">
 | 
			
		||||
		<p>signup form</p>
 | 
			
		||||
		{{> (lookup this "tag_name")}}
 | 
			
		||||
		<form id="signup" method="post" action="/signup">
 | 
			
		||||
			<div>
 | 
			
		||||
				<label for="username">username</label>
 | 
			
		||||
				<input type="text" name="username">
 | 
			
		||||
			</div>
 | 
			
		||||
			<br />
 | 
			
		||||
			<div>
 | 
			
		||||
				<label for="email">email</label>
 | 
			
		||||
				<input type="email" name="email">
 | 
			
		||||
			</div>
 | 
			
		||||
			<br />
 | 
			
		||||
			<div>
 | 
			
		||||
				<label for="password">password</label>
 | 
			
		||||
				<input type="password" name="password">
 | 
			
		||||
			</div>
 | 
			
		||||
		<form class="big" id="signup" method="post" action="/signup">
 | 
			
		||||
			<input type="text" name="username" placeholder="username">
 | 
			
		||||
			<br>
 | 
			
		||||
			<input type="email" name="email" placeholder="email">
 | 
			
		||||
			<br>
 | 
			
		||||
			<input type="password" name="password" placeholder="password">
 | 
			
		||||
			<input type="submit" value="Submit" hidden>
 | 
			
		||||
		</form>
 | 
			
		||||
	</div>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue