mirror of
https://github.com/aljazceru/pubky-core.git
synced 2026-01-10 09:44:20 +01:00
Merge pull request #46 from pubky/feat/add-head-endpoint
Feat/add head endpoint
This commit is contained in:
152
Cargo.lock
generated
152
Cargo.lock
generated
@@ -4,9 +4,9 @@ version = 3
|
||||
|
||||
[[package]]
|
||||
name = "addr2line"
|
||||
version = "0.24.1"
|
||||
version = "0.24.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f5fb1d8e4442bd405fdfd1dacb42792696b0cf9cb15882e5d097b742a676d375"
|
||||
checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1"
|
||||
dependencies = [
|
||||
"gimli",
|
||||
]
|
||||
@@ -362,9 +362,9 @@ checksum = "428d9aa8fbc0670b7b8d6030a7fadd0f86151cae55e4dbbece15f3780a3dfaf3"
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.1.22"
|
||||
version = "1.1.30"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9540e661f81799159abee814118cc139a2004b3a3aa3ea37724a1b66530b90e0"
|
||||
checksum = "b16803a61b81d9eabb7eae2588776c4c1e584b738ede45fdbb4c972cec1e9945"
|
||||
dependencies = [
|
||||
"shlex",
|
||||
]
|
||||
@@ -388,9 +388,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "4.5.18"
|
||||
version = "4.5.20"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b0956a43b323ac1afaffc053ed5c4b7c1f1800bacd1683c353aabbb752515dd3"
|
||||
checksum = "b97f376d85a664d5837dbae44bf546e6477a679ff6610010f17276f686d867e8"
|
||||
dependencies = [
|
||||
"clap_builder",
|
||||
"clap_derive",
|
||||
@@ -398,9 +398,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "clap_builder"
|
||||
version = "4.5.18"
|
||||
version = "4.5.20"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4d72166dd41634086d5803a47eb71ae740e61d84709c36f3c34110173db3961b"
|
||||
checksum = "19bc80abd44e4bed93ca373a0704ccbd1b710dc5749406201bb018272808dc54"
|
||||
dependencies = [
|
||||
"anstream",
|
||||
"anstyle",
|
||||
@@ -520,9 +520,9 @@ checksum = "19d374276b40fb8bbdee95aef7c7fa6b5316ec764510eb64b8dd0e2ed0d7e7f5"
|
||||
|
||||
[[package]]
|
||||
name = "critical-section"
|
||||
version = "1.1.3"
|
||||
version = "1.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f64009896348fc5af4222e9cf7d7d82a95a256c634ebcf61c53e4ea461422242"
|
||||
checksum = "790eea4361631c5e7d22598ecd5723ff611904e3344ce8720784c93e3d83d40b"
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-queue"
|
||||
@@ -899,9 +899,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "gimli"
|
||||
version = "0.31.0"
|
||||
version = "0.31.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "32085ea23f3234fc7846555e85283ba4de91e21016dc0455a16286d87a292d64"
|
||||
checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f"
|
||||
|
||||
[[package]]
|
||||
name = "h2"
|
||||
@@ -933,9 +933,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.14.5"
|
||||
version = "0.15.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1"
|
||||
checksum = "1e087f84d4f86bf4b218b927129862374b72199ae7d8657835f1e89000eea4fb"
|
||||
|
||||
[[package]]
|
||||
name = "headers"
|
||||
@@ -1067,9 +1067,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "httparse"
|
||||
version = "1.9.4"
|
||||
version = "1.9.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0fcc0b4a115bf80b728eb8ea024ad5bd707b615bfed49e0665b6e0f86fd082d9"
|
||||
checksum = "7d71d3574edd2771538b901e6549113b4006ece66150fb69c0fb6d9a2adae946"
|
||||
|
||||
[[package]]
|
||||
name = "httpdate"
|
||||
@@ -1079,9 +1079,9 @@ checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9"
|
||||
|
||||
[[package]]
|
||||
name = "hyper"
|
||||
version = "1.4.1"
|
||||
version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "50dfd22e0e76d0f662d429a5f80fcaf3855009297eab6a0a9f8543834744ba05"
|
||||
checksum = "bbbff0a806a4728c99295b254c8838933b5b082d75e3cb70c8dab21fdfbcfa9a"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"futures-channel",
|
||||
@@ -1173,9 +1173,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "indexmap"
|
||||
version = "2.5.0"
|
||||
version = "2.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "68b900aa2f7301e21c36462b170ee99994de34dff39a4a6a528e80e7376d07e5"
|
||||
checksum = "707907fe3c25f5424cce2cb7e1cbcafee6bdbe735ca90ef77c29e84591e5b9da"
|
||||
dependencies = [
|
||||
"equivalent",
|
||||
"hashbrown",
|
||||
@@ -1192,9 +1192,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ipnet"
|
||||
version = "2.10.0"
|
||||
version = "2.10.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "187674a687eed5fe42285b40c6291f9a01517d415fad1c3cbc6a9f778af7fcd4"
|
||||
checksum = "ddc24109865250148c2e0f3d25d4f0f479571723792d3802153c60922a4fb708"
|
||||
|
||||
[[package]]
|
||||
name = "is_terminal_polyfill"
|
||||
@@ -1210,9 +1210,9 @@ checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b"
|
||||
|
||||
[[package]]
|
||||
name = "js-sys"
|
||||
version = "0.3.70"
|
||||
version = "0.3.72"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1868808506b929d7b0cfa8f75951347aa71bb21144b7791bae35d9bccfcfe37a"
|
||||
checksum = "6a88f1bda2bd75b0452a14784937d796722fdebfe50df998aeb3f0b7603019a9"
|
||||
dependencies = [
|
||||
"wasm-bindgen",
|
||||
]
|
||||
@@ -1225,9 +1225,9 @@ checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.159"
|
||||
version = "0.2.160"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "561d97a539a36e26a9a5fad1ea11a3039a67714694aaa379433e580854bc3dc5"
|
||||
checksum = "f0b21006cd1874ae9e650973c565615676dc4a274c965bb0a73796dac838ce4f"
|
||||
|
||||
[[package]]
|
||||
name = "libredox"
|
||||
@@ -1280,9 +1280,9 @@ checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24"
|
||||
|
||||
[[package]]
|
||||
name = "lru"
|
||||
version = "0.12.4"
|
||||
version = "0.12.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "37ee39891760e7d94734f6f63fedc29a2e4a152f836120753a72503f09fcf904"
|
||||
checksum = "234cf4f4a04dc1f57e24b96cc0cd600cf2af460d4161ac5ecdd0af8e1f3b2a38"
|
||||
|
||||
[[package]]
|
||||
name = "mainline"
|
||||
@@ -1396,21 +1396,18 @@ checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9"
|
||||
|
||||
[[package]]
|
||||
name = "object"
|
||||
version = "0.36.4"
|
||||
version = "0.36.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "084f1a5821ac4c651660a94a7153d27ac9d8a53736203f58b31945ded098070a"
|
||||
checksum = "aedf0a2d09c573ed1d8d85b30c119153926a2b36dce0ab28322c09a117a4683e"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "once_cell"
|
||||
version = "1.20.1"
|
||||
version = "1.20.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "82881c4be219ab5faaf2ad5e5e5ecdff8c66bd7402ca3160975c93b24961afd1"
|
||||
dependencies = [
|
||||
"portable-atomic",
|
||||
]
|
||||
checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775"
|
||||
|
||||
[[package]]
|
||||
name = "opaque-debug"
|
||||
@@ -1420,9 +1417,9 @@ checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381"
|
||||
|
||||
[[package]]
|
||||
name = "openssl"
|
||||
version = "0.10.66"
|
||||
version = "0.10.68"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9529f4786b70a3e8c61e11179af17ab6188ad8d0ded78c5529441ed39d4bd9c1"
|
||||
checksum = "6174bc48f102d208783c2c84bf931bb75927a617866870de8a4ea85597f871f5"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"cfg-if",
|
||||
@@ -1452,9 +1449,9 @@ checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf"
|
||||
|
||||
[[package]]
|
||||
name = "openssl-sys"
|
||||
version = "0.9.103"
|
||||
version = "0.9.104"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7f9e8deee91df40a943c71b917e5874b951d32a802526c85721ce3b776c929d6"
|
||||
checksum = "45abf306cbf99debc8195b66b7346498d7b10c210de50418b5ccd7ceba08c741"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"libc",
|
||||
@@ -1575,7 +1572,7 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
|
||||
[[package]]
|
||||
name = "pkarr"
|
||||
version = "2.2.0"
|
||||
source = "git+https://github.com/Pubky/pkarr?branch=serde#680ec9303f5f3ee4b40dc53c0071c4088d4eb6ff"
|
||||
source = "git+https://github.com/Pubky/pkarr?branch=serde#61232ffa1b81be20530dfb81fe31273e2c860977"
|
||||
dependencies = [
|
||||
"base32",
|
||||
"bytes",
|
||||
@@ -1625,12 +1622,6 @@ dependencies = [
|
||||
"universal-hash",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "portable-atomic"
|
||||
version = "1.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cc9c68a3f6da06753e9335d63e27f6b9754dd1920d941135b7ea8224f141adb2"
|
||||
|
||||
[[package]]
|
||||
name = "postcard"
|
||||
version = "1.0.10"
|
||||
@@ -1661,9 +1652,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.86"
|
||||
version = "1.0.88"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77"
|
||||
checksum = "7c3a7fc5db1e57d5a779a352c8cdb57b29aa4c40cc69c3a68a7fedc815fbf2f9"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
@@ -1705,11 +1696,27 @@ dependencies = [
|
||||
"once_cell",
|
||||
"pkarr",
|
||||
"postcard",
|
||||
"pubky-timestamp",
|
||||
"rand",
|
||||
"serde",
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pubky-timestamp"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "084b6e5bfcc186781b71257d636b660f20e94bb588c3ba52393fd9faf7a7bfda"
|
||||
dependencies = [
|
||||
"base32",
|
||||
"document-features",
|
||||
"getrandom",
|
||||
"httpdate",
|
||||
"js-sys",
|
||||
"once_cell",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pubky_homeserver"
|
||||
version = "0.1.0"
|
||||
@@ -2022,9 +2029,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "rustls"
|
||||
version = "0.23.13"
|
||||
version = "0.23.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f2dabaac7466917e566adb06783a81ca48944c6898a1b08b9374106dd671f4c8"
|
||||
checksum = "5fbb44d7acc4e873d613422379f69f237a1b141928c02f6bc6ccfddddc2d7993"
|
||||
dependencies = [
|
||||
"once_cell",
|
||||
"ring",
|
||||
@@ -2036,19 +2043,18 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "rustls-pemfile"
|
||||
version = "2.1.3"
|
||||
version = "2.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "196fe16b00e106300d3e45ecfcb764fa292a535d7326a29a5875c579c7417425"
|
||||
checksum = "dce314e5fee3f39953d46bb63bb8a46d40c2f8fb7cc5a3b6cab2bde9721d6e50"
|
||||
dependencies = [
|
||||
"base64 0.22.1",
|
||||
"rustls-pki-types",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustls-pki-types"
|
||||
version = "1.9.0"
|
||||
version = "1.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0e696e35370c65c9c541198af4543ccd580cf17fc25d8e05c5a242b202488c55"
|
||||
checksum = "16f1201b3c9a7ee8039bcadc17b7e605e2945b27eee7631788c1bd2b0643674b"
|
||||
|
||||
[[package]]
|
||||
name = "rustls-webpki"
|
||||
@@ -2063,9 +2069,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "rustversion"
|
||||
version = "1.0.17"
|
||||
version = "1.0.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "955d28af4278de8121b7ebeb796b6a45735dc01436d898801014aced2773a3d6"
|
||||
checksum = "0e819f2bc632f285be6d7cd36e25940d45b2391dd6d9b939e79de557f7014248"
|
||||
|
||||
[[package]]
|
||||
name = "ryu"
|
||||
@@ -2732,9 +2738,9 @@ checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-bidi"
|
||||
version = "0.3.15"
|
||||
version = "0.3.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75"
|
||||
checksum = "5ab17db44d7388991a428b2ee655ce0c212e862eff1768a455c58f9aad6e7893"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
@@ -2819,9 +2825,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen"
|
||||
version = "0.2.93"
|
||||
version = "0.2.95"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a82edfc16a6c469f5f44dc7b571814045d60404b55a0ee849f9bcfa2e63dd9b5"
|
||||
checksum = "128d1e363af62632b8eb57219c8fd7877144af57558fb2ef0368d0087bddeb2e"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"once_cell",
|
||||
@@ -2830,9 +2836,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-backend"
|
||||
version = "0.2.93"
|
||||
version = "0.2.95"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9de396da306523044d3302746f1208fa71d7532227f15e347e2d93e4145dd77b"
|
||||
checksum = "cb6dd4d3ca0ddffd1dd1c9c04f94b868c37ff5fac97c30b97cff2d74fce3a358"
|
||||
dependencies = [
|
||||
"bumpalo",
|
||||
"log",
|
||||
@@ -2845,9 +2851,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-futures"
|
||||
version = "0.4.43"
|
||||
version = "0.4.45"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "61e9300f63a621e96ed275155c108eb6f843b6a26d053f122ab69724559dc8ed"
|
||||
checksum = "cc7ec4f8827a71586374db3e87abdb5a2bb3a15afed140221307c3ec06b1f63b"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"js-sys",
|
||||
@@ -2857,9 +2863,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro"
|
||||
version = "0.2.93"
|
||||
version = "0.2.95"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "585c4c91a46b072c92e908d99cb1dcdf95c5218eeb6f3bf1efa991ee7a68cccf"
|
||||
checksum = "e79384be7f8f5a9dd5d7167216f022090cf1f9ec128e6e6a482a2cb5c5422c56"
|
||||
dependencies = [
|
||||
"quote",
|
||||
"wasm-bindgen-macro-support",
|
||||
@@ -2867,9 +2873,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro-support"
|
||||
version = "0.2.93"
|
||||
version = "0.2.95"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "afc340c74d9005395cf9dd098506f7f44e38f2b4a21c6aaacf9a105ea5e1e836"
|
||||
checksum = "26c6ab57572f7a24a4985830b120de1594465e5d500f24afe89e16b4e833ef68"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -2880,15 +2886,15 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-shared"
|
||||
version = "0.2.93"
|
||||
version = "0.2.95"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c62a0a307cb4a311d3a07867860911ca130c3494e8c2719593806c08bc5d0484"
|
||||
checksum = "65fc09f10666a9f147042251e0dda9c18f166ff7de300607007e96bdebc1068d"
|
||||
|
||||
[[package]]
|
||||
name = "web-sys"
|
||||
version = "0.3.70"
|
||||
version = "0.3.72"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "26fdeaafd9bd129f65e7c031593c24d62186301e0c72c8978fa1678be7d532c0"
|
||||
checksum = "f6488b90108c040df0fe62fa815cbdee25124641df01814dd7282749234c6112"
|
||||
dependencies = [
|
||||
"js-sys",
|
||||
"wasm-bindgen",
|
||||
|
||||
@@ -10,7 +10,7 @@ members = [
|
||||
resolver = "2"
|
||||
|
||||
[workspace.dependencies]
|
||||
pkarr = { git = "https://github.com/Pubky/pkarr", branch = "serde", package = "pkarr", features = ["async"] }
|
||||
pkarr = { git = "https://github.com/Pubky/pkarr", branch = "serde", package = "pkarr", features = ["async", "serde"] }
|
||||
serde = { version = "^1.0.209", features = ["derive"] }
|
||||
|
||||
[profile.release]
|
||||
|
||||
@@ -8,7 +8,7 @@ edition = "2021"
|
||||
[dependencies]
|
||||
base32 = "0.5.0"
|
||||
blake3 = "1.5.1"
|
||||
ed25519-dalek = "2.1.1"
|
||||
ed25519-dalek = { version = "2.1.1", features = ["serde"] }
|
||||
once_cell = "1.19.0"
|
||||
pkarr = { workspace = true }
|
||||
rand = "0.8.5"
|
||||
@@ -17,17 +17,11 @@ postcard = { version = "1.0.8", features = ["alloc"] }
|
||||
crypto_secretbox = { version = "0.1.1", features = ["std"] }
|
||||
argon2 = { version = "0.5.3", features = ["std"] }
|
||||
|
||||
serde = { workspace = true, optional = true }
|
||||
serde = { workspace = true }
|
||||
pubky-timestamp = { version = "0.2.0", features = ["full"] }
|
||||
|
||||
[target.'cfg(target_arch = "wasm32")'.dependencies]
|
||||
js-sys = "0.3.69"
|
||||
|
||||
[dev-dependencies]
|
||||
postcard = "1.0.8"
|
||||
|
||||
[features]
|
||||
|
||||
serde = ["dep:serde", "ed25519-dalek/serde", "pkarr/serde"]
|
||||
full = ['serde']
|
||||
|
||||
default = ['full']
|
||||
|
||||
@@ -76,7 +76,7 @@ impl AuthToken {
|
||||
let now = Timestamp::now();
|
||||
|
||||
// Chcek timestamp;
|
||||
let diff = token.timestamp.difference(&now);
|
||||
let diff = token.timestamp.as_u64() as i64 - now.as_u64() as i64;
|
||||
if diff > TIMESTAMP_WINDOW {
|
||||
return Err(Error::TooFarInTheFuture);
|
||||
}
|
||||
@@ -155,7 +155,7 @@ impl AuthVerifier {
|
||||
|
||||
/// Remove all tokens older than two time intervals in the past.
|
||||
fn gc(&self) {
|
||||
let threshold = ((Timestamp::now().into_inner() / TIME_INTERVAL) - 2).to_be_bytes();
|
||||
let threshold = ((Timestamp::now().as_u64() / TIME_INTERVAL) - 2).to_be_bytes();
|
||||
|
||||
let mut inner = self.seen.lock().unwrap();
|
||||
|
||||
@@ -235,7 +235,7 @@ mod tests {
|
||||
|
||||
let verifier = AuthVerifier::default();
|
||||
|
||||
let timestamp = (&Timestamp::now()) - (TIMESTAMP_WINDOW as u64);
|
||||
let timestamp = (Timestamp::now()) - (TIMESTAMP_WINDOW as u64);
|
||||
|
||||
let mut signable = vec![];
|
||||
signable.extend_from_slice(signer.public_key().as_bytes());
|
||||
|
||||
@@ -4,4 +4,7 @@ pub mod crypto;
|
||||
pub mod namespaces;
|
||||
pub mod recovery_file;
|
||||
pub mod session;
|
||||
pub mod timestamp;
|
||||
|
||||
pub mod timestamp {
|
||||
pub use pubky_timestamp::*;
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@ impl Session {
|
||||
Self {
|
||||
version: 0,
|
||||
pubky: token.pubky().to_owned(),
|
||||
created_at: Timestamp::now().into_inner(),
|
||||
created_at: Timestamp::now().as_u64(),
|
||||
capabilities: token.capabilities().to_vec(),
|
||||
user_agent: user_agent.as_deref().unwrap_or("").to_string(),
|
||||
name: user_agent.as_deref().unwrap_or("").to_string(),
|
||||
|
||||
@@ -1,280 +0,0 @@
|
||||
//! Strictly monotonic unix timestamp in microseconds
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt::Display;
|
||||
use std::{
|
||||
ops::{Add, Sub},
|
||||
sync::Mutex,
|
||||
};
|
||||
|
||||
use once_cell::sync::Lazy;
|
||||
use rand::Rng;
|
||||
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
use std::time::SystemTime;
|
||||
|
||||
/// ~4% chance of none of 10 clocks have matching id.
|
||||
const CLOCK_MASK: u64 = (1 << 8) - 1;
|
||||
const TIME_MASK: u64 = !0 >> 8;
|
||||
|
||||
pub struct TimestampFactory {
|
||||
clock_id: u64,
|
||||
last_time: u64,
|
||||
}
|
||||
|
||||
impl TimestampFactory {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
clock_id: rand::thread_rng().gen::<u64>() & CLOCK_MASK,
|
||||
last_time: system_time() & TIME_MASK,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn now(&mut self) -> Timestamp {
|
||||
// Ensure strict monotonicity.
|
||||
self.last_time = (system_time() & TIME_MASK).max(self.last_time + CLOCK_MASK + 1);
|
||||
|
||||
// Add clock_id to the end of the timestamp
|
||||
Timestamp(self.last_time | self.clock_id)
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for TimestampFactory {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
static DEFAULT_FACTORY: Lazy<Mutex<TimestampFactory>> =
|
||||
Lazy::new(|| Mutex::new(TimestampFactory::default()));
|
||||
|
||||
/// STrictly monotonic timestamp since [SystemTime::UNIX_EPOCH] in microseconds as u64.
|
||||
///
|
||||
/// The purpose of this timestamp is to unique per "user", not globally,
|
||||
/// it achieves this by:
|
||||
/// 1. Override the last byte with a random `clock_id`, reducing the probability
|
||||
/// of two matching timestamps across multiple machines/threads.
|
||||
/// 2. Gurantee that the remaining 3 bytes are ever increasing (strictly monotonic) within
|
||||
/// the same thread regardless of the wall clock value
|
||||
///
|
||||
/// This timestamp is also serialized as BE bytes to remain sortable.
|
||||
/// If a `utf-8` encoding is necessary, it is encoded as [base32::Alphabet::Crockford]
|
||||
/// to act as a sortable Id.
|
||||
///
|
||||
/// U64 of microseconds is valid for the next 500 thousand years!
|
||||
#[derive(Debug, Clone, PartialEq, PartialOrd, Hash, Eq, Ord)]
|
||||
pub struct Timestamp(u64);
|
||||
|
||||
impl Timestamp {
|
||||
pub fn now() -> Self {
|
||||
DEFAULT_FACTORY.lock().unwrap().now()
|
||||
}
|
||||
|
||||
/// Return big endian bytes
|
||||
pub fn to_bytes(&self) -> [u8; 8] {
|
||||
self.0.to_be_bytes()
|
||||
}
|
||||
|
||||
pub fn difference(&self, rhs: &Timestamp) -> i64 {
|
||||
(self.0 as i64) - (rhs.0 as i64)
|
||||
}
|
||||
|
||||
pub fn into_inner(&self) -> u64 {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for Timestamp {
|
||||
fn default() -> Self {
|
||||
Timestamp::now()
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for Timestamp {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
let bytes: [u8; 8] = self.into();
|
||||
f.write_str(&base32::encode(base32::Alphabet::Crockford, &bytes))
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<String> for Timestamp {
|
||||
type Error = TimestampError;
|
||||
|
||||
fn try_from(value: String) -> Result<Self, Self::Error> {
|
||||
match base32::decode(base32::Alphabet::Crockford, &value) {
|
||||
Some(vec) => {
|
||||
let bytes: [u8; 8] = vec
|
||||
.try_into()
|
||||
.map_err(|_| TimestampError::InvalidEncoding)?;
|
||||
|
||||
Ok(bytes.into())
|
||||
}
|
||||
None => Err(TimestampError::InvalidEncoding),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<&[u8]> for Timestamp {
|
||||
type Error = TimestampError;
|
||||
|
||||
fn try_from(bytes: &[u8]) -> Result<Self, Self::Error> {
|
||||
let bytes: [u8; 8] = bytes
|
||||
.try_into()
|
||||
.map_err(|_| TimestampError::InvalidBytesLength(bytes.len()))?;
|
||||
|
||||
Ok(bytes.into())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&Timestamp> for [u8; 8] {
|
||||
fn from(timestamp: &Timestamp) -> Self {
|
||||
timestamp.0.to_be_bytes()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<[u8; 8]> for Timestamp {
|
||||
fn from(bytes: [u8; 8]) -> Self {
|
||||
Self(u64::from_be_bytes(bytes))
|
||||
}
|
||||
}
|
||||
|
||||
// === U64 conversion ===
|
||||
|
||||
impl From<Timestamp> for u64 {
|
||||
fn from(value: Timestamp) -> Self {
|
||||
value.into_inner()
|
||||
}
|
||||
}
|
||||
|
||||
impl Add<u64> for &Timestamp {
|
||||
type Output = Timestamp;
|
||||
|
||||
fn add(self, rhs: u64) -> Self::Output {
|
||||
Timestamp(self.0 + rhs)
|
||||
}
|
||||
}
|
||||
|
||||
impl Sub<u64> for &Timestamp {
|
||||
type Output = Timestamp;
|
||||
|
||||
fn sub(self, rhs: u64) -> Self::Output {
|
||||
Timestamp(self.0 - rhs)
|
||||
}
|
||||
}
|
||||
|
||||
impl Serialize for Timestamp {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: serde::Serializer,
|
||||
{
|
||||
let bytes = self.to_bytes();
|
||||
bytes.serialize(serializer)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de> Deserialize<'de> for Timestamp {
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
where
|
||||
D: serde::Deserializer<'de>,
|
||||
{
|
||||
let bytes: [u8; 8] = Deserialize::deserialize(deserializer)?;
|
||||
Ok(Timestamp(u64::from_be_bytes(bytes)))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
/// Return the number of microseconds since [SystemTime::UNIX_EPOCH]
|
||||
fn system_time() -> u64 {
|
||||
SystemTime::now()
|
||||
.duration_since(SystemTime::UNIX_EPOCH)
|
||||
.expect("time drift")
|
||||
.as_micros() as u64
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
/// Return the number of microseconds since [SystemTime::UNIX_EPOCH]
|
||||
pub fn system_time() -> u64 {
|
||||
// Won't be an issue for more than 5000 years!
|
||||
(js_sys::Date::now() as u64 )
|
||||
// Turn miliseconds to microseconds
|
||||
* 1000
|
||||
}
|
||||
|
||||
#[derive(thiserror::Error, Debug)]
|
||||
pub enum TimestampError {
|
||||
#[error("Invalid bytes length, Timestamp should be encoded as 8 bytes, got {0}")]
|
||||
InvalidBytesLength(usize),
|
||||
#[error("Invalid timestamp encoding")]
|
||||
InvalidEncoding,
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::collections::HashSet;
|
||||
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn strictly_monotonic() {
|
||||
const COUNT: usize = 100;
|
||||
|
||||
let mut set = HashSet::with_capacity(COUNT);
|
||||
let mut vec = Vec::with_capacity(COUNT);
|
||||
|
||||
for _ in 0..COUNT {
|
||||
let timestamp = Timestamp::now();
|
||||
|
||||
set.insert(timestamp.clone());
|
||||
vec.push(timestamp);
|
||||
}
|
||||
|
||||
let mut ordered = vec.clone();
|
||||
ordered.sort();
|
||||
|
||||
assert_eq!(set.len(), COUNT, "unique");
|
||||
assert_eq!(ordered, vec, "ordered");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn strings() {
|
||||
const COUNT: usize = 100;
|
||||
|
||||
let mut set = HashSet::with_capacity(COUNT);
|
||||
let mut vec = Vec::with_capacity(COUNT);
|
||||
|
||||
for _ in 0..COUNT {
|
||||
let string = Timestamp::now().to_string();
|
||||
|
||||
set.insert(string.clone());
|
||||
vec.push(string)
|
||||
}
|
||||
|
||||
let mut ordered = vec.clone();
|
||||
ordered.sort();
|
||||
|
||||
assert_eq!(set.len(), COUNT, "unique");
|
||||
assert_eq!(ordered, vec, "ordered");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn to_from_string() {
|
||||
let timestamp = Timestamp::now();
|
||||
let string = timestamp.to_string();
|
||||
let decoded: Timestamp = string.try_into().unwrap();
|
||||
|
||||
assert_eq!(decoded, timestamp)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn serde() {
|
||||
let timestamp = Timestamp::now();
|
||||
|
||||
let serialized = postcard::to_allocvec(×tamp).unwrap();
|
||||
|
||||
assert_eq!(serialized, timestamp.to_bytes());
|
||||
|
||||
let deserialized: Timestamp = postcard::from_bytes(&serialized).unwrap();
|
||||
|
||||
assert_eq!(deserialized, timestamp);
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
use axum::{
|
||||
extract::DefaultBodyLimit,
|
||||
routing::{delete, get, post, put},
|
||||
routing::{delete, get, head, post, put},
|
||||
Router,
|
||||
};
|
||||
use tower_cookies::CookieManagerLayer;
|
||||
@@ -25,6 +25,7 @@ fn base(state: AppState) -> Router {
|
||||
.route("/:pubky/session", delete(auth::signout))
|
||||
.route("/:pubky/*path", put(public::put))
|
||||
.route("/:pubky/*path", get(public::get))
|
||||
.route("/:pubky/*path", head(public::head))
|
||||
.route("/:pubky/*path", delete(public::delete))
|
||||
.route("/events/", get(feed::feed))
|
||||
.layer(CookieManagerLayer::new())
|
||||
|
||||
@@ -104,7 +104,7 @@ pub async fn signin(
|
||||
&mut wtxn,
|
||||
public_key,
|
||||
&User {
|
||||
created_at: Timestamp::now().into_inner(),
|
||||
created_at: Timestamp::now().as_u64(),
|
||||
},
|
||||
)?;
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ use axum::{
|
||||
http::{header, Response, StatusCode},
|
||||
response::IntoResponse,
|
||||
};
|
||||
use pubky_common::timestamp::{Timestamp, TimestampError};
|
||||
use pubky_common::timestamp::Timestamp;
|
||||
|
||||
use crate::{
|
||||
error::{Error, Result},
|
||||
@@ -17,17 +17,11 @@ pub async fn feed(
|
||||
params: ListQueryParams,
|
||||
) -> Result<impl IntoResponse> {
|
||||
if let Some(ref cursor) = params.cursor {
|
||||
if let Err(timestmap_error) = Timestamp::try_from(cursor.to_string()) {
|
||||
let cause = match timestmap_error {
|
||||
TimestampError::InvalidEncoding => {
|
||||
"Cursor should be valid base32 Crockford encoding of a timestamp"
|
||||
}
|
||||
TimestampError::InvalidBytesLength(size) => {
|
||||
&format!("Cursor should be 13 characters long, got: {size}")
|
||||
}
|
||||
};
|
||||
|
||||
Err(Error::new(StatusCode::BAD_REQUEST, cause.into()))?
|
||||
if Timestamp::try_from(cursor.to_string()).is_err() {
|
||||
Err(Error::new(
|
||||
StatusCode::BAD_REQUEST,
|
||||
"Cursor should be valid base32 Crockford encoding of a timestamp".into(),
|
||||
))?
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use axum::{
|
||||
body::Body,
|
||||
extract::State,
|
||||
http::{header, Response, StatusCode},
|
||||
http::{header, HeaderMap, HeaderValue, Response, StatusCode},
|
||||
response::IntoResponse,
|
||||
};
|
||||
use futures_util::stream::StreamExt;
|
||||
@@ -125,6 +125,26 @@ pub async fn get(
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn head(
|
||||
State(state): State<AppState>,
|
||||
pubky: Pubky,
|
||||
path: EntryPath,
|
||||
) -> Result<impl IntoResponse> {
|
||||
verify(path.as_str())?;
|
||||
|
||||
let rtxn = state.db.env.read_txn()?;
|
||||
|
||||
match state
|
||||
.db
|
||||
.get_entry(&rtxn, pubky.public_key(), path.as_str())?
|
||||
.as_ref()
|
||||
.map(HeaderMap::from)
|
||||
{
|
||||
Some(headers) => Ok(headers),
|
||||
None => Err(Error::with_status(StatusCode::NOT_FOUND)),
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn delete(
|
||||
State(mut state): State<AppState>,
|
||||
pubky: Pubky,
|
||||
@@ -188,3 +208,32 @@ fn verify(path: &str) -> Result<()> {
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
impl From<&Entry> for HeaderMap {
|
||||
fn from(entry: &Entry) -> Self {
|
||||
let mut headers = HeaderMap::new();
|
||||
headers.insert(header::CONTENT_LENGTH, entry.content_length().into());
|
||||
headers.insert(
|
||||
header::LAST_MODIFIED,
|
||||
HeaderValue::from_str(&entry.timestamp().format_http_date())
|
||||
.expect("http date is valid header value"),
|
||||
);
|
||||
headers.insert(
|
||||
header::CONTENT_TYPE,
|
||||
// TODO: when setting content type from user input, we should validate it as a HeaderValue
|
||||
entry
|
||||
.content_type()
|
||||
.try_into()
|
||||
.or(HeaderValue::from_str(""))
|
||||
.expect("valid header value"),
|
||||
);
|
||||
headers.insert(
|
||||
header::ETAG,
|
||||
format!("\"{}\"", entry.content_hash())
|
||||
.try_into()
|
||||
.expect("hex string is valid"),
|
||||
);
|
||||
|
||||
headers
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user