adding some starter code to the depell
This commit is contained in:
parent
4c15f61cb7
commit
c7dbe1c43d
810
Cargo.lock
generated
810
Cargo.lock
generated
|
@ -3,30 +3,38 @@
|
|||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "addr2line"
|
||||
version = "0.24.2"
|
||||
name = "aead"
|
||||
version = "0.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1"
|
||||
checksum = "d122413f284cf2d62fb1b7db97e02edb8cda96d769b16e443a4f6195e35662b0"
|
||||
dependencies = [
|
||||
"gimli",
|
||||
"crypto-common",
|
||||
"generic-array",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "adler2"
|
||||
version = "2.0.0"
|
||||
name = "aes"
|
||||
version = "0.8.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627"
|
||||
|
||||
[[package]]
|
||||
name = "ahash"
|
||||
version = "0.8.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011"
|
||||
checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"once_cell",
|
||||
"version_check",
|
||||
"zerocopy",
|
||||
"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]]
|
||||
|
@ -36,92 +44,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f"
|
||||
|
||||
[[package]]
|
||||
name = "async-trait"
|
||||
version = "0.1.83"
|
||||
name = "block-buffer"
|
||||
version = "0.10.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "721cae7de5c34fbb2acd27e21e6d2cf7b886dce0c27388d46c4e6c47ea4318dd"
|
||||
checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"generic-array",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "axum"
|
||||
version = "0.7.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "504e3947307ac8326a5437504c517c4b56716c9d98fac0028c2acc7ca47d70ae"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"axum-core",
|
||||
"bytes",
|
||||
"futures-util",
|
||||
"http",
|
||||
"http-body",
|
||||
"http-body-util",
|
||||
"hyper",
|
||||
"hyper-util",
|
||||
"itoa",
|
||||
"matchit",
|
||||
"memchr",
|
||||
"mime",
|
||||
"percent-encoding",
|
||||
"pin-project-lite",
|
||||
"rustversion",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"serde_path_to_error",
|
||||
"serde_urlencoded",
|
||||
"sync_wrapper 1.0.1",
|
||||
"tokio",
|
||||
"tower",
|
||||
"tower-layer",
|
||||
"tower-service",
|
||||
"tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "axum-core"
|
||||
version = "0.4.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "09f2bd6146b97ae3359fa0cc6d6b376d9539582c7b4220f041a33ec24c226199"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"bytes",
|
||||
"futures-util",
|
||||
"http",
|
||||
"http-body",
|
||||
"http-body-util",
|
||||
"mime",
|
||||
"pin-project-lite",
|
||||
"rustversion",
|
||||
"sync_wrapper 1.0.1",
|
||||
"tower-layer",
|
||||
"tower-service",
|
||||
"tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "backtrace"
|
||||
version = "0.3.74"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a"
|
||||
dependencies = [
|
||||
"addr2line",
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"miniz_oxide",
|
||||
"object",
|
||||
"rustc-demangle",
|
||||
"windows-targets",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "2.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de"
|
||||
|
||||
[[package]]
|
||||
name = "bumpalo"
|
||||
version = "3.16.0"
|
||||
|
@ -131,100 +61,162 @@ dependencies = [
|
|||
"allocator-api2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bytes"
|
||||
version = "1.7.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "428d9aa8fbc0670b7b8d6030a7fadd0f86151cae55e4dbbece15f3780a3dfaf3"
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
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 = "cpufeatures"
|
||||
version = "0.2.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "608697df725056feaccfa42cffdaeeec3fccc4ffc38358ecd19b243e716a78e0"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crypto-common"
|
||||
version = "0.1.6"
|
||||
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 = "curve25519-dalek"
|
||||
version = "4.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "97fb8b7c4503de7d6ae7b42ab72a5a59857b4c937ec27a3d4539dba95b5ab2be"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"cpufeatures",
|
||||
"curve25519-dalek-derive",
|
||||
"digest",
|
||||
"fiat-crypto",
|
||||
"rustc_version",
|
||||
"subtle",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "curve25519-dalek-derive"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "depell"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"axum",
|
||||
"rusqlite",
|
||||
"aes-gcm",
|
||||
"ed25519-dalek",
|
||||
"getrandom",
|
||||
"rand_core",
|
||||
"x25519-dalek",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fallible-iterator"
|
||||
version = "0.3.0"
|
||||
name = "digest"
|
||||
version = "0.10.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2acce4a10f12dc2fb14a218589d4f1f62ef011b2d0cc4b3cb1bba8e94da14649"
|
||||
|
||||
[[package]]
|
||||
name = "fallible-streaming-iterator"
|
||||
version = "0.1.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7360491ce676a36bf9bb3c56c1aa791658183a54d2744120f27285738d90465a"
|
||||
|
||||
[[package]]
|
||||
name = "fnv"
|
||||
version = "1.0.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
|
||||
|
||||
[[package]]
|
||||
name = "form_urlencoded"
|
||||
version = "1.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456"
|
||||
checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292"
|
||||
dependencies = [
|
||||
"percent-encoding",
|
||||
"block-buffer",
|
||||
"crypto-common",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures-channel"
|
||||
version = "0.3.30"
|
||||
name = "ed25519"
|
||||
version = "2.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78"
|
||||
checksum = "115531babc129696a58c64a4fef0a8bf9e9698629fb97e9e40767d235cfbcd53"
|
||||
dependencies = [
|
||||
"futures-core",
|
||||
"signature",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures-core"
|
||||
version = "0.3.30"
|
||||
name = "ed25519-dalek"
|
||||
version = "2.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d"
|
||||
|
||||
[[package]]
|
||||
name = "futures-task"
|
||||
version = "0.3.30"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004"
|
||||
|
||||
[[package]]
|
||||
name = "futures-util"
|
||||
version = "0.3.30"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48"
|
||||
checksum = "4a3daa8e81a3963a60642bcc1f90a670680bd4a77535faa384e9d1c79d620871"
|
||||
dependencies = [
|
||||
"futures-core",
|
||||
"futures-task",
|
||||
"pin-project-lite",
|
||||
"pin-utils",
|
||||
"curve25519-dalek",
|
||||
"ed25519",
|
||||
"rand_core",
|
||||
"sha2",
|
||||
"subtle",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gimli"
|
||||
version = "0.31.1"
|
||||
name = "fiat-crypto"
|
||||
version = "0.2.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f"
|
||||
checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d"
|
||||
|
||||
[[package]]
|
||||
name = "generic-array"
|
||||
version = "0.14.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a"
|
||||
dependencies = [
|
||||
"typenum",
|
||||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "getrandom"
|
||||
version = "0.2.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"wasi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ghash"
|
||||
version = "0.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f0d8a4362ccb29cb0b265253fb0a2728f592895ee6854fd9bc13f2ffda266ff1"
|
||||
dependencies = [
|
||||
"opaque-debug",
|
||||
"polyval",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.14.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1"
|
||||
dependencies = [
|
||||
"ahash",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
|
@ -232,15 +224,6 @@ version = "0.15.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1e087f84d4f86bf4b218b927129862374b72199ae7d8657835f1e89000eea4fb"
|
||||
|
||||
[[package]]
|
||||
name = "hashlink"
|
||||
version = "0.9.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6ba4ff7128dee98c7dc9794b6a411377e1404dba1c97deb8d1a55297bd25d8af"
|
||||
dependencies = [
|
||||
"hashbrown 0.14.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hbbytecode"
|
||||
version = "0.1.0"
|
||||
|
@ -276,136 +259,26 @@ dependencies = [
|
|||
]
|
||||
|
||||
[[package]]
|
||||
name = "hermit-abi"
|
||||
version = "0.3.9"
|
||||
name = "inout"
|
||||
version = "0.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024"
|
||||
|
||||
[[package]]
|
||||
name = "html-macro"
|
||||
version = "0.1.0"
|
||||
|
||||
[[package]]
|
||||
name = "http"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "21b9ddb458710bc376481b842f5da65cdf31522de232c1ca8146abce2a358258"
|
||||
checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"fnv",
|
||||
"itoa",
|
||||
"generic-array",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "http-body"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"http",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "http-body-util"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "793429d76616a256bcb62c2a2ec2bed781c8307e797e2598c50010f2bee2544f"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"futures-util",
|
||||
"http",
|
||||
"http-body",
|
||||
"pin-project-lite",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "httparse"
|
||||
version = "1.9.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7d71d3574edd2771538b901e6549113b4006ece66150fb69c0fb6d9a2adae946"
|
||||
|
||||
[[package]]
|
||||
name = "httpdate"
|
||||
version = "1.0.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9"
|
||||
|
||||
[[package]]
|
||||
name = "hyper"
|
||||
version = "1.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "50dfd22e0e76d0f662d429a5f80fcaf3855009297eab6a0a9f8543834744ba05"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"futures-channel",
|
||||
"futures-util",
|
||||
"http",
|
||||
"http-body",
|
||||
"httparse",
|
||||
"httpdate",
|
||||
"itoa",
|
||||
"pin-project-lite",
|
||||
"smallvec",
|
||||
"tokio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hyper-util"
|
||||
version = "0.1.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "41296eb09f183ac68eec06e03cdbea2e759633d4067b2f6552fc2e009bcad08b"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"futures-util",
|
||||
"http",
|
||||
"http-body",
|
||||
"hyper",
|
||||
"pin-project-lite",
|
||||
"tokio",
|
||||
"tower-service",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "1.0.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.158"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d8adc4bb1803a324070e64a98ae98f38934d91957a99cfb3a43dcbc01bc56439"
|
||||
|
||||
[[package]]
|
||||
name = "libsqlite3-sys"
|
||||
version = "0.30.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2e99fb7a497b1e3339bc746195567ed8d3e24945ecd636e3619d20b9de9e9149"
|
||||
dependencies = [
|
||||
"pkg-config",
|
||||
"vcpkg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.4.22"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24"
|
||||
|
||||
[[package]]
|
||||
name = "matchit"
|
||||
version = "0.7.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0e7465ac9959cc2b1404e8e2367b43684a6d13790fe23056cc8c6c5a6b7bcb94"
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.7.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
|
||||
|
||||
[[package]]
|
||||
name = "memmap2"
|
||||
version = "0.9.5"
|
||||
|
@ -416,80 +289,23 @@ dependencies = [
|
|||
]
|
||||
|
||||
[[package]]
|
||||
name = "mime"
|
||||
version = "0.3.17"
|
||||
name = "opaque-debug"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a"
|
||||
checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381"
|
||||
|
||||
[[package]]
|
||||
name = "miniz_oxide"
|
||||
version = "0.8.0"
|
||||
name = "polyval"
|
||||
version = "0.6.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e2d80299ef12ff69b16a84bb182e3b9df68b5a91574d3d4fa6e41b65deec4df1"
|
||||
checksum = "9d1fe60d06143b2430aa532c94cfe9e29783047f06c0d7fd359a9a51b729fa25"
|
||||
dependencies = [
|
||||
"adler2",
|
||||
"cfg-if",
|
||||
"cpufeatures",
|
||||
"opaque-debug",
|
||||
"universal-hash",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mio"
|
||||
version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "80e04d1dcff3aae0704555fe5fee3bcfaf3d1fdf8a7e521d5b9d2b42acb52cec"
|
||||
dependencies = [
|
||||
"hermit-abi",
|
||||
"libc",
|
||||
"wasi",
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "object"
|
||||
version = "0.36.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "aedf0a2d09c573ed1d8d85b30c119153926a2b36dce0ab28322c09a117a4683e"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "once_cell"
|
||||
version = "1.20.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "82881c4be219ab5faaf2ad5e5e5ecdff8c66bd7402ca3160975c93b24961afd1"
|
||||
dependencies = [
|
||||
"portable-atomic",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "percent-encoding"
|
||||
version = "2.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e"
|
||||
|
||||
[[package]]
|
||||
name = "pin-project-lite"
|
||||
version = "0.2.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02"
|
||||
|
||||
[[package]]
|
||||
name = "pin-utils"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
|
||||
|
||||
[[package]]
|
||||
name = "pkg-config"
|
||||
version = "0.3.31"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2"
|
||||
|
||||
[[package]]
|
||||
name = "portable-atomic"
|
||||
version = "1.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cc9c68a3f6da06753e9335d63e27f6b9754dd1920d941135b7ea8224f141adb2"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.86"
|
||||
|
@ -508,6 +324,15 @@ dependencies = [
|
|||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_core"
|
||||
version = "0.6.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
|
||||
dependencies = [
|
||||
"getrandom",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regalloc2"
|
||||
version = "0.10.2"
|
||||
|
@ -521,26 +346,6 @@ dependencies = [
|
|||
"smallvec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rusqlite"
|
||||
version = "0.32.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7753b721174eb8ff87a9a0e799e2d7bc3749323e773db92e0984debb00019d6e"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"fallible-iterator",
|
||||
"fallible-streaming-iterator",
|
||||
"hashlink",
|
||||
"libsqlite3-sys",
|
||||
"smallvec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustc-demangle"
|
||||
version = "0.1.24"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f"
|
||||
|
||||
[[package]]
|
||||
name = "rustc-hash"
|
||||
version = "2.0.0"
|
||||
|
@ -548,70 +353,36 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "583034fd73374156e66797ed8e5b0d5690409c9226b22d87cb7f19821c05d152"
|
||||
|
||||
[[package]]
|
||||
name = "rustversion"
|
||||
version = "1.0.17"
|
||||
name = "rustc_version"
|
||||
version = "0.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "955d28af4278de8121b7ebeb796b6a45735dc01436d898801014aced2773a3d6"
|
||||
|
||||
[[package]]
|
||||
name = "ryu"
|
||||
version = "1.0.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f"
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.210"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c8e3592472072e6e22e0a54d5904d9febf8508f65fb8552499a1abc7d1078c3a"
|
||||
checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
"semver",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.210"
|
||||
name = "semver"
|
||||
version = "1.0.23"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f"
|
||||
checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b"
|
||||
|
||||
[[package]]
|
||||
name = "sha2"
|
||||
version = "0.10.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"cfg-if",
|
||||
"cpufeatures",
|
||||
"digest",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.128"
|
||||
name = "signature"
|
||||
version = "2.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6ff5456707a1de34e7e37f2a6fd3d3f808c318259cbd01ab6377795054b483d8"
|
||||
dependencies = [
|
||||
"itoa",
|
||||
"memchr",
|
||||
"ryu",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_path_to_error"
|
||||
version = "0.1.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "af99884400da37c88f5e9146b7f1fd0fbcae8f6eec4e9da38b67d05486f814a6"
|
||||
dependencies = [
|
||||
"itoa",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_urlencoded"
|
||||
version = "0.7.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd"
|
||||
dependencies = [
|
||||
"form_urlencoded",
|
||||
"itoa",
|
||||
"ryu",
|
||||
"serde",
|
||||
]
|
||||
checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de"
|
||||
|
||||
[[package]]
|
||||
name = "smallvec"
|
||||
|
@ -620,14 +391,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67"
|
||||
|
||||
[[package]]
|
||||
name = "socket2"
|
||||
version = "0.5.7"
|
||||
name = "subtle"
|
||||
version = "2.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"windows-sys",
|
||||
]
|
||||
checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292"
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
|
@ -641,90 +408,10 @@ dependencies = [
|
|||
]
|
||||
|
||||
[[package]]
|
||||
name = "sync_wrapper"
|
||||
version = "0.1.2"
|
||||
name = "typenum"
|
||||
version = "1.17.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160"
|
||||
|
||||
[[package]]
|
||||
name = "sync_wrapper"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a7065abeca94b6a8a577f9bd45aa0867a2238b74e8eb67cf10d492bc39351394"
|
||||
|
||||
[[package]]
|
||||
name = "tokio"
|
||||
version = "1.40.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e2b070231665d27ad9ec9b8df639893f46727666c6767db40317fbe920a5d998"
|
||||
dependencies = [
|
||||
"backtrace",
|
||||
"libc",
|
||||
"mio",
|
||||
"pin-project-lite",
|
||||
"socket2",
|
||||
"tokio-macros",
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio-macros"
|
||||
version = "2.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tower"
|
||||
version = "0.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2873938d487c3cfb9aed7546dc9f2711d867c9f90c46b889989a2cb84eba6b4f"
|
||||
dependencies = [
|
||||
"futures-core",
|
||||
"futures-util",
|
||||
"pin-project-lite",
|
||||
"sync_wrapper 0.1.2",
|
||||
"tokio",
|
||||
"tower-layer",
|
||||
"tower-service",
|
||||
"tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tower-layer"
|
||||
version = "0.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e"
|
||||
|
||||
[[package]]
|
||||
name = "tower-service"
|
||||
version = "0.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3"
|
||||
|
||||
[[package]]
|
||||
name = "tracing"
|
||||
version = "0.1.40"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef"
|
||||
dependencies = [
|
||||
"log",
|
||||
"pin-project-lite",
|
||||
"tracing-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tracing-core"
|
||||
version = "0.1.32"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54"
|
||||
dependencies = [
|
||||
"once_cell",
|
||||
]
|
||||
checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
|
@ -733,10 +420,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe"
|
||||
|
||||
[[package]]
|
||||
name = "vcpkg"
|
||||
version = "0.2.15"
|
||||
name = "universal-hash"
|
||||
version = "0.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
|
||||
checksum = "fc1de2c688dc15305988b563c3854064043356019f97a4b46276fe734c4f07ea"
|
||||
dependencies = [
|
||||
"crypto-common",
|
||||
"subtle",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "version_check"
|
||||
|
@ -751,98 +442,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.52.0"
|
||||
name = "x25519-dalek"
|
||||
version = "2.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
|
||||
checksum = "c7e468321c81fb07fa7f4c636c3972b9100f0346e5b6a9f2bd0603a52f7ed277"
|
||||
dependencies = [
|
||||
"windows-targets",
|
||||
"curve25519-dalek",
|
||||
"rand_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-targets"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
|
||||
dependencies = [
|
||||
"windows_aarch64_gnullvm",
|
||||
"windows_aarch64_msvc",
|
||||
"windows_i686_gnu",
|
||||
"windows_i686_gnullvm",
|
||||
"windows_i686_msvc",
|
||||
"windows_x86_64_gnu",
|
||||
"windows_x86_64_gnullvm",
|
||||
"windows_x86_64_msvc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_gnullvm"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_msvc"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnu"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnullvm"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_msvc"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnu"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnullvm"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_msvc"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
|
||||
|
||||
[[package]]
|
||||
name = "xtask"
|
||||
version = "0.1.0"
|
||||
|
||||
[[package]]
|
||||
name = "zerocopy"
|
||||
version = "0.7.35"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0"
|
||||
dependencies = [
|
||||
"zerocopy-derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zerocopy-derive"
|
||||
version = "0.7.35"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[workspace]
|
||||
resolver = "2"
|
||||
members = ["hbbytecode", "hbvm", "hbxrt", "xtask", "hblang", "hbjit", "depell", "depell/html-macro"]
|
||||
members = ["hbbytecode", "hbvm", "hbxrt", "xtask", "hblang", "hbjit", "depell"]
|
||||
|
||||
[profile.release]
|
||||
lto = true
|
||||
|
|
|
@ -4,5 +4,8 @@ version = "0.1.0"
|
|||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
axum = "0.7.7"
|
||||
rusqlite = "0.32.1"
|
||||
aes-gcm = { version = "0.10.3", default-features = false, features = ["aes", "rand_core"] }
|
||||
ed25519-dalek = { version = "2.1.1", default-features = false, features = ["rand_core"] }
|
||||
getrandom = "0.2.15"
|
||||
rand_core = { version = "0.6.4", features = ["getrandom"] }
|
||||
x25519-dalek = { version = "2.0.1", default-features = false }
|
||||
|
|
|
@ -1,7 +0,0 @@
|
|||
[package]
|
||||
name = "html-macro"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[lib]
|
||||
proc-macro = true
|
|
@ -1,530 +0,0 @@
|
|||
#![feature(proc_macro_diagnostic)]
|
||||
#![feature(proc_macro_def_site)]
|
||||
|
||||
use std::fmt::Write;
|
||||
use std::str::FromStr;
|
||||
|
||||
macro_rules! diag {
|
||||
($level:ident: $($tt:tt)*) => {diag!($level(proc_macro::Span::call_site()): $($tt)*)};
|
||||
($level:ident[$span:expr]: $($tt:tt)*) => {diag!($level($span.span()): $($tt)*)};
|
||||
($level:ident($span:expr): $($tt:tt)*) => {{
|
||||
proc_macro::Diagnostic::spanned($span, proc_macro::Level::$level, format!($($tt)*)).emit();
|
||||
}};
|
||||
}
|
||||
|
||||
macro_rules! fatal_diag {
|
||||
($($tt:tt)*) => {{
|
||||
diag!($($tt)*);
|
||||
return None;
|
||||
}};
|
||||
}
|
||||
|
||||
#[proc_macro]
|
||||
pub fn html(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
|
||||
let mut trees = input.into_iter().peekable();
|
||||
let mut st = State {
|
||||
final_code: "Html({ let mut ___out = String::new(); ".to_string(),
|
||||
write_target: "___out".to_string(),
|
||||
error_handler: ".unwrap()",
|
||||
..State::default()
|
||||
};
|
||||
|
||||
if st.output_fmt(&mut trees).is_none() {
|
||||
return proc_macro::TokenStream::default();
|
||||
};
|
||||
|
||||
st.final_code.push_str("___out })");
|
||||
|
||||
if !st.tag_stack.is_empty() {
|
||||
diag!(Error(proc_macro::Span::def_site()): "unclosed tags: {}", st.tag_stack);
|
||||
}
|
||||
|
||||
proc_macro::TokenStream::from_str(&st.final_code).unwrap()
|
||||
}
|
||||
|
||||
#[proc_macro]
|
||||
pub fn write_html(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
|
||||
let mut trees = input.into_iter().peekable();
|
||||
let mut st = State {
|
||||
write_target: trees.next().expect("expected first token").to_string(),
|
||||
error_handler: ".unwrap()",
|
||||
..State::default()
|
||||
};
|
||||
|
||||
if st.output_fmt(&mut trees).is_none() {
|
||||
return proc_macro::TokenStream::default();
|
||||
};
|
||||
|
||||
if !st.tag_stack.is_empty() {
|
||||
diag!(Error(proc_macro::Span::def_site()): "unclosed tags: {}", st.tag_stack);
|
||||
}
|
||||
|
||||
proc_macro::TokenStream::from_str(&st.final_code).unwrap()
|
||||
}
|
||||
|
||||
type Trees = std::iter::Peekable<proc_macro::token_stream::IntoIter>;
|
||||
|
||||
#[derive(Default)]
|
||||
struct State {
|
||||
final_code: String,
|
||||
template: String,
|
||||
tstr: String,
|
||||
tag_stack: String,
|
||||
write_target: String,
|
||||
no_escaping: bool,
|
||||
error_handler: &'static str,
|
||||
}
|
||||
|
||||
impl State {
|
||||
fn flush_template(&mut self) {
|
||||
if self.template.is_empty() {
|
||||
return;
|
||||
}
|
||||
write!(
|
||||
self.final_code,
|
||||
"write!({}, {:?}){};",
|
||||
self.write_target, self.template, self.error_handler
|
||||
)
|
||||
.unwrap();
|
||||
self.template.clear();
|
||||
}
|
||||
|
||||
fn display_expr(&mut self, expr: impl std::fmt::Display) {
|
||||
self.flush_template();
|
||||
if std::mem::take(&mut self.no_escaping) {
|
||||
write!(
|
||||
self.final_code,
|
||||
"write!({}, \"{{}}\", {expr}){};",
|
||||
self.write_target, self.error_handler
|
||||
)
|
||||
.unwrap();
|
||||
} else {
|
||||
write!(
|
||||
self.final_code,
|
||||
"write!({}, \"{{}}\", &HtmlEscaped(&{expr})){};",
|
||||
self.write_target, self.error_handler,
|
||||
)
|
||||
.unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
fn expect_group(
|
||||
&mut self,
|
||||
trees: &mut Trees,
|
||||
delim: proc_macro::Delimiter,
|
||||
) -> Option<proc_macro::TokenStream> {
|
||||
match trees.next() {
|
||||
Some(proc_macro::TokenTree::Group(g)) if g.delimiter() == delim => Some(g.stream()),
|
||||
Some(c) => fatal_diag!(Error[c]: "expected {delim:?} group"),
|
||||
None => fatal_diag!(Error: "expected {delim:?} group, got eof"),
|
||||
}
|
||||
}
|
||||
|
||||
fn expect_punct(&mut self, trees: &mut Trees, c: char) -> Option<()> {
|
||||
match trees.next() {
|
||||
Some(proc_macro::TokenTree::Punct(p)) if p.as_char() == c => Some(()),
|
||||
Some(c) => fatal_diag!(Error[c]: "expected {c}"),
|
||||
None => fatal_diag!(Error: "expected {c}, got eof"),
|
||||
}
|
||||
}
|
||||
|
||||
fn tag(&mut self, p: proc_macro::Punct, trees: &mut Trees) -> Option<()> {
|
||||
let temp = match trees.next() {
|
||||
Some(proc_macro::TokenTree::Ident(id)) => {
|
||||
let temp = temp_str(&id, &mut self.tstr);
|
||||
if !is_html_tag(temp) {
|
||||
diag!(Error[p]: "expected html5 tag name");
|
||||
}
|
||||
temp
|
||||
}
|
||||
Some(proc_macro::TokenTree::Literal(lit)) => {
|
||||
let temp = temp_str(&lit, &mut self.tstr).trim_matches('"');
|
||||
if is_html_tag(temp) {
|
||||
if !temp.contains('!') {
|
||||
diag!(Warning[p]: "unnescessary string escaping");
|
||||
}
|
||||
} else if !is_valid_webcomponent(temp) {
|
||||
diag!(Error[p]: "invalid web component identifier");
|
||||
}
|
||||
temp
|
||||
}
|
||||
Some(proc_macro::TokenTree::Punct(p)) if p.as_char() == '/' => {
|
||||
let Some((_, top)) = self.tag_stack.rsplit_once(',') else {
|
||||
fatal_diag!(Error[p]: "no tag to close");
|
||||
};
|
||||
|
||||
let new_tag_stack_len = self.tag_stack.len() - top.len() - 1;
|
||||
|
||||
let (temp, span) = match trees.next() {
|
||||
Some(proc_macro::TokenTree::Ident(id)) => {
|
||||
(temp_str(&id, &mut self.tstr), id.span())
|
||||
}
|
||||
Some(proc_macro::TokenTree::Literal(lit)) => {
|
||||
(temp_str(&lit, &mut self.tstr).trim_matches('"'), lit.span())
|
||||
}
|
||||
Some(proc_macro::TokenTree::Punct(p)) if p.as_char() == '>' => {
|
||||
// easter egg
|
||||
write!(&mut self.template, "</{top}>").unwrap();
|
||||
self.tag_stack.truncate(new_tag_stack_len);
|
||||
return Some(());
|
||||
}
|
||||
Some(c) => fatal_diag!(Error[c]: "unexpected token in closing tag"),
|
||||
None => {
|
||||
fatal_diag!(Error[p]: "expected tag ident or string or '>'")
|
||||
}
|
||||
};
|
||||
|
||||
if temp != top {
|
||||
diag!(Error(span): "expected closing '{top}' tag");
|
||||
}
|
||||
|
||||
write!(&mut self.template, "</{top}>").unwrap();
|
||||
self.expect_punct(trees, '>')?;
|
||||
self.tag_stack.truncate(new_tag_stack_len);
|
||||
return Some(());
|
||||
}
|
||||
_ => fatal_diag!(Error[p]: "expected tag ident or string literal"),
|
||||
};
|
||||
|
||||
write!(&mut self.template, "<{temp}").unwrap();
|
||||
if !is_self_closing(temp) {
|
||||
write!(self.tag_stack, ",{temp}").unwrap();
|
||||
}
|
||||
|
||||
let mut has_attr = false;
|
||||
while let Some(c) = trees.next() {
|
||||
let mut has_attr_tmp = false;
|
||||
match c {
|
||||
proc_macro::TokenTree::Punct(p) if p.as_char() == '=' && has_attr => loop {
|
||||
match trees.next() {
|
||||
Some(proc_macro::TokenTree::Punct(p)) if p.as_char() == '!' => {
|
||||
self.no_escaping = true;
|
||||
continue;
|
||||
}
|
||||
Some(proc_macro::TokenTree::Literal(lit)) => {
|
||||
write!(&mut self.template, "={lit}").unwrap();
|
||||
}
|
||||
Some(proc_macro::TokenTree::Ident(id)) => {
|
||||
write!(&mut self.template, "=\"").unwrap();
|
||||
self.display_expr(id);
|
||||
write!(&mut self.template, "\"").unwrap();
|
||||
}
|
||||
Some(proc_macro::TokenTree::Group(g))
|
||||
if g.delimiter() == proc_macro::Delimiter::Brace =>
|
||||
{
|
||||
write!(&mut self.template, "=\"").unwrap();
|
||||
self.display_expr(g.stream());
|
||||
write!(&mut self.template, "\"").unwrap();
|
||||
}
|
||||
Some(c) => {
|
||||
diag!(Error[c]: "unexpected token in attr value")
|
||||
}
|
||||
None => diag!(Error[p]: "expected attribute value"),
|
||||
}
|
||||
break;
|
||||
},
|
||||
proc_macro::TokenTree::Punct(p) if p.as_char() == '>' => {
|
||||
write!(&mut self.template, ">").unwrap();
|
||||
break;
|
||||
}
|
||||
proc_macro::TokenTree::Ident(id) => {
|
||||
write!(&mut self.template, " {id}").unwrap();
|
||||
has_attr_tmp = true;
|
||||
}
|
||||
proc_macro::TokenTree::Literal(lit) => {
|
||||
let temp = temp_str(&lit, &mut self.tstr).trim_matches('"');
|
||||
if !is_valid_html_attt_name(temp) {
|
||||
diag!(Error[p]: "invalid attribute name");
|
||||
}
|
||||
write!(&mut self.template, " {temp}").unwrap();
|
||||
has_attr_tmp = true;
|
||||
}
|
||||
c => diag!(Error[c]: "unexpected token in attribute list"),
|
||||
}
|
||||
has_attr = has_attr_tmp;
|
||||
}
|
||||
|
||||
Some(())
|
||||
}
|
||||
|
||||
fn matches_char(t: &proc_macro::TokenTree, ch: char, spacing: proc_macro::Spacing) -> bool {
|
||||
matches!(t, proc_macro::TokenTree::Punct(p) if p.as_char() == ch && p.spacing() == spacing)
|
||||
}
|
||||
|
||||
fn match_expr(&mut self, trees: &mut Trees) -> Option<()> {
|
||||
let expr = self.expect_group(trees, proc_macro::Delimiter::Parenthesis)?;
|
||||
let mut body = self
|
||||
.expect_group(trees, proc_macro::Delimiter::Brace)?
|
||||
.into_iter()
|
||||
.peekable();
|
||||
self.flush_template();
|
||||
|
||||
write!(&mut self.final_code, "match {expr} {{").unwrap();
|
||||
|
||||
loop {
|
||||
let mut pattern = proc_macro::TokenStream::new();
|
||||
let mut looped = false;
|
||||
|
||||
while let Some(c) = body.next() {
|
||||
if !Self::matches_char(&c, '=', proc_macro::Spacing::Joint) {
|
||||
pattern.extend([c]);
|
||||
looped = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
let nc = body.next().expect("haaaaa");
|
||||
if Self::matches_char(&nc, '>', proc_macro::Spacing::Alone) {
|
||||
break;
|
||||
}
|
||||
pattern.extend([c, nc]);
|
||||
looped = true;
|
||||
}
|
||||
|
||||
if !looped {
|
||||
break;
|
||||
}
|
||||
|
||||
let body = self.expect_group(&mut body, proc_macro::Delimiter::Brace)?;
|
||||
|
||||
write!(&mut self.final_code, "{pattern} => {{").unwrap();
|
||||
self.output_fmt(&mut body.into_iter().peekable())?;
|
||||
write!(&mut self.final_code, "}}").unwrap();
|
||||
}
|
||||
|
||||
write!(&mut self.final_code, "}}").unwrap();
|
||||
|
||||
Some(())
|
||||
}
|
||||
|
||||
fn for_expr(&mut self, trees: &mut Trees) -> Option<()> {
|
||||
let mut ink = proc_macro::Span::call_site();
|
||||
let loop_var = trees
|
||||
.by_ref()
|
||||
.take_while(|t| {
|
||||
ink = t.span();
|
||||
!matches!(t, proc_macro::TokenTree::Ident(id) if temp_str(id, &mut self.tstr) == "in")
|
||||
})
|
||||
.collect::<proc_macro::TokenStream>();
|
||||
|
||||
let iter = self.expect_group(trees, proc_macro::Delimiter::Parenthesis)?;
|
||||
let body = self.expect_group(trees, proc_macro::Delimiter::Brace)?;
|
||||
let else_body = match trees.peek() {
|
||||
Some(proc_macro::TokenTree::Ident(id)) if temp_str(id, &mut self.tstr) == "else" => {
|
||||
trees.next();
|
||||
self.expect_group(trees, proc_macro::Delimiter::Brace)?
|
||||
}
|
||||
_ => proc_macro::TokenStream::new(),
|
||||
};
|
||||
|
||||
self.tstr.clear();
|
||||
|
||||
self.flush_template();
|
||||
|
||||
if else_body.is_empty() {
|
||||
write!(&mut self.final_code, "for {loop_var} in {iter} {{").unwrap();
|
||||
} else {
|
||||
write!(
|
||||
&mut self.final_code,
|
||||
"let mut looped = false;\
|
||||
for {loop_var} in {iter} {{\
|
||||
looped = true;"
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
self.output_fmt(&mut body.into_iter().peekable())?;
|
||||
write!(&mut self.final_code, "}}").unwrap();
|
||||
if !else_body.is_empty() {
|
||||
write!(&mut self.final_code, "if !looped {{").unwrap();
|
||||
self.output_fmt(&mut else_body.into_iter().peekable())?;
|
||||
write!(&mut self.final_code, "}}").unwrap();
|
||||
}
|
||||
Some(())
|
||||
}
|
||||
|
||||
fn output_fmt(&mut self, trees: &mut Trees) -> Option<()> {
|
||||
while let Some(c) = trees.next() {
|
||||
match c {
|
||||
proc_macro::TokenTree::Punct(p) if p.as_char() == '!' => self.no_escaping = true,
|
||||
proc_macro::TokenTree::Punct(p) if p.as_char() == '<' => self.tag(p, trees)?,
|
||||
proc_macro::TokenTree::Literal(lit) => self
|
||||
.template
|
||||
.push_str(temp_str(&lit, &mut self.tstr).trim_matches('"')),
|
||||
proc_macro::TokenTree::Ident(id) => match temp_str(&id, &mut self.tstr) {
|
||||
"match" => self.match_expr(trees)?,
|
||||
"for" => self.for_expr(trees)?,
|
||||
_ => self.display_expr(id),
|
||||
},
|
||||
proc_macro::TokenTree::Group(g)
|
||||
if g.delimiter() == proc_macro::Delimiter::Brace =>
|
||||
{
|
||||
self.display_expr(g.stream());
|
||||
}
|
||||
c => fatal_diag!(Error[c]: "unexpected token"),
|
||||
}
|
||||
}
|
||||
self.flush_template();
|
||||
|
||||
Some(())
|
||||
}
|
||||
}
|
||||
|
||||
fn temp_str(i: impl std::fmt::Display, buf: &mut String) -> &str {
|
||||
buf.clear();
|
||||
write!(buf, "{i}").unwrap();
|
||||
buf
|
||||
}
|
||||
|
||||
fn is_valid_html_attt_name(tag: &str) -> bool {
|
||||
tag.bytes()
|
||||
.all(|c| matches!(c, b'a'..=b'z' | b'_' | b'-' | b'A'..=b'Z' | 128..=u8::MAX))
|
||||
}
|
||||
|
||||
fn is_valid_webcomponent(tag: &str) -> bool {
|
||||
let mut seen_dash = false;
|
||||
tag.bytes()
|
||||
.inspect(|c| seen_dash |= *c == b'-')
|
||||
.all(|c| matches!(c, b'a'..=b'z' | b'_' | b'-' | b'.' | 128..=u8::MAX))
|
||||
&& seen_dash
|
||||
}
|
||||
|
||||
fn is_html_tag(tag: &str) -> bool {
|
||||
matches!(
|
||||
tag,
|
||||
"!DOCTYPE"
|
||||
| "a"
|
||||
| "abbr"
|
||||
| "acronym"
|
||||
| "address"
|
||||
| "area"
|
||||
| "article"
|
||||
| "aside"
|
||||
| "audio"
|
||||
| "b"
|
||||
| "base"
|
||||
| "basefont"
|
||||
| "bdi"
|
||||
| "bdo"
|
||||
| "big"
|
||||
| "blockquote"
|
||||
| "body"
|
||||
| "br"
|
||||
| "button"
|
||||
| "canvas"
|
||||
| "caption"
|
||||
| "center"
|
||||
| "cite"
|
||||
| "code"
|
||||
| "col"
|
||||
| "colgroup"
|
||||
| "data"
|
||||
| "datalist"
|
||||
| "dd"
|
||||
| "del"
|
||||
| "details"
|
||||
| "dfn"
|
||||
| "dialog"
|
||||
| "div"
|
||||
| "dl"
|
||||
| "dt"
|
||||
| "em"
|
||||
| "embed"
|
||||
| "fieldset"
|
||||
| "figcaption"
|
||||
| "figure"
|
||||
| "footer"
|
||||
| "form"
|
||||
| "h1"
|
||||
| "h2"
|
||||
| "h3"
|
||||
| "h4"
|
||||
| "h5"
|
||||
| "h6"
|
||||
| "head"
|
||||
| "header"
|
||||
| "hr"
|
||||
| "html"
|
||||
| "i"
|
||||
| "iframe"
|
||||
| "img"
|
||||
| "input"
|
||||
| "ins"
|
||||
| "kbd"
|
||||
| "label"
|
||||
| "legend"
|
||||
| "li"
|
||||
| "link"
|
||||
| "main"
|
||||
| "map"
|
||||
| "mark"
|
||||
| "meta"
|
||||
| "meter"
|
||||
| "nav"
|
||||
| "noscript"
|
||||
| "object"
|
||||
| "ol"
|
||||
| "optgroup"
|
||||
| "option"
|
||||
| "output"
|
||||
| "p"
|
||||
| "param"
|
||||
| "picture"
|
||||
| "pre"
|
||||
| "progress"
|
||||
| "q"
|
||||
| "rp"
|
||||
| "rt"
|
||||
| "ruby"
|
||||
| "s"
|
||||
| "samp"
|
||||
| "script"
|
||||
| "section"
|
||||
| "select"
|
||||
| "small"
|
||||
| "source"
|
||||
| "span"
|
||||
| "strong"
|
||||
| "style"
|
||||
| "sub"
|
||||
| "summary"
|
||||
| "sup"
|
||||
| "svg"
|
||||
| "table"
|
||||
| "tbody"
|
||||
| "td"
|
||||
| "template"
|
||||
| "textarea"
|
||||
| "tfoot"
|
||||
| "th"
|
||||
| "thead"
|
||||
| "time"
|
||||
| "title"
|
||||
| "tr"
|
||||
| "track"
|
||||
| "u"
|
||||
| "ul"
|
||||
| "var"
|
||||
| "video"
|
||||
| "wbr"
|
||||
)
|
||||
}
|
||||
|
||||
fn is_self_closing(tag: &str) -> bool {
|
||||
matches!(
|
||||
tag,
|
||||
"!DOCTYPE"
|
||||
| "area"
|
||||
| "base"
|
||||
| "br"
|
||||
| "col"
|
||||
| "embed"
|
||||
| "hr"
|
||||
| "img"
|
||||
| "input"
|
||||
| "link"
|
||||
| "meta"
|
||||
| "param"
|
||||
| "source"
|
||||
| "track"
|
||||
| "wbr"
|
||||
)
|
||||
}
|
|
@ -1,3 +1,544 @@
|
|||
fn main() {
|
||||
println!("Hello, world!");
|
||||
#![feature(array_windows)]
|
||||
#![feature(write_all_vectored)]
|
||||
use {
|
||||
aes_gcm::{
|
||||
aead::{self, AeadMutInPlace},
|
||||
AeadCore, Aes256Gcm, KeyInit,
|
||||
},
|
||||
ed25519_dalek::ed25519::signature::Signer,
|
||||
rand_core::OsRng,
|
||||
std::{
|
||||
collections::{HashMap, HashSet},
|
||||
fmt, fs,
|
||||
io::{self, IoSlice, IoSliceMut, Read, Write},
|
||||
mem::{self, MaybeUninit},
|
||||
net::{Ipv4Addr, SocketAddrV4, TcpListener, TcpStream},
|
||||
path::PathBuf,
|
||||
slice,
|
||||
str::FromStr,
|
||||
sync::{atomic, OnceLock},
|
||||
time,
|
||||
},
|
||||
x25519_dalek::{EphemeralSecret, SharedSecret},
|
||||
};
|
||||
|
||||
static CONN_COUNT: atomic::AtomicUsize = atomic::AtomicUsize::new(0);
|
||||
static USER_DATA_DIR: OnceLock<PathBuf> = OnceLock::new();
|
||||
static SERVER_SECRET: OnceLock<ed25519_dalek::SigningKey> = OnceLock::new();
|
||||
|
||||
#[derive(Default)]
|
||||
struct Cli {
|
||||
program: String,
|
||||
args: Vec<String>,
|
||||
flags: HashSet<String>,
|
||||
options: HashMap<String, String>,
|
||||
}
|
||||
|
||||
impl Cli {
|
||||
pub fn parse() -> Self {
|
||||
let mut s = Self::default();
|
||||
let mut args = std::env::args();
|
||||
s.program = args.next().unwrap();
|
||||
|
||||
for arg in args {
|
||||
if let Some(arg) = arg.strip_prefix("--") {
|
||||
match arg.split_once('=') {
|
||||
Some((name, value)) => _ = s.options.insert(name.to_owned(), value.to_owned()),
|
||||
None => _ = s.flags.insert(arg.to_string()),
|
||||
}
|
||||
} else {
|
||||
s.args.push(arg);
|
||||
}
|
||||
}
|
||||
|
||||
s
|
||||
}
|
||||
|
||||
pub fn arg(&self, index: usize) -> &str {
|
||||
self.args.get(index).map_or("", String::as_str)
|
||||
}
|
||||
|
||||
pub fn expect_option(&self, name: &str) -> &str {
|
||||
self.options.get(name).unwrap_or_else(|| panic!("--{name} is mandatory"))
|
||||
}
|
||||
|
||||
pub fn expect_poption<T: FromStr<Err: fmt::Display>>(&self, name: &str) -> T {
|
||||
self.expect_option(name).parse::<T>().unwrap_or_else(|e| {
|
||||
panic!("failed to parse --{name} as {}: {e}", std::any::type_name::<T>())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
type Subcommand<'a> = (&'a str, &'a str, fn(&Cli) -> io::Result<()>);
|
||||
|
||||
fn help<T>(subs: &[(&str, &str, T)]) -> io::Result<()> {
|
||||
for (name, desc, _) in subs {
|
||||
eprintln!("{name} - {desc}");
|
||||
}
|
||||
Err(io::ErrorKind::NotFound.into())
|
||||
}
|
||||
|
||||
const SUBCOMMANDS: &[Subcommand] = &[
|
||||
("help", "print command descriptions", |_| help(SUBCOMMANDS)),
|
||||
("serve", "run the server", |cli| {
|
||||
let port = cli.expect_poption::<u16>("port");
|
||||
let max_conns = cli.expect_poption::<usize>("max-conns");
|
||||
USER_DATA_DIR.set(cli.expect_poption("user-data-path")).unwrap();
|
||||
SERVER_SECRET.set(cli.expect_poption::<HexSk>("secret").0).unwrap();
|
||||
let listener = TcpListener::bind((Ipv4Addr::UNSPECIFIED, port)).unwrap();
|
||||
for incoming in listener.incoming() {
|
||||
match incoming {
|
||||
Ok(c) => {
|
||||
if CONN_COUNT.fetch_add(1, atomic::Ordering::Relaxed) >= max_conns {
|
||||
CONN_COUNT.fetch_sub(1, atomic::Ordering::Relaxed);
|
||||
continue;
|
||||
}
|
||||
|
||||
std::thread::spawn(move || {
|
||||
_ = handle_client(c);
|
||||
CONN_COUNT.fetch_sub(1, atomic::Ordering::Relaxed);
|
||||
});
|
||||
}
|
||||
Err(e) => {
|
||||
eprintln!("accepting conn conn: {e}")
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}),
|
||||
("make-profile", "create profile file (private key + name)", |cli| {
|
||||
let name = cli.expect_option("name");
|
||||
let name = str_as_username(name)
|
||||
.ok_or(io::ErrorKind::InvalidData)
|
||||
.ctx("name is limmited to 32 characters")?;
|
||||
|
||||
let &key = ed25519_dalek::SigningKey::generate(&mut rand_core::OsRng).as_bytes();
|
||||
let profile = UserProfile { name, key };
|
||||
|
||||
let out_file = cli.expect_option("out-file");
|
||||
_ = fs::write(out_file, as_bytes(&profile)).ctx("while saving profile file");
|
||||
Ok(())
|
||||
}),
|
||||
("consume", "connect to server and do an action", |cli| {
|
||||
let profile_path = cli.expect_option("profile");
|
||||
let mut profile_file = fs::File::open(profile_path).ctx("opening profile file")?;
|
||||
let profile: UserProfile = read_struct(&mut profile_file).ctx("reading the profile")?;
|
||||
let sx = x25519_dalek::EphemeralSecret::random_from_rng(OsRng);
|
||||
let auth = UserAuth::sign(profile, &sx);
|
||||
|
||||
let addr = cli.expect_poption::<SocketAddrV4>("addr");
|
||||
let mut stream = TcpStream::connect(addr).ctx("creating connection to the server")?;
|
||||
write_struct(&mut stream, &auth).ctx("sending initial handshake packet")?;
|
||||
|
||||
let HexPk(server_identity) = cli.expect_poption("server-identity");
|
||||
let sauth: ServerAuth = read_struct(&mut stream).ctx("reading server auth")?;
|
||||
let secret = sauth
|
||||
.verify(auth.pk, server_identity, sx)
|
||||
.map_err(|_| io::ErrorKind::PermissionDenied)
|
||||
.ctx("authenticating server")?;
|
||||
let stream = EncriptedStream::new(stream, secret);
|
||||
|
||||
select_subcommand(1, CONSUME_SUBCOMMAND, cli)(cli, stream)
|
||||
}),
|
||||
];
|
||||
|
||||
type ConsumeSubcommand<'a> = (&'a str, &'a str, fn(&Cli, EncriptedStream) -> io::Result<()>);
|
||||
|
||||
const CONSUME_SUBCOMMAND: &[ConsumeSubcommand] = &[
|
||||
("help", "this help message", |_, _| help(CONSUME_SUBCOMMAND)),
|
||||
("ping", "ping the server to check the connection", |_, mut stream| {
|
||||
write_struct(&mut stream, &Qid::Ping)
|
||||
}), //
|
||||
];
|
||||
|
||||
fn hex_to_array<const SIZE: usize>(s: &str) -> Result<[u8; SIZE], &'static str> {
|
||||
let mut buf = [0u8; SIZE];
|
||||
|
||||
if s.len() != SIZE * 2 {
|
||||
return Err("expected 64 character hex string");
|
||||
}
|
||||
|
||||
fn byte_to_hex(val: u8) -> Result<u8, &'static str> {
|
||||
Ok(match val {
|
||||
b'0'..=b'9' => val - b'0',
|
||||
b'a'..=b'f' => val - b'a' + 10,
|
||||
b'A'..=b'F' => val - b'A' + 10,
|
||||
_ => return Err("invalid hex char"),
|
||||
})
|
||||
}
|
||||
|
||||
for (dst, &[a, b]) in buf.iter_mut().zip(s.as_bytes().array_windows()) {
|
||||
*dst = byte_to_hex(a)? | (byte_to_hex(b)? << 4);
|
||||
}
|
||||
|
||||
Ok(buf)
|
||||
}
|
||||
|
||||
struct HexPk(ed25519_dalek::VerifyingKey);
|
||||
|
||||
impl std::str::FromStr for HexPk {
|
||||
type Err = &'static str;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
ed25519_dalek::VerifyingKey::from_bytes(&hex_to_array(s)?)
|
||||
.map_err(|_| "hex code does not represent the valid key")
|
||||
.map(Self)
|
||||
}
|
||||
}
|
||||
|
||||
struct HexSk(ed25519_dalek::SigningKey);
|
||||
|
||||
impl std::str::FromStr for HexSk {
|
||||
type Err = &'static str;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
Ok(Self(ed25519_dalek::SigningKey::from_bytes(&hex_to_array(s)?)))
|
||||
}
|
||||
}
|
||||
|
||||
fn select_subcommand<'a, T>(depth: usize, list: &'a [(&str, &str, T)], cli: &Cli) -> &'a T {
|
||||
&list.iter().find(|&&(name, ..)| name == cli.arg(depth)).unwrap_or(&list[0]).2
|
||||
}
|
||||
|
||||
fn main() -> io::Result<()> {
|
||||
let cli = Cli::parse();
|
||||
select_subcommand(0, SUBCOMMANDS, &cli)(&cli)
|
||||
}
|
||||
|
||||
fn handle_client(mut stream: TcpStream) -> io::Result<()> {
|
||||
let (user, sec) = {
|
||||
let user_auth: UserAuth = read_struct(&mut stream).ctx("reading auth packet")?;
|
||||
let sx = x25519_dalek::EphemeralSecret::random_from_rng(OsRng);
|
||||
let pk = x25519_dalek::PublicKey::from(&sx);
|
||||
let user = UserData::load(&user_auth, sx).ctx("loading user data")?;
|
||||
let sauth = ServerAuth::sign(&user_auth, SERVER_SECRET.get().unwrap(), pk);
|
||||
write_struct(&mut stream, &sauth).ctx("sending handshare response")?;
|
||||
user
|
||||
};
|
||||
|
||||
let mut stream = EncriptedStream::new(stream, sec);
|
||||
|
||||
loop {
|
||||
match Qid::try_from(read_struct::<u16>(&mut stream)?)? {
|
||||
Qid::Ping => write_struct(&mut stream, &Aid::Pong)?,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(u16)]
|
||||
enum Aid {
|
||||
Pong,
|
||||
}
|
||||
|
||||
#[repr(u16)]
|
||||
enum Qid {
|
||||
Ping,
|
||||
}
|
||||
|
||||
impl TryFrom<u16> for Qid {
|
||||
type Error = io::ErrorKind;
|
||||
|
||||
fn try_from(value: u16) -> Result<Self, Self::Error> {
|
||||
if value <= Self::Ping as u16 {
|
||||
Ok(unsafe { mem::transmute::<u16, Qid>(value) })
|
||||
} else {
|
||||
Err(io::ErrorKind::NotFound)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
trait Ctx {
|
||||
fn ctx(self, label: &str) -> Self;
|
||||
}
|
||||
|
||||
impl<O, E: fmt::Display> Ctx for Result<O, E> {
|
||||
fn ctx(self, label: &str) -> Self {
|
||||
if let Err(e) = &self {
|
||||
eprintln!("{label}: {e}")
|
||||
}
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
const ASOC_DATA: &[u8] = b"testicle torsion vizard";
|
||||
|
||||
struct EncriptedStream {
|
||||
inner: TcpStream,
|
||||
key: SharedSecret,
|
||||
buf: Vec<u8>,
|
||||
}
|
||||
|
||||
impl EncriptedStream {
|
||||
fn new(inner: TcpStream, key: SharedSecret) -> Self {
|
||||
Self { inner, key, buf: Default::default() }
|
||||
}
|
||||
}
|
||||
|
||||
impl Read for EncriptedStream {
|
||||
fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> {
|
||||
let mut tag = MaybeUninit::<aead::Tag<Aes256Gcm>>::uninit();
|
||||
let mut nonce = MaybeUninit::<aead::Nonce<Aes256Gcm>>::uninit();
|
||||
|
||||
let mut bufs = &mut [
|
||||
IoSliceMut::new(as_mut_bytes(&mut tag)),
|
||||
IoSliceMut::new(as_mut_bytes(&mut nonce)),
|
||||
IoSliceMut::new(buf),
|
||||
][..];
|
||||
|
||||
loop {
|
||||
let red = self.inner.read_vectored(bufs)?;
|
||||
if red == 0 {
|
||||
return Err(io::ErrorKind::UnexpectedEof.into());
|
||||
}
|
||||
IoSliceMut::advance_slices(&mut bufs, red);
|
||||
if bufs.is_empty() {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
unsafe {
|
||||
Aes256Gcm::new(self.key.as_bytes().into())
|
||||
.decrypt_in_place_detached(&nonce.assume_init(), ASOC_DATA, buf, &tag.assume_init())
|
||||
.map_err(|_| io::ErrorKind::PermissionDenied)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn read(&mut self, _: &mut [u8]) -> io::Result<usize> {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
||||
impl Write for EncriptedStream {
|
||||
fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
|
||||
self.buf.clear();
|
||||
self.buf.extend(buf);
|
||||
|
||||
let nonce = Aes256Gcm::generate_nonce(OsRng);
|
||||
let tag = Aes256Gcm::new(self.key.as_bytes().into())
|
||||
.encrypt_in_place_detached(&nonce, ASOC_DATA, &mut self.buf)
|
||||
.unwrap();
|
||||
|
||||
self.inner.write_all_vectored(&mut [
|
||||
IoSlice::new(as_bytes(&tag)),
|
||||
IoSlice::new(as_bytes(&nonce)),
|
||||
IoSlice::new(&self.buf),
|
||||
])
|
||||
}
|
||||
|
||||
fn flush(&mut self) -> io::Result<()> {
|
||||
self.inner.flush()
|
||||
}
|
||||
|
||||
fn write(&mut self, _: &[u8]) -> io::Result<usize> {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
||||
fn read_struct<T>(stream: &mut impl Read) -> io::Result<T> {
|
||||
let mut res = mem::MaybeUninit::uninit();
|
||||
stream.read_exact(as_mut_bytes(&mut res))?;
|
||||
unsafe { res.assume_init() }
|
||||
}
|
||||
|
||||
fn write_struct<T>(stream: &mut impl Write, value: &T) -> io::Result<()> {
|
||||
stream.write_all(as_bytes(value))
|
||||
}
|
||||
|
||||
fn as_mut_bytes<T>(value: &mut T) -> &mut [u8] {
|
||||
unsafe { slice::from_raw_parts_mut(value as *mut _ as *mut u8, mem::size_of::<T>()) }
|
||||
}
|
||||
|
||||
fn as_bytes<T>(value: &T) -> &[u8] {
|
||||
unsafe { slice::from_raw_parts(value as *const _ as *const u8, mem::size_of::<T>()) }
|
||||
}
|
||||
|
||||
type Username = [u8; 32];
|
||||
type Postname = [u8; 64];
|
||||
type Pk = [u8; 32];
|
||||
type Nonce = u64;
|
||||
|
||||
fn username_as_str(name: &Username) -> Option<&str> {
|
||||
let len = name.iter().rposition(|&b| b != 0xff)? + 1;
|
||||
std::str::from_utf8(&name[..len]).ok()
|
||||
}
|
||||
|
||||
fn str_as_username(name: &str) -> Option<Username> {
|
||||
if name.len() > mem::size_of::<Username>() {
|
||||
return None;
|
||||
}
|
||||
let mut buff = [0xffu8; mem::size_of::<Username>()];
|
||||
buff[..name.len()].copy_from_slice(name.as_bytes());
|
||||
Some(buff)
|
||||
}
|
||||
|
||||
#[repr(packed)]
|
||||
struct UserProfile {
|
||||
name: Username,
|
||||
key: ed25519_dalek::SecretKey,
|
||||
}
|
||||
|
||||
#[repr(packed)]
|
||||
struct UserAuth {
|
||||
signature: ed25519_dalek::Signature,
|
||||
pk: Pk,
|
||||
x: x25519_dalek::PublicKey,
|
||||
name: Username,
|
||||
nonce: Nonce,
|
||||
}
|
||||
|
||||
impl UserAuth {
|
||||
fn sign(UserProfile { name, key }: UserProfile, sx: &x25519_dalek::EphemeralSecret) -> Self {
|
||||
let nonce =
|
||||
time::SystemTime::now().duration_since(time::SystemTime::UNIX_EPOCH).unwrap().as_secs();
|
||||
let mut message = [0; mem::size_of::<Username>() + mem::size_of::<u64>()];
|
||||
message[..mem::size_of::<Username>()].copy_from_slice(&name);
|
||||
message[mem::size_of::<Username>()..].copy_from_slice(&nonce.to_le_bytes());
|
||||
|
||||
let signing_key = ed25519_dalek::SigningKey::from_bytes(&key);
|
||||
let signature = signing_key.sign(&message);
|
||||
let pk = ed25519_dalek::VerifyingKey::from(&signing_key).to_bytes();
|
||||
let x = x25519_dalek::PublicKey::from(sx);
|
||||
|
||||
Self { signature, pk, x, name, nonce }
|
||||
}
|
||||
|
||||
fn verify(
|
||||
&self,
|
||||
pk: Pk,
|
||||
nonce: Nonce,
|
||||
sx: x25519_dalek::EphemeralSecret,
|
||||
) -> Result<SharedSecret, ed25519_dalek::SignatureError> {
|
||||
if nonce >= self.nonce {
|
||||
eprintln!("invalid auth nonce");
|
||||
return Err(ed25519_dalek::SignatureError::default());
|
||||
}
|
||||
|
||||
let pk = ed25519_dalek::VerifyingKey::from_bytes(&pk)?;
|
||||
|
||||
let mut message = [0; mem::size_of::<Username>() + mem::size_of::<u64>()];
|
||||
message[..mem::size_of::<Username>()].copy_from_slice(&self.name);
|
||||
message[mem::size_of::<Username>()..].copy_from_slice(&nonce.to_le_bytes());
|
||||
|
||||
pk.verify_strict(&message, &self.signature)?;
|
||||
|
||||
Ok(sx.diffie_hellman(&self.x))
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(packed)]
|
||||
struct ServerAuth {
|
||||
signature: ed25519_dalek::Signature,
|
||||
x: x25519_dalek::PublicKey,
|
||||
}
|
||||
|
||||
impl ServerAuth {
|
||||
fn sign(
|
||||
user_auth: &UserAuth,
|
||||
sk: &ed25519_dalek::SigningKey,
|
||||
x: x25519_dalek::PublicKey,
|
||||
) -> Self {
|
||||
let signature = sk.sign(user_auth.x.as_bytes());
|
||||
Self { signature, x }
|
||||
}
|
||||
|
||||
fn verify(
|
||||
&self,
|
||||
x: Pk,
|
||||
pk: ed25519_dalek::VerifyingKey,
|
||||
sx: EphemeralSecret,
|
||||
) -> Result<SharedSecret, ed25519_dalek::SignatureError> {
|
||||
pk.verify_strict(&x, &self.signature)?;
|
||||
Ok(sx.diffie_hellman(&self.x))
|
||||
}
|
||||
}
|
||||
|
||||
struct UserData {
|
||||
header: UserHeader,
|
||||
post_headers: fs::File,
|
||||
posts: fs::File,
|
||||
}
|
||||
|
||||
impl UserData {
|
||||
fn load(
|
||||
auth: &UserAuth,
|
||||
sx: x25519_dalek::EphemeralSecret,
|
||||
) -> io::Result<(Self, SharedSecret)> {
|
||||
const HEADER_PATH: &str = "header.bin";
|
||||
const POST_HEADERS_PATH: &str = "post-headers.bin";
|
||||
const POST_PATH: &str = "posts.bin";
|
||||
|
||||
let mut path = PathBuf::from_iter([
|
||||
USER_DATA_DIR.get().unwrap().as_path(),
|
||||
username_as_str(&auth.name).ok_or(io::ErrorKind::InvalidData)?.as_ref(),
|
||||
]);
|
||||
|
||||
if path.exists() {
|
||||
path.push(HEADER_PATH);
|
||||
let mut header_file = fs::File::open(&path).ctx("opening user header file")?;
|
||||
let mut header: UserHeader =
|
||||
read_struct(&mut header_file).ctx("reading the user header")?;
|
||||
path.pop();
|
||||
|
||||
let secret = auth
|
||||
.verify(header.pk, header.nonce, sx)
|
||||
.map_err(|_| io::ErrorKind::PermissionDenied)
|
||||
.ctx("authenticating user")?;
|
||||
|
||||
header.nonce = auth.nonce;
|
||||
write_struct(&mut header_file, &header).ctx("saving user nonce")?;
|
||||
|
||||
path.push(POST_HEADERS_PATH);
|
||||
let post_headers = fs::File::open(&path).ctx("opening user post header file")?;
|
||||
path.pop();
|
||||
|
||||
path.push(POST_PATH);
|
||||
let posts = fs::File::open(&path).ctx("opening user post file")?;
|
||||
path.pop();
|
||||
|
||||
Ok((Self { header, post_headers, posts }, secret))
|
||||
} else {
|
||||
let secret = auth
|
||||
.verify(auth.pk, 0, sx)
|
||||
.map_err(|_| io::ErrorKind::PermissionDenied)
|
||||
.ctx("verifiing registratio signature")?;
|
||||
|
||||
fs::create_dir_all(&path).ctx("creating new user directory")?;
|
||||
path.push(HEADER_PATH);
|
||||
let header =
|
||||
UserHeader { pk: auth.pk, nonce: auth.nonce, post_count: 0, runs: 0, imports: 0 };
|
||||
fs::write(&path, as_bytes(&header)).ctx("writing new user header")?;
|
||||
path.pop();
|
||||
|
||||
path.push(POST_HEADERS_PATH);
|
||||
let post_headers = fs::File::create_new(&path).ctx("creating new user post headers")?;
|
||||
path.pop();
|
||||
|
||||
path.push(POST_PATH);
|
||||
let posts = fs::File::create_new(&path).ctx("creating new user posts")?;
|
||||
path.pop();
|
||||
|
||||
Ok((Self { header, post_headers, posts }, secret))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(packed)]
|
||||
struct UserHeader {
|
||||
pk: Pk,
|
||||
nonce: Nonce,
|
||||
post_count: u32,
|
||||
imports: u32,
|
||||
runs: u32,
|
||||
}
|
||||
|
||||
#[repr(packed)]
|
||||
struct PostHeader {
|
||||
name: Postname,
|
||||
timestamp: u64,
|
||||
size: u32,
|
||||
offset: u32,
|
||||
imports: u32,
|
||||
runs: u32,
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue