From 6fb3f5ea4cec7eaf0c9dae274cf1fa09ff4ea198 Mon Sep 17 00:00:00 2001 From: Seongmin Lee Date: Sun, 9 Aug 2026 01:35:22 +0300 Subject: [PATCH] knot2: `git.keepCommit` pretty rough implementation since we will replace everything with git-push later. Signed-off-by: Seongmin Lee --- Cargo.lock | 740 +++++++++++++++++++++++++++--- knot2/crates/knot-git/src/repo.rs | 11 + knot2/crates/knot-xrpc/Cargo.toml | 3 + knot2/crates/knot-xrpc/src/git.rs | 171 +++++++ knot2/crates/knot-xrpc/src/lib.rs | 2 + 5 files changed, 856 insertions(+), 71 deletions(-) create mode 100644 knot2/crates/knot-xrpc/src/git.rs diff --git a/Cargo.lock b/Cargo.lock index 269f6174..368690c6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8,6 +8,16 @@ version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" +[[package]] +name = "aead" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d122413f284cf2d62fb1b7db97e02edb8cda96d769b16e443a4f6195e35662b0" +dependencies = [ + "crypto-common 0.1.6", + "generic-array 0.14.9", +] + [[package]] name = "aead" version = "0.6.1" @@ -15,7 +25,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1973cfbc1a2daf9cf550e74e1f088c28e7f7d8c1e1418fb6c9dc5184b7e84c99" dependencies = [ "crypto-common 0.2.2", - "inout", + "inout 0.2.2", +] + +[[package]] +name = "aes" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0" +dependencies = [ + "cfg-if", + "cipher 0.4.4", + "cpufeatures 0.2.17", ] [[package]] @@ -24,23 +45,37 @@ version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f1fc76eaeac4c9164506c466d4ffdd8ec9d0c5bf57ee97177c4d8eceb3a0e138" dependencies = [ - "cipher", + "cipher 0.5.2", "cpubits", "cpufeatures 0.3.0", "zeroize", ] +[[package]] +name = "aes-gcm" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "831010a0f742e1209b3bcea8fab6a8e149051ba6099432c8cb2cc117dec3ead1" +dependencies = [ + "aead 0.5.2", + "aes 0.8.4", + "cipher 0.4.4", + "ctr 0.9.2", + "ghash 0.5.1", + "subtle", +] + [[package]] name = "aes-gcm" version = "0.11.0-rc.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "da8c919c118108f144adecad74b425b804ad075580d605d9b33c2d6d1c62a2f8" dependencies = [ - "aead", - "aes", - "cipher", - "ctr", - "ghash", + "aead 0.6.1", + "aes 0.9.1", + "cipher 0.5.2", + "ctr 0.10.1", + "ghash 0.6.0", "subtle", "zeroize", ] @@ -501,6 +536,29 @@ dependencies = [ "tracing", ] +[[package]] +name = "axum-extra" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9963ff19f40c6102c76756ef0a46004c0d58957d87259fc9208ff8441c12ab96" +dependencies = [ + "axum", + "axum-core", + "bytes", + "cookie", + "futures-util", + "http", + "http-body", + "http-body-util", + "mime", + "pin-project-lite", + "rustversion", + "serde_core", + "tower-layer", + "tower-service", + "tracing", +] + [[package]] name = "base-x" version = "0.2.11" @@ -666,7 +724,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "62ce3946557b35e71d1bbe07ec385073ce9eda05043f95de134eb578fcf1a298" dependencies = [ "byteorder", - "cipher", + "cipher 0.5.2", ] [[package]] @@ -1057,7 +1115,7 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ce2dc9ee5f88d11e0beb842c88b33c8a5cf0d1329c4b19494af42b07dbfe8896" dependencies = [ - "cipher", + "cipher 0.5.2", ] [[package]] @@ -1130,7 +1188,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6f8d983286843e49675a4b7a2d174efe136dc93a18d69130dd18198a6c167601" dependencies = [ "cfg-if", - "cipher", + "cipher 0.5.2", "cpufeatures 0.3.0", "rand_core 0.10.1", "zeroize", @@ -1190,6 +1248,16 @@ dependencies = [ "unsigned-varint", ] +[[package]] +name = "cipher" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" +dependencies = [ + "crypto-common 0.1.6", + "inout 0.1.4", +] + [[package]] name = "cipher" version = "0.5.2" @@ -1198,7 +1266,7 @@ checksum = "e8cf2a2c93cd704877c0858356ed03480ff301ee950b43f1cbe4573b088bfa6c" dependencies = [ "block-buffer 0.12.1", "crypto-common 0.2.2", - "inout", + "inout 0.2.2", "zeroize", ] @@ -1368,6 +1436,21 @@ version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2f421161cb492475f1661ddc9815a745a1c894592070661180fdec3d4872e9c3" +[[package]] +name = "cookie" +version = "0.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a373e3602691c3cdea496d2f0ee5935151e6168fe87739483c463db1b2f2f87" +dependencies = [ + "aes-gcm 0.10.3", + "base64", + "percent-encoding", + "rand 0.8.6", + "subtle", + "time", + "version_check", +] + [[package]] name = "cordyceps" version = "0.3.4" @@ -1552,6 +1635,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" dependencies = [ "generic-array 0.14.9", + "rand_core 0.6.4", "typenum", ] @@ -1576,13 +1660,22 @@ dependencies = [ "rand_core 0.10.1", ] +[[package]] +name = "ctr" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0369ee1ad671834580515889b80f2ea915f23b8be8d0daa4bbaf2ac5c7590835" +dependencies = [ + "cipher 0.4.4", +] + [[package]] name = "ctr" version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baaca1c4b237092596f64d571e9db6ce4109c4ef9742e27590f1709594461f21" dependencies = [ - "cipher", + "cipher 0.5.2", ] [[package]] @@ -1595,6 +1688,22 @@ dependencies = [ "subtle", ] +[[package]] +name = "curve25519-dalek" +version = "4.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97fb8b7c4503de7d6ae7b42ab72a5a59857b4c937ec27a3d4539dba95b5ab2be" +dependencies = [ + "cfg-if", + "cpufeatures 0.2.17", + "curve25519-dalek-derive", + "digest 0.10.7", + "fiat-crypto 0.2.9", + "rustc_version", + "subtle", + "zeroize", +] + [[package]] name = "curve25519-dalek" version = "5.0.0-rc.0" @@ -1605,7 +1714,7 @@ dependencies = [ "cpufeatures 0.3.0", "curve25519-dalek-derive", "digest 0.11.3", - "fiat-crypto", + "fiat-crypto 0.3.0", "rustc_version", "subtle", "zeroize", @@ -1849,7 +1958,7 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "916a94e407b54f9034d71dd748234cd1e516ced6284009906ae246f177eafe5a" dependencies = [ - "cipher", + "cipher 0.5.2", ] [[package]] @@ -1959,6 +2068,16 @@ dependencies = [ "zeroize", ] +[[package]] +name = "ed25519" +version = "2.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "115531babc129696a58c64a4fef0a8bf9e9698629fb97e9e40767d235cfbcd53" +dependencies = [ + "pkcs8 0.10.2", + "signature 2.2.0", +] + [[package]] name = "ed25519" version = "3.0.0" @@ -1969,14 +2088,29 @@ dependencies = [ "signature 3.0.0", ] +[[package]] +name = "ed25519-dalek" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70e796c081cee67dc755e1a36a0a172b897fab85fc3f6bc48307991f64e4eca9" +dependencies = [ + "curve25519-dalek 4.1.3", + "ed25519 2.2.3", + "rand_core 0.6.4", + "serde", + "sha2 0.10.9", + "subtle", + "zeroize", +] + [[package]] name = "ed25519-dalek" version = "3.0.0-rc.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b011170fe4f04665565b4110afef66774fe9ffff278f3eb5b81cc73d26e27d60" dependencies = [ - "curve25519-dalek", - "ed25519", + "curve25519-dalek 5.0.0-rc.0", + "ed25519 3.0.0", "rand_core 0.10.1", "serde", "sha2 0.11.0", @@ -2003,6 +2137,7 @@ dependencies = [ "ff 0.13.1", "generic-array 0.14.9", "group 0.13.0", + "hkdf 0.12.4", "pem-rfc7468 0.7.0", "pkcs8 0.10.2", "rand_core 0.6.4", @@ -2023,7 +2158,7 @@ dependencies = [ "digest 0.11.3", "ff 0.14.0", "group 0.14.0", - "hkdf", + "hkdf 0.13.0", "hybrid-array", "once_cell", "pem-rfc7468 1.0.0", @@ -2181,6 +2316,12 @@ dependencies = [ "subtle", ] +[[package]] +name = "fiat-crypto" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d" + [[package]] name = "fiat-crypto" version = "0.3.0" @@ -2284,6 +2425,16 @@ version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c" +[[package]] +name = "futf" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df420e2e84819663797d1ec6544b13c5be84629e7bb00dc960d6917db2987843" +dependencies = [ + "mac", + "new_debug_unreachable", +] + [[package]] name = "futures" version = "0.3.32" @@ -2508,13 +2659,23 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "ghash" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0d8a4362ccb29cb0b265253fb0a2728f592895ee6854fd9bc13f2ffda266ff1" +dependencies = [ + "opaque-debug", + "polyval 0.6.2", +] + [[package]] name = "ghash" version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2eecf2d5dc9b66b732b97707a0210906b1d30523eb773193ab777c0c84b3e8d5" dependencies = [ - "polyval", + "polyval 0.7.1", ] [[package]] @@ -3435,6 +3596,34 @@ dependencies = [ "regex-syntax", ] +[[package]] +name = "gloo-storage" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbc8031e8c92758af912f9bc08fbbadd3c6f3cfcbf6b64cdf3d6a81f0139277a" +dependencies = [ + "gloo-utils", + "js-sys", + "serde", + "serde_json", + "thiserror 1.0.69", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "gloo-utils" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b5555354113b18c547c1d3a98fbf7fb32a9ff4f6fa112ce823a21641a0ba3aa" +dependencies = [ + "js-sys", + "serde", + "serde_json", + "wasm-bindgen", + "web-sys", +] + [[package]] name = "governor" version = "0.10.4" @@ -3701,6 +3890,15 @@ dependencies = [ "tracing", ] +[[package]] +name = "hkdf" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b5f8eb2ad728638ea2c7d47a21db23b7b58a72ed6a38256b8a1849f15fbbdf7" +dependencies = [ + "hmac 0.12.1", +] + [[package]] name = "hkdf" version = "0.13.0" @@ -3728,6 +3926,20 @@ dependencies = [ "digest 0.11.3", ] +[[package]] +name = "html5ever" +version = "0.27.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c13771afe0e6e846f1e67d038d4cb29998a6779f93c809212e4e9c32efd244d4" +dependencies = [ + "log", + "mac", + "markup5ever", + "proc-macro2", + "quote", + "syn 2.0.118", +] + [[package]] name = "htmlescape" version = "0.3.1" @@ -4011,6 +4223,15 @@ dependencies = [ "serde_core", ] +[[package]] +name = "inout" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "879f10e63c20629ecabbb64a8010319738c66a5cd0c29b02d63d272b03751d01" +dependencies = [ + "generic-array 0.14.9", +] + [[package]] name = "inout" version = "0.2.2" @@ -4112,6 +4333,73 @@ version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" +[[package]] +name = "jacquard" +version = "0.12.1" +source = "git+https://tangled.org/oppi.li/jacquard?rev=bb32de36f1cc2727954fba6377e0433c391d34f3#bb32de36f1cc2727954fba6377e0433c391d34f3" +dependencies = [ + "bytes", + "getrandom 0.2.17", + "gloo-storage", + "http", + "jacquard-api", + "jacquard-common", + "jacquard-identity", + "jacquard-oauth", + "jose-jwk", + "miette", + "regex", + "regex-lite", + "reqwest 0.12.28", + "serde", + "serde_html_form", + "serde_json", + "smol_str", + "thiserror 2.0.18", + "tokio", + "trait-variant", + "webpage", +] + +[[package]] +name = "jacquard-api" +version = "0.12.1" +source = "git+https://tangled.org/oppi.li/jacquard?rev=bb32de36f1cc2727954fba6377e0433c391d34f3#bb32de36f1cc2727954fba6377e0433c391d34f3" +dependencies = [ + "jacquard-common", + "jacquard-derive", + "jacquard-lexicon", + "miette", + "serde", + "thiserror 2.0.18", +] + +[[package]] +name = "jacquard-axum" +version = "0.12.1" +source = "git+https://tangled.org/oppi.li/jacquard?rev=bb32de36f1cc2727954fba6377e0433c391d34f3#bb32de36f1cc2727954fba6377e0433c391d34f3" +dependencies = [ + "axum", + "axum-extra", + "base64", + "bytes", + "chrono", + "jacquard", + "jacquard-common", + "jacquard-derive", + "jacquard-identity", + "miette", + "mini-moka-wasm", + "multibase", + "serde", + "serde_html_form", + "serde_json", + "thiserror 2.0.18", + "tokio", + "tower-http 0.6.11", + "tracing", +] + [[package]] name = "jacquard-common" version = "0.12.1" @@ -4175,6 +4463,28 @@ dependencies = [ "syn 2.0.118", ] +[[package]] +name = "jacquard-identity" +version = "0.12.1" +source = "git+https://tangled.org/oppi.li/jacquard?rev=bb32de36f1cc2727954fba6377e0433c391d34f3#bb32de36f1cc2727954fba6377e0433c391d34f3" +dependencies = [ + "bon", + "bytes", + "http", + "jacquard-common", + "jacquard-lexicon", + "miette", + "mini-moka-wasm", + "n0-future", + "reqwest 0.12.28", + "serde", + "serde_html_form", + "serde_json", + "thiserror 2.0.18", + "tokio", + "trait-variant", +] + [[package]] name = "jacquard-lexicon" version = "0.12.1" @@ -4202,6 +4512,39 @@ dependencies = [ "unicode-segmentation", ] +[[package]] +name = "jacquard-oauth" +version = "0.12.1" +source = "git+https://tangled.org/oppi.li/jacquard?rev=bb32de36f1cc2727954fba6377e0433c391d34f3#bb32de36f1cc2727954fba6377e0433c391d34f3" +dependencies = [ + "base64", + "bytes", + "chrono", + "dashmap", + "ed25519-dalek 2.2.0", + "elliptic-curve 0.13.8", + "http", + "jacquard-common", + "jacquard-identity", + "jose-jwa", + "jose-jwk", + "k256", + "miette", + "p256 0.13.2", + "p384 0.13.1", + "rand 0.8.6", + "reqwest 0.12.28", + "serde", + "serde_html_form", + "serde_json", + "sha2 0.10.9", + "smallvec", + "smol_str", + "thiserror 2.0.18", + "tokio", + "trait-variant", +] + [[package]] name = "jiff" version = "0.2.29" @@ -4298,6 +4641,42 @@ dependencies = [ "libc", ] +[[package]] +name = "jose-b64" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bec69375368709666b21c76965ce67549f2d2db7605f1f8707d17c9656801b56" +dependencies = [ + "base64ct", + "serde", + "subtle", + "zeroize", +] + +[[package]] +name = "jose-jwa" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ab78e053fe886a351d67cf0d194c000f9d0dcb92906eb34d853d7e758a4b3a7" +dependencies = [ + "serde", +] + +[[package]] +name = "jose-jwk" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "280fa263807fe0782ecb6f2baadc28dffc04e00558a58e33bfdb801d11fd58e7" +dependencies = [ + "jose-b64", + "jose-jwa", + "p256 0.13.2", + "p384 0.13.1", + "rsa 0.9.10", + "serde", + "zeroize", +] + [[package]] name = "js-sys" version = "0.3.102" @@ -4795,9 +5174,9 @@ dependencies = [ name = "knot-secrets" version = "2.0.0" dependencies = [ - "aes-gcm", + "aes-gcm 0.11.0-rc.4", "base64", - "hkdf", + "hkdf 0.13.0", "k256", "knot-resource", "knot-runtime", @@ -4969,6 +5348,8 @@ dependencies = [ "http", "http-body", "httpdate", + "jacquard-axum", + "jacquard-common", "k256", "knot-acl", "knot-atproto", @@ -4991,6 +5372,7 @@ dependencies = [ "knot-runtime", "knot-secrets", "knot-types", + "lexicons", "serde", "serde_json", "sha2 0.11.0", @@ -5032,6 +5414,9 @@ name = "lazy_static" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" +dependencies = [ + "spin 0.9.8", +] [[package]] name = "levenshtein_automata" @@ -5063,6 +5448,12 @@ version = "0.2.186" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66" +[[package]] +name = "libm" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6d2cec3eae94f9f509c767b45932f1ada8350c4bdb85af2fcab4a3c14807981" + [[package]] name = "libsqlite3-sys" version = "0.36.0" @@ -5150,6 +5541,12 @@ version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7ef0d4ed8669f8f8826eb00dc878084aa8f253506c4fd5e8f58f5bce72ddb97e" +[[package]] +name = "mac" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c41e0c4fef86961ac6d6f8a82609f55f31b05e4fce149ac5710e439df7619ba4" + [[package]] name = "maitake-sync" version = "0.1.2" @@ -5163,6 +5560,32 @@ dependencies = [ "portable-atomic", ] +[[package]] +name = "markup5ever" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16ce3abbeba692c8b8441d036ef91aea6df8da2c6b6e21c7e14d3c18e526be45" +dependencies = [ + "log", + "phf", + "phf_codegen", + "string_cache", + "string_cache_codegen", + "tendril", +] + +[[package]] +name = "markup5ever_rcdom" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edaa21ab3701bfee5099ade5f7e1f84553fd19228cf332f13cd6e964bf59be18" +dependencies = [ + "html5ever", + "markup5ever", + "tendril", + "xml5ever", +] + [[package]] name = "match-lookup" version = "0.1.2" @@ -5277,6 +5700,19 @@ dependencies = [ "unicase", ] +[[package]] +name = "mini-moka-wasm" +version = "0.10.99" +source = "git+https://tangled.org/oppi.li/jacquard?rev=bb32de36f1cc2727954fba6377e0433c391d34f3#bb32de36f1cc2727954fba6377e0433c391d34f3" +dependencies = [ + "crossbeam-channel", + "crossbeam-utils", + "dashmap", + "smallvec", + "tagptr", + "triomphe", +] + [[package]] name = "minimal-lexical" version = "0.2.1" @@ -5419,6 +5855,12 @@ dependencies = [ "web-time", ] +[[package]] +name = "new_debug_unreachable" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086" + [[package]] name = "nix" version = "0.31.3" @@ -5479,6 +5921,22 @@ dependencies = [ "num-traits", ] +[[package]] +name = "num-bigint-dig" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e661dda6640fad38e827a6d4a310ff4763082116fe217f279885c97f511bb0b7" +dependencies = [ + "lazy_static", + "libm", + "num-integer", + "num-iter", + "num-traits", + "rand 0.8.6", + "smallvec", + "zeroize", +] + [[package]] name = "num-conv" version = "0.2.2" @@ -5494,6 +5952,16 @@ dependencies = [ "num-traits", ] +[[package]] +name = "num-iter" +version = "0.1.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c92800bd69a1eac91786bcfe9da64a897eb72911b8dc3095decbd07429e8048b" +dependencies = [ + "num-integer", + "num-traits", +] + [[package]] name = "num-traits" version = "0.2.19" @@ -5501,6 +5969,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" dependencies = [ "autocfg", + "libm", ] [[package]] @@ -5555,6 +6024,12 @@ version = "11.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d6790f58c7ff633d8771f42965289203411a5e5c68388703c06e14f24770b41e" +[[package]] +name = "opaque-debug" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" + [[package]] name = "openssl-probe" version = "0.2.1" @@ -5622,6 +6097,18 @@ dependencies = [ "sha2 0.11.0", ] +[[package]] +name = "p384" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe42f1670a52a47d448f14b6a5c61dd78fce51856e68edaa38f7ae3a46b8d6b6" +dependencies = [ + "ecdsa 0.16.9", + "elliptic-curve 0.13.8", + "primeorder 0.13.6", + "sha2 0.10.9", +] + [[package]] name = "p384" version = "0.14.0-rc.10" @@ -5630,7 +6117,7 @@ checksum = "9bd5333afa5ae0347f39e6a0f2c9c155da431583fd71fe5555bd0521b4ccaf02" dependencies = [ "ecdsa 0.17.0-rc.18", "elliptic-curve 0.14.0-rc.33", - "fiat-crypto", + "fiat-crypto 0.3.0", "primefield", "primeorder 0.14.0-rc.10", "sha2 0.11.0", @@ -5799,6 +6286,16 @@ dependencies = [ "phf_shared", ] +[[package]] +name = "phf_codegen" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aef8048c789fa5e851558d709946d6d79a8ff88c0440c587967f8e94bfb1216a" +dependencies = [ + "phf_generator", + "phf_shared", +] + [[package]] name = "phf_generator" version = "0.11.3" @@ -5868,6 +6365,17 @@ dependencies = [ "futures-io", ] +[[package]] +name = "pkcs1" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8ffb9f10fa047879315e6625af03c164b16962a5368d724ed16323b68ace47f" +dependencies = [ + "der 0.7.10", + "pkcs8 0.10.2", + "spki 0.7.3", +] + [[package]] name = "pkcs1" version = "0.8.0-rc.4" @@ -5884,7 +6392,7 @@ version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "279a91971a1d8eb1260a30938eae3be9cb67b472dffecb222fbbbe2fd2dc1453" dependencies = [ - "aes", + "aes 0.9.1", "cbc", "der 0.8.0", "pbkdf2", @@ -5943,10 +6451,22 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a00baa632505d05512f48a963e16051c54fda9a95cc9acea1a4e3c90991c4a2e" dependencies = [ "cpufeatures 0.3.0", - "universal-hash", + "universal-hash 0.6.1", "zeroize", ] +[[package]] +name = "polyval" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d1fe60d06143b2430aa532c94cfe9e29783047f06c0d7fd359a9a51b729fa25" +dependencies = [ + "cfg-if", + "cpufeatures 0.2.17", + "opaque-debug", + "universal-hash 0.5.1", +] + [[package]] name = "polyval" version = "0.7.1" @@ -5955,7 +6475,7 @@ checksum = "7dfc63250416fea14f5749b90725916a6c903f599d51cb635aa7a52bfd03eede" dependencies = [ "cpubits", "cpufeatures 0.3.0", - "universal-hash", + "universal-hash 0.6.1", ] [[package]] @@ -6010,6 +6530,12 @@ dependencies = [ "zerocopy", ] +[[package]] +name = "precomputed-hash" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" + [[package]] name = "prettyplease" version = "0.2.37" @@ -6689,6 +7215,26 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "rsa" +version = "0.9.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8573f03f5883dcaebdfcf4725caa1ecb9c15b2ef50c43a07b816e06799bb12d" +dependencies = [ + "const-oid 0.9.6", + "digest 0.10.7", + "num-bigint-dig", + "num-integer", + "num-traits", + "pkcs1 0.7.5", + "pkcs8 0.10.2", + "rand_core 0.6.4", + "signature 2.2.0", + "spki 0.7.3", + "subtle", + "zeroize", +] + [[package]] name = "rsa" version = "0.10.0-rc.18" @@ -6699,7 +7245,7 @@ dependencies = [ "crypto-bigint 0.7.4", "crypto-primes", "digest 0.11.3", - "pkcs1", + "pkcs1 0.8.0-rc.4", "pkcs8 0.11.0", "rand_core 0.10.1", "sha2 0.11.0", @@ -6739,33 +7285,33 @@ version = "0.61.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbf893f64684e58da8a68d56a5e84d1cf0440226274c515770fe267707a7d0b0" dependencies = [ - "aes", + "aes 0.9.1", "aws-lc-rs", "bitflags 2.13.0", "block-padding", "byteorder", "bytes", "cbc", - "cipher", + "cipher 0.5.2", "crypto-bigint 0.7.4", - "ctr", - "curve25519-dalek", + "ctr 0.10.1", + "curve25519-dalek 5.0.0-rc.0", "data-encoding", "delegate", "der 0.8.0", "digest 0.11.3", "ecdsa 0.17.0-rc.18", - "ed25519-dalek", + "ed25519-dalek 3.0.0-rc.0", "elliptic-curve 0.14.0-rc.33", "enum_dispatch", "flate2", "futures", "generic-array 1.4.3", "getrandom 0.4.3", - "ghash", + "ghash 0.6.0", "hex-literal", "hmac 0.13.0", - "inout", + "inout 0.2.2", "internal-russh-num-bigint", "keccak", "log", @@ -6774,17 +7320,17 @@ dependencies = [ "module-lattice", "num-bigint", "p256 0.14.0-rc.10", - "p384", + "p384 0.14.0-rc.10", "p521", "pageant", "pbkdf2", - "pkcs1", + "pkcs1 0.8.0-rc.4", "pkcs5", "pkcs8 0.11.0", - "polyval", + "polyval 0.7.1", "rand 0.10.1", "rand_core 0.10.1", - "rsa", + "rsa 0.10.0-rc.18", "russh-cryptovec", "russh-util", "salsa20", @@ -6801,7 +7347,7 @@ dependencies = [ "thiserror 2.0.18", "tokio", "typenum", - "universal-hash", + "universal-hash 0.6.1", "zeroize", ] @@ -7025,7 +7571,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2f874456e72520ff1375a06c588eaf074b0f01f9e9e1aada45bd9b7954a6e42c" dependencies = [ "cfg-if", - "cipher", + "cipher 0.5.2", ] [[package]] @@ -7607,13 +8153,13 @@ version = "0.3.0-rc.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "10db6f219196a8528f9ec904d9d45cdad692d65b0e57e72be4dedd1c5fddce36" dependencies = [ - "aead", - "aes", - "aes-gcm", + "aead 0.6.1", + "aes 0.9.1", + "aes-gcm 0.11.0-rc.4", "cbc", "chacha20", - "cipher", - "ctr", + "cipher 0.5.2", + "ctr 0.10.1", "ctutils", "des", "poly1305", @@ -7645,14 +8191,14 @@ dependencies = [ "argon2", "bcrypt-pbkdf", "ctutils", - "ed25519-dalek", + "ed25519-dalek 3.0.0-rc.0", "hex", "hmac 0.13.0", "p256 0.14.0-rc.10", - "p384", + "p384 0.14.0-rc.10", "p521", "rand_core 0.10.1", - "rsa", + "rsa 0.10.0-rc.18", "sec1 0.8.1", "sha1 0.11.0", "sha2 0.11.0", @@ -7674,6 +8220,31 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" +[[package]] +name = "string_cache" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf776ba3fa74f83bf4b63c3dcbbf82173db2632ed8452cb2d891d33f459de70f" +dependencies = [ + "new_debug_unreachable", + "parking_lot", + "phf_shared", + "precomputed-hash", + "serde", +] + +[[package]] +name = "string_cache_codegen" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c711928715f1fe0fe509c53b43e993a9a557babc2d0a3567d0a3006f1ac931a0" +dependencies = [ + "phf_generator", + "phf_shared", + "proc-macro2", + "quote", +] + [[package]] name = "strsim" version = "0.11.1" @@ -7927,6 +8498,17 @@ dependencies = [ "windows-sys 0.61.2", ] +[[package]] +name = "tendril" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d24a120c5fc464a3458240ee02c299ebcb9d67b5249c8848b09d639dca8d7bb0" +dependencies = [ + "futf", + "mac", + "utf-8", +] + [[package]] name = "terminal_size" version = "0.4.4" @@ -8284,6 +8866,7 @@ dependencies = [ "tower", "tower-layer", "tower-service", + "tracing", "url", ] @@ -8428,6 +9011,12 @@ dependencies = [ "syn 2.0.118", ] +[[package]] +name = "triomphe" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b40688ea6389c8171614b25491f71d4a27946e0c7ce2da1c6de27e25abf1a0ae" + [[package]] name = "trusted-proxies" version = "0.0.1" @@ -8582,6 +9171,16 @@ version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" +[[package]] +name = "universal-hash" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc1de2c688dc15305988b563c3854064043356019f97a4b46276fe734c4f07ea" +dependencies = [ + "crypto-common 0.1.6", + "subtle", +] + [[package]] name = "universal-hash" version = "0.6.1" @@ -8830,6 +9429,18 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "webpage" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70862efc041d46e6bbaa82bb9c34ae0596d090e86cbd14bd9e93b36ee6802eac" +dependencies = [ + "html5ever", + "markup5ever_rcdom", + "serde_json", + "url", +] + [[package]] name = "webpki-root-certs" version = "1.0.8" @@ -9338,6 +9949,17 @@ dependencies = [ "rustix", ] +[[package]] +name = "xml5ever" +version = "0.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9bbb26405d8e919bc1547a5aa9abc95cbfa438f04844f5fdd9dc7596b748bf69" +dependencies = [ + "log", + "mac", + "markup5ever", +] + [[package]] name = "yasna" version = "0.5.2" @@ -9427,6 +10049,7 @@ version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e13c156562582aa81c60cb29407084cdb54c4164760106ab78e6c5b0858cf64e" dependencies = [ + "serde", "zeroize_derive", ] @@ -9513,28 +10136,3 @@ dependencies = [ "cc", "pkg-config", ] - -[[patch.unused]] -name = "jacquard" -version = "0.12.1" -source = "git+https://tangled.org/oppi.li/jacquard?rev=bb32de36f1cc2727954fba6377e0433c391d34f3#bb32de36f1cc2727954fba6377e0433c391d34f3" - -[[patch.unused]] -name = "jacquard-api" -version = "0.12.1" -source = "git+https://tangled.org/oppi.li/jacquard?rev=bb32de36f1cc2727954fba6377e0433c391d34f3#bb32de36f1cc2727954fba6377e0433c391d34f3" - -[[patch.unused]] -name = "jacquard-axum" -version = "0.12.1" -source = "git+https://tangled.org/oppi.li/jacquard?rev=bb32de36f1cc2727954fba6377e0433c391d34f3#bb32de36f1cc2727954fba6377e0433c391d34f3" - -[[patch.unused]] -name = "jacquard-identity" -version = "0.12.1" -source = "git+https://tangled.org/oppi.li/jacquard?rev=bb32de36f1cc2727954fba6377e0433c391d34f3#bb32de36f1cc2727954fba6377e0433c391d34f3" - -[[patch.unused]] -name = "jacquard-oauth" -version = "0.12.1" -source = "git+https://tangled.org/oppi.li/jacquard?rev=bb32de36f1cc2727954fba6377e0433c391d34f3#bb32de36f1cc2727954fba6377e0433c391d34f3" diff --git a/knot2/crates/knot-git/src/repo.rs b/knot2/crates/knot-git/src/repo.rs index 2a47a285..1ff94c40 100644 --- a/knot2/crates/knot-git/src/repo.rs +++ b/knot2/crates/knot-git/src/repo.rs @@ -507,6 +507,17 @@ impl Repo { self.git.git_dir().join("objects") } + pub fn set_reference(&self, name: &RefName, target: Oid) -> Result<(), GitError> { + self.git.reference( + name.as_str(), + target, + PreviousValue::Any, + "update ref to target commit", + ) + .map_err(|error| GitError::Backend(error.to_string()))?; + Ok(()) + } + pub fn references(&self) -> Result, GitError> { self.git .references() diff --git a/knot2/crates/knot-xrpc/Cargo.toml b/knot2/crates/knot-xrpc/Cargo.toml index 0d5ad684..430b81ad 100644 --- a/knot2/crates/knot-xrpc/Cargo.toml +++ b/knot2/crates/knot-xrpc/Cargo.toml @@ -25,6 +25,9 @@ knot-postreceive = { workspace = true } knot-messages = { workspace = true } knot-receive = { workspace = true } knot-maintenance = { workspace = true } +lexicons = { workspace = true } +jacquard-axum = { workspace = true } +jacquard-common = { workspace = true } tracing = { workspace = true } axum = { workspace = true, features = ["ws"] } tower = { workspace = true } diff --git a/knot2/crates/knot-xrpc/src/git.rs b/knot2/crates/knot-xrpc/src/git.rs new file mode 100644 index 00000000..e8d9882e --- /dev/null +++ b/knot2/crates/knot-xrpc/src/git.rs @@ -0,0 +1,171 @@ +#![allow(unused)] +use std::sync::Arc; + +use axum::extract::State; +use http::{HeaderMap, StatusCode}; +use jacquard_axum::{ExtractXrpc, XrpcResponse}; +use jacquard_common::types::ident::AtIdentifier; +use knot_runtime::{Clock, HttpTransport}; +use knot_types::{Oid, RefName, RepoDid}; +use lexicons::sh_tangled::git::keep_commit::{self, KeepCommitSource}; + +use crate::error::XrpcError; +use crate::{run_blocking, XrpcState}; + +pub(crate) const KEEP_COMMIT_ROUTE: &str = "/xrpc/sh.tangled.git.keepCommit"; + +const KEEP_COMMIT_DENIED: &str = "only repository owner or a collaborator may execute keepCommit"; + +fn encode_ref_component(raw: &str) -> String { + let mut out = String::with_capacity(raw.len()); + for c in raw.chars() { + match c { + '%' => out.push_str("%25"), + ':' => out.push_str("%3A"), + '~' => out.push_str("%7E"), + other => out.push(other), + } + } + out +} + +pub(crate) async fn keep_commit( + State(state): State>>, + headers: HeaderMap, + method: crate::Method, + ExtractXrpc(input): ExtractXrpc, +) -> Result, XrpcError> { + let actor = state.authenticate(&headers, &method).await?; + let repo_did = RepoDid::new(input.repo.as_str()).map_err(|_e| { + XrpcError::from_status(StatusCode::BAD_REQUEST, "repo should be valid DID") + })?; + + let (AtIdentifier::Did(record_did), Some(record_collection), Some(record_rkey)) = ( + input.record.authority(), + input.record.collection(), + input.record.rkey(), + ) else { + return Err(XrpcError::from_status( + StatusCode::BAD_REQUEST, + "record should be an AT-URI pointing to a record", + )); + }; + + crate::authorize_push(&state, &actor, &repo_did, KEEP_COMMIT_DENIED).await?; + + let commit = match input.source { + KeepCommitSource::Commit(commit) => { + let commit_id = Oid::from_hex(commit.oid.as_str()).map_err(|_e| { + XrpcError::from_status(StatusCode::BAD_REQUEST, "commit.oid must be valid OID") + })?; + if input.repo == commit.repo { + // no-op + } else { + // TODO: fetch `{commit.oid}` from `{commit.repo}` + return Err(XrpcError::from_status( + StatusCode::BAD_REQUEST, + "importing source from external repo is not supported yet.", + )); + } + + Ok(commit_id) + } + _ => Err(XrpcError::from_status( + StatusCode::BAD_REQUEST, + "only 'commit' source is supported yet.", + )), + }?; + + // set `refs/tngl/keep/{did}/{collection}/{rkey}/{oid}` to `{oid}` + let layout = state.layout.clone(); + let opened = repo_did.clone(); + let ref_name = RefName::new(format!( + "refs/tngl/keep/{}/{}/{}/{}", + encode_ref_component(record_did.as_str()), + record_collection.as_str(), + encode_ref_component(record_rkey.as_str()), + commit, + )) + .map_err(|_e| { + XrpcError::from_status( + StatusCode::BAD_REQUEST, + "record does not map to a usable ref name", + ) + })?; + run_blocking(move || { + let repo = layout.open(&opened)?; + repo.set_reference(&ref_name, commit)?; + Ok(()) + }) + .await?; + + Ok(XrpcResponse(keep_commit::KeepCommitOutput { + commit: commit.to_hex().into(), + ..Default::default() + })) +} + +#[cfg(test)] +mod tests { + use super::encode_ref_component; + use knot_types::RefName; + + const OID: &str = "81158e200ff7e520a20b5e7505960cee4f35e4b3"; + + fn keep_ref(did: &str, collection: &str, rkey: &str) -> String { + format!( + "refs/tngl/keep/{}/{}/{}/{OID}", + encode_ref_component(did), + collection, + encode_ref_component(rkey), + ) + } + + #[test] + fn keep_ref_for_a_did_and_tid_rkey_is_a_valid_ref_name() { + let name = keep_ref( + "did:plc:lpbyv7yk5vnegj63jmdwlxzx", + "sh.tangled.repo.pull", + "3ms6rk5d6gk22", + ); + assert!( + name.contains("did%3Aplc%3Alpbyv7yk5vnegj63jmdwlxzx"), + "the did's colons must be encoded, got {name}" + ); + assert!(RefName::new(&name).is_ok(), "{name} must be a valid ref"); + } + + #[test] + fn keep_ref_for_a_vouch_whose_rkey_is_itself_a_did_is_valid() { + let name = keep_ref( + "did:plc:lpbyv7yk5vnegj63jmdwlxzx", + "sh.tangled.graph.vouch", + "did:plc:zgazxbjxy2dkmgqovbvbnxwx", + ); + assert!(RefName::new(&name).is_ok(), "{name} must be a valid ref"); + assert!(!name.contains(':'), "no raw colon may survive, got {name}"); + } + + #[test] + fn tilde_in_an_rkey_is_encoded() { + let name = keep_ref("did:plc:alice", "sh.tangled.string", "a~b"); + assert!(name.contains("a%7Eb"), "got {name}"); + assert!(RefName::new(&name).is_ok(), "{name} must be a valid ref"); + } + + #[test] + fn encoding_is_injective() { + assert_ne!( + encode_ref_component("did:web:foo:bar"), + encode_ref_component("did:web:foo-bar") + ); + assert_ne!(encode_ref_component("a%3Ab"), encode_ref_component("a:b")); + assert_eq!(encode_ref_component("a%3Ab"), "a%253Ab"); + } + + #[test] + fn structurally_invalid_rkey_is_rejected_rather_than_reaching_git() { + let name = keep_ref("did:plc:alice", "sh.tangled.string", "a..b"); + assert!(RefName::new(&name).is_err(), "{name} must be rejected"); + } +} diff --git a/knot2/crates/knot-xrpc/src/lib.rs b/knot2/crates/knot-xrpc/src/lib.rs index 70c78581..36d2332d 100644 --- a/knot2/crates/knot-xrpc/src/lib.rs +++ b/knot2/crates/knot-xrpc/src/lib.rs @@ -6,6 +6,7 @@ mod collaborators; mod error; mod events; mod forks; +mod git; pub mod legacy_admin; mod lfs; mod lists; @@ -298,6 +299,7 @@ pub fn router(state: Arc>) -> Router branches::DELETE_ROUTE, post(branches::delete_branch::), ) + .route(git::KEEP_COMMIT_ROUTE, post(git::keep_commit::)) .route(forks::SYNC_ROUTE, post(forks::fork_sync::)) .route(forks::HIDDEN_REF_ROUTE, post(forks::hidden_ref::)) .route(reads::TREE_ROUTE, get(reads::repo_tree::)) -- 2.51.2