tirbofish/kitgit · commit
09c7d9c61c765bb80b3a1849689c755f7e12e26f
fix: updated the ports so port 2222 is not required to be defined for the remote.
feat: on `ssh git@{git_server}`, you are given the poem "Fox". thought that would be nice
fix: upgraded openssh to support post-quantum (git kept on bothering).
Type: SSH
SSH Key Fingerprint:
Verified
SgQHY4vUORbJC3ZtdixCl62ek/4QGh/iG2FRSyjfGPc
@@ -10,30 +10,31 @@ checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" [[package]] name = "aead" -version = "0.5.2" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d122413f284cf2d62fb1b7db97e02edb8cda96d769b16e443a4f6195e35662b0" +checksum = "1973cfbc1a2daf9cf550e74e1f088c28e7f7d8c1e1418fb6c9dc5184b7e84c99" dependencies = [ - "crypto-common", - "generic-array", + "crypto-common 0.2.2", + "inout", ] [[package]] name = "aes" -version = "0.8.4" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0" +checksum = "f8eb277bec05f56a0e0591f155a484cbd0f4f07ff2905051a48c72f004f7ed58" dependencies = [ - "cfg-if", "cipher", - "cpufeatures 0.2.17", + "cpubits", + "cpufeatures 0.3.0", + "zeroize", ] [[package]] name = "aes-gcm" -version = "0.10.3" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "831010a0f742e1209b3bcea8fab6a8e149051ba6099432c8cb2cc117dec3ead1" +checksum = "fdf011db2e21ce0d575593d749db5554b47fed37aff429e4dc50bc91ac93a028" dependencies = [ "aead", "aes", @@ -41,6 +42,7 @@ dependencies = [ "ctr", "ghash", "subtle", + "zeroize", ] [[package]] @@ -125,13 +127,13 @@ checksum = "330a5ed07fa54e4702c9d6c4174f74427fc0ef6e214bbd677ae50a5099946470" [[package]] name = "argon2" -version = "0.5.3" +version = "0.6.0-rc.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c3610892ee6e0cbce8ae2700349fcf8f98adb0dbfbee85aec3c9179d29cc072" +checksum = "7af50940b73bf4e16c15c448a2b121c63f2d68e3e54b6a8731673cb4aa0cdff5" dependencies = [ "base64ct", "blake2", - "cpufeatures 0.2.17", + "cpufeatures 0.3.0", "password-hash", ] @@ -341,6 +343,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" [[package]] +name = "base16ct" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd307490d624467aa6f74b0eabb77633d1f758a7b25f12bceb0b22e08d9726f6" + +[[package]] name = "base64" version = "0.21.7" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -369,13 +377,13 @@ dependencies = [ [[package]] name = "bcrypt-pbkdf" -version = "0.10.0" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6aeac2e1fe888769f34f05ac343bbef98b14d1ffb292ab69d4608b3abc86f2a2" +checksum = "144e573728da132683b9488acd528274c790e07fc06ff81ee29f9d8f8b1041e0" dependencies = [ "blowfish", "pbkdf2", - "sha2", + "sha2 0.11.0", ] [[package]] @@ -413,11 +421,11 @@ dependencies = [ [[package]] name = "blake2" -version = "0.10.6" +version = "0.11.0-rc.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46502ad458c9a52b69d4d4d32775c788b7a1b85e8bc9d482d92250fc0e3f8efe" +checksum = "061f1a09225e328e1ffbb378d2d49923c0ca5fee19fb5ac1cc9c1e9d52b93690" dependencies = [ - "digest", + "digest 0.11.3", ] [[package]] @@ -426,23 +434,33 @@ version = "0.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" dependencies = [ - "generic-array", + "generic-array 0.14.9", +] + +[[package]] +name = "block-buffer" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2f6c7dbe95a6ed67ad9f18e57daf93a2f034c524b99fd2b76d18fdfeb6660aa" +dependencies = [ + "hybrid-array", + "zeroize", ] [[package]] name = "block-padding" -version = "0.3.3" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8894febbff9f758034a5b8e12d87918f56dfc64a8e1fe757d65e29041538d93" +checksum = "710f1dd022ef4e93f8a438b4ba958de7f64308434fa6a87104481645cc30068b" dependencies = [ - "generic-array", + "hybrid-array", ] [[package]] name = "blowfish" -version = "0.9.1" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e412e2cd0f2b2d93e02543ceae7917b3c70331573df19ee046bcbc35e45e87d7" +checksum = "62ce3946557b35e71d1bbe07ec385073ce9eda05043f95de134eb578fcf1a298" dependencies = [ "byteorder", "cipher", @@ -477,9 +495,9 @@ checksum = "fc652a48c352aef3ea3aed32080501cf3ef6ed5da78602a020c991775b0aff04" [[package]] name = "cbc" -version = "0.1.2" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26b52a9543ae338f279b96b0b9fed9c8093744685043739079ce85cd58f289a6" +checksum = "ce2dc9ee5f88d11e0beb842c88b33c8a5cf0d1329c4b19494af42b07dbfe8896" dependencies = [ "cipher", ] @@ -510,24 +528,15 @@ checksum = "f079e83a288787bcd14a6aea84cee5c87a67c5a3e660c30f557a3d24761b3527" [[package]] name = "chacha20" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3613f74bd2eac03dad61bd53dbe620703d4371614fe0bc3b9f04dd36fe4e818" -dependencies = [ - "cfg-if", - "cipher", - "cpufeatures 0.2.17", -] - -[[package]] -name = "chacha20" version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d524456ba66e72eb8b115ff89e01e497f8e6d11d78b70b1aa13c0fbd97540a81" dependencies = [ "cfg-if", + "cipher", "cpufeatures 0.3.0", "rand_core 0.10.1", + "zeroize", ] [[package]] @@ -546,12 +555,14 @@ dependencies = [ [[package]] name = "cipher" -version = "0.4.4" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" +checksum = "e8cf2a2c93cd704877c0858356ed03480ff301ee950b43f1cbe4573b088bfa6c" dependencies = [ - "crypto-common", + "block-buffer 0.12.1", + "crypto-common 0.2.2", "inout", + "zeroize", ] [[package]] @@ -595,6 +606,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c8d4a3bb8b1e0c1050499d1815f5ab16d04f0959b233085fb31653fbfc9d98f9" [[package]] +name = "cmov" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c9ea0ac24bc397ab3c98583a3c9ba74fa56b09a4449bbe172b9b1ddb016027a" + +[[package]] name = "colorchoice" version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -624,6 +641,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" [[package]] +name = "const-oid" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6ef517f0926dd24a1582492c791b6a4818a4d94e789a334894aa15b0d12f55c" + +[[package]] name = "cookie" version = "0.18.1" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -659,6 +682,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" [[package]] +name = "cpubits" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "15b85f9c39137c3a891689859392b1bd49812121d0d61c9caf00d46ed5ce06ae" + +[[package]] name = "cpufeatures" version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -721,33 +750,80 @@ version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" dependencies = [ - "generic-array", + "generic-array 0.14.9", "rand_core 0.6.4", "subtle", "zeroize", ] [[package]] +name = "crypto-bigint" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a52aa3fcda4e6302a9f48734f234d35d4721b96f8fe07d073f07ce9df4f0271" +dependencies = [ + "cpubits", + "ctutils", + "getrandom 0.4.3", + "hybrid-array", + "num-traits", + "rand_core 0.10.1", + "serdect", + "subtle", + "zeroize", +] + +[[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 0.6.4", + "generic-array 0.14.9", "typenum", ] [[package]] +name = "crypto-common" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce6e4c961d6cd6c9a86db418387425e8bdeaf05b3c8bc1411e6dca4c252f1453" +dependencies = [ + "getrandom 0.4.3", + "hybrid-array", + "rand_core 0.10.1", +] + +[[package]] +name = "crypto-primes" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3633a51a39c69ebbaa4feaa694bd83d241e4093901c84a0963b19d9bb3f0cf8f" +dependencies = [ + "crypto-bigint 0.7.5", + "rand_core 0.10.1", +] + +[[package]] name = "ctr" -version = "0.9.2" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0369ee1ad671834580515889b80f2ea915f23b8be8d0daa4bbaf2ac5c7590835" +checksum = "baaca1c4b237092596f64d571e9db6ce4109c4ef9742e27590f1709594461f21" dependencies = [ "cipher", ] [[package]] +name = "ctutils" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d5515a3834141de9eafb9717ad39eea8247b5674e6066c404e8c4b365d2a29e" +dependencies = [ + "cmov", + "subtle", +] + +[[package]] name = "curve25519-dalek" version = "4.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -756,8 +832,25 @@ dependencies = [ "cfg-if", "cpufeatures 0.2.17", "curve25519-dalek-derive", - "digest", - "fiat-crypto", + "digest 0.10.7", + "fiat-crypto 0.2.9", + "rustc_version", + "subtle", + "zeroize", +] + +[[package]] +name = "curve25519-dalek" +version = "5.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5eed333089e2e1c1ac8c6c0398e5e2497b4c9926ca6d0365ed1e099afa5bc23" +dependencies = [ + "cfg-if", + "cpufeatures 0.3.0", + "curve25519-dalek-derive", + "digest 0.11.3", + "fiat-crypto 0.3.0", + "rand_core 0.10.1", "rustc_version", "subtle", "zeroize", @@ -845,8 +938,19 @@ version = "0.7.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e7c1832837b905bbfb5101e07cc24c8deddf52f93225eee6ead5f4d63d53ddcb" dependencies = [ - "const-oid", - "pem-rfc7468", + "const-oid 0.9.6", + "pem-rfc7468 0.7.0", + "zeroize", +] + +[[package]] +name = "der" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a69dedd701da44b0536442edf09c81a64b0ab97a7a4a5e3d1971f00027cbc63d" +dependencies = [ + "const-oid 0.10.2", + "pem-rfc7468 1.0.0", "zeroize", ] @@ -860,18 +964,39 @@ dependencies = [ ] [[package]] +name = "des" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "916a94e407b54f9034d71dd748234cd1e516ced6284009906ae246f177eafe5a" +dependencies = [ + "cipher", +] + +[[package]] name = "digest" version = "0.10.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ - "block-buffer", - "const-oid", - "crypto-common", + "block-buffer 0.10.4", + "const-oid 0.9.6", + "crypto-common 0.1.6", "subtle", ] [[package]] +name = "digest" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1dd6dbb5841937940781866fa1281a1ff7bd3bf827091440879f9994983d5c2" +dependencies = [ + "block-buffer 0.12.1", + "const-oid 0.10.2", + "crypto-common 0.2.2", + "ctutils", +] + +[[package]] name = "displaydoc" version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -909,12 +1034,27 @@ version = "0.16.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ee27f32b5c5292967d2d4a9d7f1e0b0aed2c15daded5a60300e4abb9d8020bca" dependencies = [ - "der", - "digest", - "elliptic-curve", - "rfc6979", - "signature", - "spki", + "der 0.7.10", + "digest 0.10.7", + "elliptic-curve 0.13.8", + "rfc6979 0.4.0", + "signature 2.2.0", + "spki 0.7.3", +] + +[[package]] +name = "ecdsa" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0681a4fc24c767085329728d8dfba959af91228aa4610cca4f8ce317ba46ae0" +dependencies = [ + "der 0.8.1", + "digest 0.11.3", + "elliptic-curve 0.14.1", + "rfc6979 0.6.0", + "signature 3.0.0", + "spki 0.8.0", + "zeroize", ] [[package]] @@ -923,8 +1063,18 @@ version = "2.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "115531babc129696a58c64a4fef0a8bf9e9698629fb97e9e40767d235cfbcd53" dependencies = [ - "pkcs8", - "signature", + "pkcs8 0.10.2", + "signature 2.2.0", +] + +[[package]] +name = "ed25519" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29fcf32e6c73d1079f83ab4d782de2d81620346a5f38c6237a86a22f8368980a" +dependencies = [ + "pkcs8 0.11.0", + "signature 3.0.0", ] [[package]] @@ -933,11 +1083,26 @@ version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "70e796c081cee67dc755e1a36a0a172b897fab85fc3f6bc48307991f64e4eca9" dependencies = [ - "curve25519-dalek", - "ed25519", - "rand_core 0.6.4", + "curve25519-dalek 4.1.3", + "ed25519 2.2.3", "serde", - "sha2", + "sha2 0.10.9", + "subtle", + "zeroize", +] + +[[package]] +name = "ed25519-dalek" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ebaa1a2bf1290ab3bfe5a7b771d050ebffab2711c19a81691c683a5144a25de" +dependencies = [ + "curve25519-dalek 5.0.0", + "ed25519 3.0.0", + "rand_core 0.10.1", + "serde", + "sha2 0.11.0", + "signature 3.0.0", "subtle", "zeroize", ] @@ -957,17 +1122,39 @@ version = "0.13.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b5e6043086bf7973472e0c7dff2142ea0b680d30e18d9cc40f267efbf222bd47" dependencies = [ - "base16ct", - "crypto-bigint", - "digest", - "ff", - "generic-array", - "group", - "hkdf", - "pem-rfc7468", - "pkcs8", + "base16ct 0.2.0", + "crypto-bigint 0.5.5", + "digest 0.10.7", + "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", - "sec1", + "sec1 0.7.3", + "subtle", + "zeroize", +] + +[[package]] +name = "elliptic-curve" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d65aa39b3a5c1c9c1b745c9a019234bb7a21b77abcb4f4d266d706e2d577d65" +dependencies = [ + "base16ct 1.0.0", + "crypto-bigint 0.7.5", + "crypto-common 0.2.2", + "digest 0.11.3", + "ff 0.14.0", + "group 0.14.0", + "hkdf 0.13.0", + "hybrid-array", + "pem-rfc7468 1.0.0", + "pkcs8 0.11.0", + "rand_core 0.10.1", + "sec1 0.8.1", "subtle", "zeroize", ] @@ -1052,12 +1239,28 @@ dependencies = [ ] [[package]] +name = "ff" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1f686ab92a9fb0eaf188f6c6c87b89490baa6fdb0db4544ba4dc47f7942489f" +dependencies = [ + "rand_core 0.10.1", + "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" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64cd1e32ddd350061ae6edb1b082d7c54915b5c672c389143b9a63403a109f24" + +[[package]] name = "find-msvc-tools" version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1216,6 +1419,17 @@ dependencies = [ ] [[package]] +name = "generic-array" +version = "1.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab4e5aa225bc56696909483320f0ff9b600f1a971b52e07a17d70f3d9b43254b" +dependencies = [ + "generic-array 0.14.9", + "rustversion", + "typenum", +] + +[[package]] name = "getrandom" version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1244,11 +1458,10 @@ dependencies = [ [[package]] name = "ghash" -version = "0.5.1" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0d8a4362ccb29cb0b265253fb0a2728f592895ee6854fd9bc13f2ffda266ff1" +checksum = "2eecf2d5dc9b66b732b97707a0210906b1d30523eb773193ab777c0c84b3e8d5" dependencies = [ - "opaque-debug", "polyval", ] @@ -1273,12 +1486,23 @@ version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" dependencies = [ - "ff", + "ff 0.13.1", "rand_core 0.6.4", "subtle", ] [[package]] +name = "group" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fd1a1c7a5206c5b7a3f5a0d7ccd3ff85d0c8f5133d62a02680255b0004af5f4" +dependencies = [ + "ff 0.14.0", + "rand_core 0.10.1", + "subtle", +] + +[[package]] name = "hashbrown" version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1328,7 +1552,7 @@ dependencies = [ "http", "httpdate", "mime", - "sha1", + "sha1 0.10.7", ] [[package]] @@ -1354,9 +1578,9 @@ checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" [[package]] name = "hex-literal" -version = "0.4.1" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6fe2267d4ed49bc07b63801559be28c718ea06c4738b7a03c94df7386d2cde46" +checksum = "e712f64ec3850b98572bffac52e2c6f282b29fe6c5fa6d42334b30be438d95c1" [[package]] name = "hkdf" @@ -1364,7 +1588,16 @@ version = "0.12.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7b5f8eb2ad728638ea2c7d47a21db23b7b58a72ed6a38256b8a1849f15fbbdf7" dependencies = [ - "hmac", + "hmac 0.12.1", +] + +[[package]] +name = "hkdf" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4aaa26c720c68b866f2c96ef5c1264b3e6f473fe5d4ce61cd44bbe913e553018" +dependencies = [ + "hmac 0.13.0", ] [[package]] @@ -1373,7 +1606,16 @@ version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" dependencies = [ - "digest", + "digest 0.10.7", +] + +[[package]] +name = "hmac" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6303bc9732ae41b04cb554b844a762b4115a61bfaa81e3e83050991eeb56863f" +dependencies = [ + "digest 0.11.3", ] [[package]] @@ -1437,6 +1679,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" [[package]] +name = "hybrid-array" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "818356c5132c1fede50f837ca96afbe78ff42413047f4abb886217845e1b6c8c" +dependencies = [ + "ctutils", + "subtle", + "typenum", + "zeroize", +] + +[[package]] name = "hyper" version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1508,7 +1762,7 @@ dependencies = [ "js-sys", "log", "wasm-bindgen", - "windows-core 0.62.2", + "windows-core", ] [[package]] @@ -1654,40 +1908,24 @@ dependencies = [ [[package]] name = "inout" -version = "0.1.4" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "879f10e63c20629ecabbb64a8010319738c66a5cd0c29b02d63d272b03751d01" +checksum = "4250ce6452e92010fdf7268ccc5d14faa80bb12fc741938534c58f16804e03c7" dependencies = [ "block-padding", - "generic-array", + "hybrid-array", ] [[package]] -name = "internal-russh-forked-ssh-key" -version = "0.6.9+upstream-0.6.7" +name = "internal-russh-num-bigint" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb5af01d366561582e9ea5f841837cc1d8e37e7142a32f33a43801e81863cba5" +checksum = "ae8e22120c32fb4d19ec55fba35015f57095cd95a2e3b732e44457f5915b2ee8" dependencies = [ - "argon2", - "bcrypt-pbkdf", - "ecdsa", - "ed25519-dalek", - "hex", - "hmac", - "num-bigint-dig", - "p256", - "p384", - "p521", - "rand_core 0.6.4", - "rsa", - "sec1", - "sha1", - "sha2", - "signature", - "ssh-cipher", - "ssh-encoding", - "subtle", - "zeroize", + "num-integer", + "num-traits", + "rand 0.10.2", + "rand_core 0.10.1", ] [[package]] @@ -1739,6 +1977,26 @@ dependencies = [ ] [[package]] +name = "keccak" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e24a010dd405bd7ed803e5253182815b41bf2e6a80cc3bfc066658e03a198aa" +dependencies = [ + "cfg-if", + "cpufeatures 0.3.0", +] + +[[package]] +name = "kem" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01737161ba802849cfd486b5bd209d38ba4943494c249a8126005170c7621edd" +dependencies = [ + "crypto-common 0.2.2", + "rand_core 0.10.1", +] + +[[package]] name = "kitgit" version = "0.1.0" dependencies = [ @@ -1757,19 +2015,19 @@ dependencies = [ "futures", "git2", "hex", - "hmac", + "hmac 0.12.1", "http-body-util", "mime_guess", "openidconnect", "pulldown-cmark", "qrcode", - "rand 0.8.7", + "rand 0.10.2", "reqwest", "russh", "serde", "serde_json", - "sha1", - "sha2", + "sha1 0.10.7", + "sha2 0.10.9", "sqlx", "syntect", "thiserror 2.0.19", @@ -1924,14 +2182,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d89e7ee0cfbedfc4da3340218492196241d89eefb6dab27de5df917a6d2e78cf" dependencies = [ "cfg-if", - "digest", + "digest 0.10.7", ] [[package]] name = "md5" -version = "0.7.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "490cc448043f947bae3cbee9c203358d62dbee0db12107a74be5c30ccfd09771" +checksum = "7ebb8d8732c6a6df3d8f032a82911cfc747e00efb95cc46e8d0acd5b5b88570c" [[package]] name = "memchr" @@ -1977,6 +2235,31 @@ dependencies = [ ] [[package]] +name = "ml-kem" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e15f3e5b957493873e396a66914e83e616b6afe335cdef7efe5c6e1216aba66" +dependencies = [ + "hybrid-array", + "kem", + "module-lattice", + "pkcs8 0.11.0", + "rand_core 0.10.1", + "sha3 0.11.0", +] + +[[package]] +name = "module-lattice" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c61b87c9683ab7cb1c6871d261ad5479b6b10ceb52c4352aaca3b5d35a8febe" +dependencies = [ + "ctutils", + "hybrid-array", + "num-traits", +] + +[[package]] name = "multer" version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1994,6 +2277,18 @@ dependencies = [ ] [[package]] +name = "nix" +version = "0.31.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf20d2fde8ff38632c426f1165ed7436270b44f199fc55284c38276f9db47c3d" +dependencies = [ + "bitflags", + "cfg-if", + "cfg_aliases", + "libc", +] + +[[package]] name = "nu-ansi-term" version = "0.50.3" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -2010,7 +2305,6 @@ checksum = "c89e69e7e0f03bea5ef08013795c25018e101932225a656383bd384495ecc367" dependencies = [ "num-integer", "num-traits", - "rand 0.8.7", ] [[package]] @@ -2079,7 +2373,7 @@ dependencies = [ "serde", "serde_json", "serde_path_to_error", - "sha2", + "sha2 0.10.9", "thiserror 1.0.69", "url", ] @@ -2097,12 +2391,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe" [[package]] -name = "opaque-debug" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" - -[[package]] name = "openidconnect" version = "4.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -2111,23 +2399,23 @@ dependencies = [ "base64 0.21.7", "chrono", "dyn-clone", - "ed25519-dalek", - "hmac", + "ed25519-dalek 2.2.0", + "hmac 0.12.1", "http", "itertools", "log", "oauth2", - "p256", - "p384", + "p256 0.13.2", + "p384 0.13.1", "rand 0.8.7", - "rsa", + "rsa 0.9.10", "serde", "serde-value", "serde_json", "serde_path_to_error", "serde_plain", "serde_with", - "sha2", + "sha2 0.10.9", "subtle", "thiserror 1.0.69", "url", @@ -2166,10 +2454,23 @@ version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c9863ad85fa8f4460f9c48cb909d38a0d689dba1f6f6988a5e3e0d31071bcd4b" dependencies = [ - "ecdsa", - "elliptic-curve", - "primeorder", - "sha2", + "ecdsa 0.16.9", + "elliptic-curve 0.13.8", + "primeorder 0.13.6", + "sha2 0.10.9", +] + +[[package]] +name = "p256" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2c9239b2dbc807adbbe147e8cf72ea7450c3a0aabe62cb8e75ff4ec22e1f72a" +dependencies = [ + "ecdsa 0.17.0", + "elliptic-curve 0.14.1", + "primefield", + "primeorder 0.14.0", + "sha2 0.11.0", ] [[package]] @@ -2178,40 +2479,58 @@ version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fe42f1670a52a47d448f14b6a5c61dd78fce51856e68edaa38f7ae3a46b8d6b6" dependencies = [ - "ecdsa", - "elliptic-curve", - "primeorder", - "sha2", + "ecdsa 0.16.9", + "elliptic-curve 0.13.8", + "primeorder 0.13.6", + "sha2 0.10.9", +] + +[[package]] +name = "p384" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d17b851e6b3e378ab4ecb07fa2ed23f4d15f075735f8fec9fa1e7bdce5f8301f" +dependencies = [ + "ecdsa 0.17.0", + "elliptic-curve 0.14.1", + "fiat-crypto 0.3.0", + "primefield", + "primeorder 0.14.0", + "sha2 0.11.0", ] [[package]] name = "p521" -version = "0.13.3" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fc9e2161f1f215afdfce23677034ae137bbd45016a880c2eb3ba8eb95f085b2" +checksum = "4ad64cc32c2dc466317c12ee5853e61f159f9eab1fe7efade0395dc2e7b43449" dependencies = [ - "base16ct", - "ecdsa", - "elliptic-curve", - "primeorder", - "rand_core 0.6.4", - "sha2", + "base16ct 1.0.0", + "ecdsa 0.17.0", + "elliptic-curve 0.14.1", + "primefield", + "primeorder 0.14.0", + "sha2 0.11.0", ] [[package]] name = "pageant" -version = "0.0.2" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c6f0e349ea8dea1b50aa17c082777d30df133d89898c7568a615354772d3731" +checksum = "4f3a5ae18f65a85c67a77d18d42d3606c07948e3c17c1e5f74852b26589e88a5" dependencies = [ + "base16ct 1.0.0", + "byteorder", "bytes", "delegate", "futures", - "log", - "rand 0.8.7", - "thiserror 1.0.69", + "log", + "rand 0.10.2", + "sha2 0.11.0", + "thiserror 2.0.19", "tokio", "windows", + "windows-strings", ] [[package]] @@ -2245,23 +2564,21 @@ dependencies = [ [[package]] name = "password-hash" -version = "0.5.0" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "346f04948ba92c43e8469c1ee6736c7563d71012b17d40745260fe106aac2166" +checksum = "aab41826031698d6ffcd9cff78ef56ef998e39dc7e5067cdfebe373842d4723b" dependencies = [ - "base64ct", - "rand_core 0.6.4", - "subtle", + "phc", ] [[package]] name = "pbkdf2" -version = "0.12.2" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8ed6a7761f76e3b9f92dfb0a60a6a6477c61024b775147ff0973a02653abaf2" +checksum = "112d82ceb8c5bf524d9af484d4e4970c9fd5a0cc15ba14ad93dccd28873b0629" dependencies = [ - "digest", - "hmac", + "digest 0.11.3", + "hmac 0.13.0", ] [[package]] @@ -2274,12 +2591,31 @@ dependencies = [ ] [[package]] +name = "pem-rfc7468" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6305423e0e7738146434843d1694d621cce767262b2a86910beab705e4493d9" +dependencies = [ + "base64ct", +] + +[[package]] name = "percent-encoding" version = "2.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" [[package]] +name = "phc" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44dc769b75f93afdddd8c7fa12d685292ddeff1e66f7f0f3a234cf1818afe892" +dependencies = [ + "base64ct", + "ctutils", +] + +[[package]] name = "pin-project-lite" version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -2291,24 +2627,36 @@ version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c8ffb9f10fa047879315e6625af03c164b16962a5368d724ed16323b68ace47f" dependencies = [ - "der", - "pkcs8", - "spki", + "der 0.7.10", + "pkcs8 0.10.2", + "spki 0.7.3", +] + +[[package]] +name = "pkcs1" +version = "0.8.0-rc.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "986d2e952779af96ea048f160fd9194e1751b4faea78bcf3ceb456efe008088e" +dependencies = [ + "der 0.8.1", + "spki 0.8.0", ] [[package]] name = "pkcs5" -version = "0.7.1" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e847e2c91a18bfa887dd028ec33f2fe6f25db77db3619024764914affe8b69a6" +checksum = "63d440a804ec8d6fafbb6b84471e013286658d373248927692ab3366686220ca" dependencies = [ "aes", + "aes-gcm", "cbc", - "der", + "der 0.8.1", "pbkdf2", + "rand_core 0.10.1", "scrypt", - "sha2", - "spki", + "sha2 0.11.0", + "spki 0.8.0", ] [[package]] @@ -2317,10 +2665,20 @@ version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" dependencies = [ - "der", + "der 0.7.10", + "spki 0.7.3", +] + +[[package]] +name = "pkcs8" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "451913da69c775a56034ea8d9003d27ee8948e12443eae7c038ba100a4f21cb7" +dependencies = [ + "der 0.8.1", "pkcs5", - "rand_core 0.6.4", - "spki", + "rand_core 0.10.1", + "spki 0.8.0", ] [[package]] @@ -2337,24 +2695,23 @@ checksum = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6" [[package]] name = "poly1305" -version = "0.8.0" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8159bd90725d2df49889a078b54f4f79e87f1f8a8444194cdca81d38f5393abf" +checksum = "6e2d0073b297041425c7c3df6eb4792d598a15323fe63346852b092eca02904c" dependencies = [ - "cpufeatures 0.2.17", - "opaque-debug", + "cpufeatures 0.3.0", "universal-hash", + "zeroize", ] [[package]] name = "polyval" -version = "0.6.2" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d1fe60d06143b2430aa532c94cfe9e29783047f06c0d7fd359a9a51b729fa25" +checksum = "f0fa31d631f2b2cb2a544d0aa321ce847a94764d701ca2becc411138b93d49cd" dependencies = [ - "cfg-if", - "cpufeatures 0.2.17", - "opaque-debug", + "cpubits", + "cpufeatures 0.3.0", "universal-hash", ] @@ -2383,12 +2740,39 @@ dependencies = [ ] [[package]] +name = "primefield" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c555a6e4eb7d4e158fcb028c835c3b8642206ddc279b5c6b202ef9a8bdb592f4" +dependencies = [ + "crypto-bigint 0.7.5", + "crypto-common 0.2.2", + "ff 0.14.0", + "rand_core 0.10.1", + "subtle", + "zeroize", +] + +[[package]] name = "primeorder" version = "0.13.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "353e1ca18966c16d9deb1c69278edbc5f194139612772bd9537af60ac231e1e6" dependencies = [ - "elliptic-curve", + "elliptic-curve 0.13.8", +] + +[[package]] +name = "primeorder" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c9f42978c78a00e3d68f69fc03e57a234debae69da4020a4fb588fcdcd07b06" +dependencies = [ + "elliptic-curve 0.14.1", + "once_cell", + "primefield", + "serdect", + "wnaf", ] [[package]] @@ -2528,7 +2912,7 @@ version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c7f5fa3a058cd35567ef9bfa5e75732bee0f9e4c55fa90477bef2dfcdbc4be80" dependencies = [ - "chacha20 0.10.1", + "chacha20", "getrandom 0.4.3", "rand_core 0.10.1", ] @@ -2668,11 +3052,21 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2" dependencies = [ - "hmac", + "hmac 0.12.1", "subtle", ] [[package]] +name = "rfc6979" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4a459cddafb3fe76b31fd8f1108007566c40301feb64dc7b54656eb7388172b" +dependencies = [ + "crypto-bigint 0.7.5", + "hmac 0.13.0", +] + +[[package]] name = "ring" version = "0.17.14" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -2692,103 +3086,128 @@ version = "0.9.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b8573f03f5883dcaebdfcf4725caa1ecb9c15b2ef50c43a07b816e06799bb12d" dependencies = [ - "const-oid", - "digest", + "const-oid 0.9.6", + "digest 0.10.7", "num-bigint-dig", "num-integer", "num-traits", - "pkcs1", - "pkcs8", + "pkcs1 0.7.5", + "pkcs8 0.10.2", "rand_core 0.6.4", - "sha2", - "signature", - "spki", + "signature 2.2.0", + "spki 0.7.3", "subtle", "zeroize", ] [[package]] +name = "rsa" +version = "0.10.0-rc.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30b2aa4ba0d89f73d1e332df05be0eeab8840351c36ca5654341dfdb57bb3caf" +dependencies = [ + "const-oid 0.10.2", + "crypto-bigint 0.7.5", + "crypto-primes", + "digest 0.11.3", + "pkcs1 0.8.0-rc.4", + "pkcs8 0.11.0", + "rand_core 0.10.1", + "sha2 0.11.0", + "signature 3.0.0", + "spki 0.8.0", + "zeroize", +] + +[[package]] name = "russh" -version = "0.50.4" +version = "0.62.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02d8075561703e70dab7b095b2c13597cde37f5be94af0849fa4e51c315020d0" +checksum = "b8b67b5a0d8068c89dcbe9d95df986af7a851d1f3c604525274c37468e60464f" dependencies = [ "aes", - "aes-gcm", "bitflags", "block-padding", "byteorder", "bytes", "cbc", - "chacha20 0.9.1", + "cipher", + "crypto-bigint 0.7.5", "ctr", - "curve25519-dalek", + "curve25519-dalek 5.0.0", "data-encoding", "delegate", - "der", - "digest", - "ecdsa", - "ed25519-dalek", - "elliptic-curve", + "der 0.8.1", + "digest 0.11.3", + "ecdsa 0.17.0", + "ed25519-dalek 3.0.0", + "elliptic-curve 0.14.1", "enum_dispatch", "flate2", "futures", - "generic-array", - "getrandom 0.2.17", + "generic-array 1.4.4", + "getrandom 0.4.3", + "ghash", "hex-literal", - "hmac", - "home", + "hmac 0.13.0", "inout", - "internal-russh-forked-ssh-key", + "internal-russh-num-bigint", + "keccak", "log", "md5", + "ml-kem", + "module-lattice", "num-bigint", - "once_cell", - "p256", - "p384", + "p256 0.14.0", + "p384 0.14.0", "p521", "pageant", "pbkdf2", - "pkcs1", + "pkcs1 0.8.0-rc.4", "pkcs5", - "pkcs8", - "poly1305", - "rand 0.8.7", - "rand_core 0.6.4", - "rsa", + "pkcs8 0.11.0", + "polyval", + "rand 0.10.2", + "rand_core 0.10.1", + "ring", + "rsa 0.10.0-rc.18", "russh-cryptovec", "russh-util", - "sec1", - "sha1", - "sha2", - "signature", - "spki", + "salsa20", + "scrypt", + "sec1 0.8.1", + "sha1 0.11.0", + "sha2 0.11.0", + "sha3 0.12.0", + "signature 3.0.0", + "spki 0.8.0", "ssh-encoding", + "ssh-key", "subtle", - "thiserror 1.0.69", + "thiserror 2.0.19", "tokio", - "tokio-stream", "typenum", + "universal-hash", "zeroize", ] [[package]] name = "russh-cryptovec" -version = "0.50.2" +version = "0.62.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fcb7c127135848b47715b5bcb13d8a27ccd86ce1de1c15eab5982df91fe279a" +checksum = "3aec6cb630dbe85d72ffd7bcd95f07e1bd69f9f270ee8adfa1afe443a6331438" dependencies = [ - "libc", "log", + "nix", "ssh-encoding", - "winapi", + "windows-sys 0.61.2", ] [[package]] name = "russh-util" -version = "0.50.0" +version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c698d702527b51a82e64de98d506e9c1e83a063035d41df4f2354499ec090b79" +checksum = "668424a5dde0bcb45b55ba7de8476b93831b4aa2fa6947e145f3b053e22c60b6" dependencies = [ "chrono", "tokio", @@ -2860,10 +3279,11 @@ checksum = "9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f" [[package]] name = "salsa20" -version = "0.10.2" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97a22f5af31f73a954c10289c93e8a50cc23d971e80ee446f1f6f7137a088213" +checksum = "2f874456e72520ff1375a06c588eaf074b0f01f9e9e1aada45bd9b7954a6e42c" dependencies = [ + "cfg-if", "cipher", ] @@ -2908,13 +3328,14 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "scrypt" -version = "0.11.0" +version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0516a385866c09368f0b5bcd1caff3366aace790fcd46e2bb032697bb172fd1f" +checksum = "d87af57419b594aa23fa95f09f0e06d80d84ba01c26148c43844cad6ff4485f0" dependencies = [ + "cfg-if", "pbkdf2", "salsa20", - "sha2", + "sha2 0.11.0", ] [[package]] @@ -2923,10 +3344,24 @@ version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc" dependencies = [ - "base16ct", - "der", - "generic-array", - "pkcs8", + "base16ct 0.2.0", + "der 0.7.10", + "generic-array 0.14.9", + "pkcs8 0.10.2", + "subtle", + "zeroize", +] + +[[package]] +name = "sec1" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d56d437c2f19203ce5f7122e507831de96f3d2d4d3be5af44a0b0a09d8a80e4d" +dependencies = [ + "base16ct 1.0.0", + "ctutils", + "der 0.8.1", + "hybrid-array", "subtle", "zeroize", ] @@ -3064,6 +3499,16 @@ dependencies = [ ] [[package]] +name = "serdect" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "66cf8fedced2fcf12406bcb34223dffb92eaf34908ede12fed414c82b7f00b3e" +dependencies = [ + "base16ct 1.0.0", + "serde", +] + +[[package]] name = "sha1" version = "0.10.7" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -3071,7 +3516,18 @@ checksum = "a978451301f4db1d02937a4ab3ccce137717b81826e79b7d49ffe3244a13c3b8" dependencies = [ "cfg-if", "cpufeatures 0.2.17", - "digest", + "digest 0.10.7", +] + +[[package]] +name = "sha1" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aacc4cc499359472b4abe1bf11d0b12e688af9a805fa5e3016f9a386dc2d0214" +dependencies = [ + "cfg-if", + "cpufeatures 0.3.0", + "digest 0.11.3", ] [[package]] @@ -3082,7 +3538,39 @@ checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" dependencies = [ "cfg-if", "cpufeatures 0.2.17", - "digest", + "digest 0.10.7", +] + +[[package]] +name = "sha2" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "446ba717509524cb3f22f17ecc096f10f4822d76ab5c0b9822c5f9c284e825f4" +dependencies = [ + "cfg-if", + "cpufeatures 0.3.0", + "digest 0.11.3", +] + +[[package]] +name = "sha3" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be176f1a57ce4e3d31c1a166222d9768de5954f811601fb7ca06fc8203905ce1" +dependencies = [ + "digest 0.11.3", + "keccak", +] + +[[package]] +name = "sha3" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc9bad02c26382724b2d2692c6f179285e4b54eeecd7968f52a50059c3c11759" +dependencies = [ + "digest 0.11.3", + "keccak", + "sponge-cursor", ] [[package]] @@ -3116,11 +3604,21 @@ version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" dependencies = [ - "digest", + "digest 0.10.7", "rand_core 0.6.4", ] [[package]] +name = "signature" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28d567dcbaf0049cb8ac2608a76cd95ff9e4412e1899d389ee400918ca7537f5" +dependencies = [ + "digest 0.11.3", + "rand_core 0.10.1", +] + +[[package]] name = "simd-adler32" version = "0.3.10" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -3167,10 +3665,26 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" dependencies = [ "base64ct", - "der", + "der 0.7.10", +] + +[[package]] +name = "spki" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d9efca8738c78ee9484207732f728b1ef517bbb1833d6fc0879ca898a522f6f" +dependencies = [ + "base64ct", + "der 0.8.1", ] [[package]] +name = "sponge-cursor" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a0219bd7d979d58245a4f41f695e1ac9f8befdffadd7f61f1bae9e39abc6620" + +[[package]] name = "sqlx" version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -3210,7 +3724,7 @@ dependencies = [ "rustls", "serde", "serde_json", - "sha2", + "sha2 0.10.9", "smallvec", "thiserror 2.0.19", "tokio", @@ -3249,7 +3763,7 @@ dependencies = [ "quote", "serde", "serde_json", - "sha2", + "sha2 0.10.9", "sqlx-core", "sqlx-mysql", "sqlx-postgres", @@ -3272,17 +3786,17 @@ dependencies = [ "bytes", "chrono", "crc", - "digest", + "digest 0.10.7", "dotenvy", "either", "futures-channel", "futures-core", "futures-io", "futures-util", - "generic-array", + "generic-array 0.14.9", "hex", - "hkdf", - "hmac", + "hkdf 0.12.4", + "hmac 0.12.1", "itoa", "log", "md-5", @@ -3290,10 +3804,10 @@ dependencies = [ "once_cell", "percent-encoding", "rand 0.8.7", - "rsa", + "rsa 0.9.10", "serde", - "sha1", - "sha2", + "sha1 0.10.7", + "sha2 0.10.9", "smallvec", "sqlx-core", "stringprep", @@ -3321,8 +3835,8 @@ dependencies = [ "futures-core", "futures-util", "hex", - "hkdf", - "hmac", + "hkdf 0.12.4", + "hmac 0.12.1", "home", "itoa", "log", @@ -3332,7 +3846,7 @@ dependencies = [ "rand 0.8.7", "serde", "serde_json", - "sha2", + "sha2 0.10.9", "smallvec", "sqlx-core", "stringprep", @@ -3370,31 +3884,61 @@ dependencies = [ [[package]] name = "ssh-cipher" -version = "0.2.0" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "caac132742f0d33c3af65bfcde7f6aa8f62f0e991d80db99149eb9d44708784f" +checksum = "d801accda99469cde6d73da741422610fdf6508a72d9a69d1b55cb241c720597" dependencies = [ + "aead", "aes", "aes-gcm", - "cbc", - "chacha20 0.9.1", + "chacha20", "cipher", - "ctr", + "ctutils", + "des", "poly1305", "ssh-encoding", - "subtle", + "zeroize", ] [[package]] name = "ssh-encoding" -version = "0.2.0" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb9242b9ef4108a78e8cd1a2c98e193ef372437f8c22be363075233321dd4a15" +checksum = "7b54d0ed0498daf3f78d82e00e28c8eec9d75a067c4cfbcc7a0f7d0f4077749e" dependencies = [ "base64ct", "bytes", - "pem-rfc7468", - "sha2", + "crypto-bigint 0.7.5", + "ctutils", + "digest 0.11.3", + "pem-rfc7468 1.0.0", + "zeroize", +] + +[[package]] +name = "ssh-key" +version = "0.7.0-rc.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9a32fae177b74a22aa9c5b01bf7e68b33545be32d9e381e248058d2adc15ce3" +dependencies = [ + "argon2", + "bcrypt-pbkdf", + "ctutils", + "ed25519-dalek 3.0.0", + "hex", + "hmac 0.13.0", + "p256 0.14.0", + "p384 0.14.0", + "p521", + "rand_core 0.10.1", + "rsa 0.10.0-rc.18", + "sec1 0.8.1", + "sha1 0.11.0", + "sha2 0.11.0", + "signature 3.0.0", + "ssh-cipher", + "ssh-encoding", + "zeroize", ] [[package]] @@ -3637,7 +4181,6 @@ dependencies = [ "futures-core", "pin-project-lite", "tokio", - "tokio-util", ] [[package]] @@ -3860,12 +4403,12 @@ checksum = "7df058c713841ad818f1dc5d3fd88063241cc61f49f5fbea4b951e8cf5a8d71d" [[package]] name = "universal-hash" -version = "0.5.1" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc1de2c688dc15305988b563c3854064043356019f97a4b46276fe734c4f07ea" +checksum = "f4987bdc12753382e0bec4a65c50738ffaabc998b9cdd1f952fb5f39b0048a96" dependencies = [ - "crypto-common", - "subtle", + "crypto-common 0.2.2", + "ctutils", ] [[package]] @@ -4070,22 +4613,6 @@ dependencies = [ ] [[package]] -name = "winapi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" -dependencies = [ - "winapi-i686-pc-windows-gnu", - "winapi-x86_64-pc-windows-gnu", -] - -[[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" - -[[package]] name = "winapi-util" version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -4095,32 +4622,24 @@ dependencies = [ ] [[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" - -[[package]] name = "windows" -version = "0.58.0" +version = "0.62.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd04d41d93c4992d421894c18c8b43496aa748dd4c081bac0dc93eb0489272b6" +checksum = "527fadee13e0c05939a6a05d5bd6eec6cd2e3dbd648b9f8e447c6518133d8580" dependencies = [ - "windows-core 0.58.0", - "windows-targets 0.52.6", + "windows-collections", + "windows-core", + "windows-future", + "windows-numerics", ] [[package]] -name = "windows-core" -version = "0.58.0" +name = "windows-collections" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ba6d44ec8c2591c134257ce647b7ea6b20335bf6379a27dac5f1641fcf59f99" +checksum = "23b2d95af1a8a14a3c7367e1ed4fc9c20e0a26e79551b1454d72583c97cc6610" dependencies = [ - "windows-implement 0.58.0", - "windows-interface 0.58.0", - "windows-result 0.2.0", - "windows-strings 0.1.0", - "windows-targets 0.52.6", + "windows-core", ] [[package]] @@ -4129,22 +4648,22 @@ version = "0.62.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb" dependencies = [ - "windows-implement 0.60.2", - "windows-interface 0.59.3", + "windows-implement", + "windows-interface", "windows-link", - "windows-result 0.4.1", - "windows-strings 0.5.1", + "windows-result", + "windows-strings", ] [[package]] -name = "windows-implement" -version = "0.58.0" +name = "windows-future" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2bbd5b46c938e506ecbce286b6628a02171d56153ba733b6c741fc627ec9579b" +checksum = "e1d6f90251fe18a279739e78025bd6ddc52a7e22f921070ccdc67dde84c605cb" dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.119", + "windows-core", + "windows-link", + "windows-threading", ] [[package]] @@ -4160,17 +4679,6 @@ dependencies = [ [[package]] name = "windows-interface" -version = "0.58.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "053c4c462dc91d3b1504c6fe5a726dd15e216ba718e84a0e46a88fbe5ded3515" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.119", -] - -[[package]] -name = "windows-interface" version = "0.59.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" @@ -4187,12 +4695,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" [[package]] -name = "windows-result" -version = "0.2.0" +name = "windows-numerics" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d1043d8214f791817bab27572aaa8af63732e11bf84aa21a45a78d6c317ae0e" +checksum = "6e2e40844ac143cdb44aead537bbf727de9b044e107a0f1220392177d15b0f26" dependencies = [ - "windows-targets 0.52.6", + "windows-core", + "windows-link", ] [[package]] @@ -4206,16 +4715,6 @@ dependencies = [ [[package]] name = "windows-strings" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4cd9b125c486025df0eabcb585e62173c6c9eddcec5d117d3b6e8c30e2ee4d10" -dependencies = [ - "windows-result 0.2.0", - "windows-targets 0.52.6", -] - -[[package]] -name = "windows-strings" version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091" @@ -4282,6 +4781,15 @@ dependencies = [ ] [[package]] +name = "windows-threading" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3949bd5b99cafdf1c7ca86b43ca564028dfe27d66958f2470940f73d86d75b37" +dependencies = [ + "windows-link", +] + +[[package]] name = "windows_aarch64_gnullvm" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -4381,6 +4889,17 @@ dependencies = [ ] [[package]] +name = "wnaf" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab12e7090f27e2ffd9322651492942d50c2926094af30601e1964337db39daf1" +dependencies = [ + "ff 0.14.0", + "group 0.14.0", + "hybrid-array", +] + +[[package]] name = "writeable" version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -27,9 +27,9 @@ http-body-util = "0.1" mime_guess = "2" openidconnect = "4" pulldown-cmark = { version = "0.13", default-features = false, features = ["html", "simd"] } -rand = "0.8" +rand = "0.10" reqwest = { version = "0.12", default-features = false, features = ["json", "rustls-tls", "cookies", "gzip"] } -russh = "0.50" +russh = { version = "0.62", default-features = false, features = ["flate2", "rsa", "ring"] } serde = { version = "1", features = ["derive"] } serde_json = "1" sha2 = "0.10" @@ -1,349 +0,0 @@ -<!DOCTYPE html> -<html lang="en"> - <head> - <meta charset="utf-8" /> - <meta name="viewport" content="width=device-width, initial-scale=1" /> - <title>kitgit — brand</title> - <meta - name="description" - content="kitgit — self-hosted git. ink on paper." - /> - <link rel="preconnect" href="https://fonts.googleapis.com" /> - <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin /> - <!-- Web fallback when a Nerd Font is not installed locally --> - <link - href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;700&display=swap" - rel="stylesheet" - /> - <link rel="stylesheet" href="./theme.css" /> - <style> - .hero { - padding: var(--kg-space-6) 0 var(--kg-space-5); - min-height: calc(100vh - 4.5rem); - display: flex; - flex-direction: column; - justify-content: center; - } - - .hero p { - max-width: 28rem; - margin: var(--kg-space-4) 0 var(--kg-space-5); - color: var(--kg-muted); - font-size: 1rem; - } - - .section { - padding: var(--kg-space-5) 0; - } - - .section + .section { - border-top: 1px solid var(--kg-line); - } - - .stack { - display: flex; - flex-direction: column; - gap: var(--kg-space-3); - } - - .type-row { - display: grid; - gap: var(--kg-space-2); - } - - .type-row small { - color: var(--kg-faint); - font-size: 0.6875rem; - letter-spacing: 0.1em; - text-transform: uppercase; - } - - .toggle { - font: inherit; - font-size: 0.75rem; - letter-spacing: 0.08em; - text-transform: uppercase; - color: var(--kg-muted); - background: none; - border: 0; - cursor: pointer; - padding: 0; - } - - .toggle:hover { - color: var(--kg-fg); - } - - .sample-list { - list-style: none; - margin: 0; - padding: 0; - border: 1px solid var(--kg-line); - } - - .sample-list li { - display: flex; - justify-content: space-between; - gap: var(--kg-space-3); - padding: var(--kg-space-2) var(--kg-space-3); - border-bottom: 1px solid var(--kg-line); - font-size: 0.875rem; - } - - .sample-list li:last-child { - border-bottom: 0; - } - - .sample-list a { - color: var(--kg-fg); - text-decoration: none; - } - - .sample-list a:hover { - text-decoration: underline; - text-underline-offset: 0.2em; - } - - .voice { - display: grid; - gap: var(--kg-space-4); - } - - @media (min-width: 640px) { - .voice { - grid-template-columns: 1fr 1fr; - } - } - - .voice dt { - font-size: 0.75rem; - letter-spacing: 0.12em; - text-transform: uppercase; - color: var(--kg-muted); - margin-bottom: var(--kg-space-1); - } - - .voice dd { - margin: 0; - } - </style> - </head> - <body> - <div class="kg-shell"> - <header class="kg-bar"> - <a class="kg-mark" href="#"> - <span class="kg-mark__glyph" aria-hidden="true">狐</span> - <span class="kg-mark__name">kitgit</span> - </a> - <nav aria-label="Brand sections"> - <a href="#mark">mark</a> - <a href="#type">type</a> - <a href="#ink">ink</a> - <a href="#voice">voice</a> - </nav> - <button - type="button" - class="toggle" - id="theme-toggle" - aria-pressed="false" - > - invert - </button> - </header> - - <main> - <!-- first viewport: brand only --> - <section class="hero" aria-label="Brand"> - <a class="kg-mark kg-mark--hero kg-caret" href="#"> - <span class="kg-mark__glyph" aria-hidden="true">狐</span> - <span class="kg-mark__name">kitgit</span> - </a> - <p> - Self-hosted git. Templates, not a product page. Ink on paper. - </p> - <div class="kg-actions"> - <a class="kg-btn" href="#mark">read the system</a> - <a class="kg-btn kg-btn--ghost" href="#sample">see a template</a> - </div> - </section> - - <section class="section" id="mark"> - <span class="kg-kicker">01 — mark</span> - <h2 class="kg-display">Wordmark, not a logo lockup.</h2> - <p class="kg-muted" style="margin: 1rem 0 1.5rem; max-width: 36rem"> - Always lowercase. Always monospace. The mark is a solid ink square — - no SVG, no lockup. UI chrome elsewhere uses Nerd Font glyphs - (<code>nf-md-git</code>, branch, commit, etc.). - </p> - <div class="stack"> - <a class="kg-mark kg-mark--hero" href="#"> - <span class="kg-mark__glyph" aria-hidden="true">狐</span> - <span class="kg-mark__name">kitgit</span> - </a> - <a class="kg-mark" href="#"> - <span class="kg-mark__glyph" aria-hidden="true">狐</span> - <span class="kg-mark__name">kitgit</span> - </a> - <span class="kg-mark kg-faint"> - <span class="kg-mark__name">kitgit</span> - </span> - </div> - </section> - - <section class="section" id="type"> - <span class="kg-kicker">02 — type</span> - <h2 class="kg-display">One face. Nerd Font first.</h2> - <p class="kg-muted" style="margin: 1rem 0 1.5rem; max-width: 36rem"> - Primary stack: - <strong style="color: var(--kg-fg); font-weight: 500" - >JetBrainsMono Nerd Font</strong - > - → JetBrains Mono → FiraCode Nerd Font → system mono. No second - family. Hierarchy is weight and size only. - </p> - <div class="stack"> - <div class="type-row"> - <small>display / 700</small> - <p class="kg-display">clone. push. host.</p> - </div> - <div class="type-row"> - <small>title / 700</small> - <p class="kg-title">thribhu / kitgit</p> - </div> - <div class="type-row"> - <small>body / 400</small> - <p> - A bare forge for people who want git over http and ssh — and - almost nothing else. - </p> - </div> - <div class="type-row"> - <small>muted / 400</small> - <p class="kg-muted">updated 2h ago · 3 commits · main</p> - </div> - </div> - </section> - - <section class="section" id="ink"> - <span class="kg-kicker">03 — ink</span> - <h2 class="kg-display">Black. White. Stop.</h2> - <p class="kg-muted" style="margin: 1rem 0 1.5rem; max-width: 36rem"> - No accent hue. Interaction is invert, underline, or opacity. Borders - are either faint paper lines or full ink. - </p> - <div class="kg-swatches" aria-label="Color tokens"> - <div class="kg-swatch" style="background: #ffffff; color: #0a0a0a"> - <span>bg #fff</span> - </div> - <div class="kg-swatch" style="background: #f7f7f7; color: #0a0a0a"> - <span>raised #f7</span> - </div> - <div class="kg-swatch" style="background: #0a0a0a; color: #ffffff"> - <span>fg #0a</span> - </div> - <div class="kg-swatch" style="background: #6b6b6b; color: #ffffff"> - <span>muted #6b</span> - </div> - <div class="kg-swatch" style="background: #e5e5e5; color: #0a0a0a"> - <span>line #e5</span> - </div> - <div class="kg-swatch" style="background: #0a0a0a; color: #ffffff"> - <span>invert</span> - </div> - </div> - <pre - class="kg-code" - style="margin-top: 1.5rem" - aria-label="Install example" - ><span class="cm"># serve a bare repo</span> -$ kitgit init ~/repos/app.git -$ kitgit serve --listen 0.0.0.0:8080 -<span class="ok">listening on :8080</span></pre> - </section> - - <section class="section" id="voice"> - <span class="kg-kicker">04 — voice</span> - <h2 class="kg-display">Short. Literal. Quiet.</h2> - <dl class="voice" style="margin-top: 1.5rem"> - <div> - <dt>Name</dt> - <dd><strong>kitgit</strong> — kit + git. A kit you host.</dd> - </div> - <div> - <dt>Tagline</dt> - <dd>Self-hosted git. Templates, not a product page.</dd> - </div> - <div> - <dt>Say</dt> - <dd> - “repos”, “bare”, “clone url”, “owner”, “push”. Prefer verbs over - marketing nouns. - </dd> - </div> - <div> - <dt>Don’t say</dt> - <dd> - “forge platform”, “developer experience”, “seamless”, “powerful”, - “next-gen”. - </dd> - </div> - <div> - <dt>UI copy</dt> - <dd> - Sentence case. No exclamation marks. Empty states are one line: - <em class="kg-muted">no repos yet.</em> - </dd> - </div> - <div> - <dt>Iconography</dt> - <dd> - Nerd Font codepoints only. No SVG icon packs. Prefer text labels - when a glyph would be decorative. - </dd> - </div> - </dl> - </section> - - <section class="section" id="sample"> - <span class="kg-kicker">05 — template sample</span> - <h2 class="kg-display">How a page should feel.</h2> - <p class="kg-muted" style="margin: 1rem 0 1.5rem; max-width: 36rem"> - One job. One title. Lists over cards. Metadata stays muted. - </p> - <p class="kg-title" style="margin-bottom: 0.75rem">repos</p> - <ul class="sample-list"> - <li> - <a href="#">thribhu/kitgit</a> - <span class="kg-muted">main · 12c</span> - </li> - <li> - <a href="#">thribhu/notes</a> - <span class="kg-muted">trunk · 4c</span> - </li> - <li> - <a href="#">ops/backup</a> - <span class="kg-muted">master · 1c</span> - </li> - </ul> - <p class="kg-faint" style="margin-top: 1rem; font-size: 0.75rem"> - clone · http://git.example/thribhu/kitgit.git - </p> - </section> - </main> - - <footer class="kg-footer"> - kitgit · ink on paper · brand v0.1 - </footer> - </div> - - <script> - const root = document.documentElement; - const btn = document.getElementById("theme-toggle"); - btn.addEventListener("click", () => { - const on = root.classList.toggle("kg-dark"); - btn.setAttribute("aria-pressed", String(on)); - btn.textContent = on ? "paper" : "invert"; - }); - </script> - </body> -</html> @@ -1,371 +0,0 @@ -/* kitgit — brand theme - ink on paper. no chrome. */ - -:root { - /* surfaces */ - --kg-bg: #ffffff; - --kg-bg-raised: #f7f7f7; - --kg-fg: #0a0a0a; - --kg-muted: #6b6b6b; - --kg-faint: #a3a3a3; - --kg-line: #e5e5e5; - --kg-line-strong: #0a0a0a; - - /* interactive */ - --kg-link: #0a0a0a; - --kg-link-hover: #0a0a0a; - --kg-focus: #0a0a0a; - --kg-danger: #0a0a0a; - - /* invert block (nav, code, CTA) */ - --kg-invert-bg: #0a0a0a; - --kg-invert-fg: #ffffff; - --kg-invert-muted: #a3a3a3; - - /* type */ - --kg-font: "JetBrainsMono Nerd Font", "JetBrainsMono NF", "JetBrains Mono", - "FiraCode Nerd Font", "Fira Code", "SauceCodePro Nerd Font", - ui-monospace, "Cascadia Code", "SF Mono", Menlo, Consolas, monospace; - --kg-font-size: 14px; - --kg-line-height: 1.55; - --kg-tracking-tight: -0.02em; - --kg-tracking-brand: 0.08em; - - /* rhythm */ - --kg-space-1: 0.25rem; - --kg-space-2: 0.5rem; - --kg-space-3: 1rem; - --kg-space-4: 1.5rem; - --kg-space-5: 2.5rem; - --kg-space-6: 4rem; - --kg-max: 75rem; - --kg-radius: 0; - - color-scheme: light; -} - -/* optional dark invert — add class="kg-dark" on <html> */ -html.kg-dark { - --kg-bg: #0a0a0a; - --kg-bg-raised: #141414; - --kg-fg: #f5f5f5; - --kg-muted: #8a8a8a; - --kg-faint: #5c5c5c; - --kg-line: #262626; - --kg-line-strong: #f5f5f5; - --kg-link: #f5f5f5; - --kg-invert-bg: #f5f5f5; - --kg-invert-fg: #0a0a0a; - --kg-invert-muted: #525252; - color-scheme: dark; -} - -*, -*::before, -*::after { - box-sizing: border-box; -} - -html { - font-size: var(--kg-font-size); - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; - text-rendering: optimizeLegibility; -} - -body { - margin: 0; - min-height: 100vh; - font-family: var(--kg-font); - font-size: 1rem; - line-height: var(--kg-line-height); - color: var(--kg-fg); - background: var(--kg-bg); -} - -/* —— wordmark —— */ -.kg-mark { - display: inline-flex; - align-items: baseline; - gap: 0.55em; - font-family: var(--kg-font); - font-weight: 700; - font-size: 1.125rem; - letter-spacing: var(--kg-tracking-brand); - text-transform: lowercase; - text-decoration: none; - color: var(--kg-fg); - line-height: 1; -} - -.kg-mark__glyph { - display: inline-block; - flex-shrink: 0; - align-self: center; - font-weight: 700; - letter-spacing: 0; - font-size: 1.15em; - line-height: 1; - speak: never; -} - -.kg-mark__name { - letter-spacing: var(--kg-tracking-brand); -} - -.kg-mark--hero { - font-size: clamp(2.5rem, 8vw, 4.5rem); - letter-spacing: 0.06em; -} - -.kg-mark--hero .kg-mark__glyph { - font-size: 1.05em; -} - -/* —— type scale —— */ -.kg-display { - font-family: var(--kg-font); - font-weight: 700; - font-size: clamp(1.75rem, 4vw, 2.25rem); - line-height: 1.2; - letter-spacing: var(--kg-tracking-tight); - margin: 0; -} - -.kg-title { - font-weight: 700; - font-size: 1.125rem; - letter-spacing: var(--kg-tracking-tight); - margin: 0; -} - -.kg-body { - margin: 0; - color: var(--kg-fg); -} - -.kg-muted { - color: var(--kg-muted); -} - -.kg-faint { - color: var(--kg-faint); -} - -.kg-mono { - font-family: var(--kg-font); -} - -.kg-kicker { - display: block; - font-size: 0.75rem; - letter-spacing: 0.14em; - text-transform: uppercase; - color: var(--kg-muted); - margin: 0 0 var(--kg-space-3); -} - -/* —— links & controls —— */ -a.kg-link { - color: var(--kg-link); - text-decoration: underline; - text-underline-offset: 0.2em; - text-decoration-thickness: 1px; -} - -a.kg-link:hover { - text-decoration-thickness: 2px; -} - -.kg-btn { - display: inline-flex; - align-items: center; - justify-content: center; - gap: 0.5em; - padding: 0.65em 1.1em; - font-family: var(--kg-font); - font-size: 0.875rem; - font-weight: 500; - letter-spacing: 0.02em; - line-height: 1; - border: 1px solid var(--kg-line-strong); - border-radius: var(--kg-radius); - background: var(--kg-invert-bg); - color: var(--kg-invert-fg); - text-decoration: none; - cursor: pointer; - transition: opacity 120ms ease; -} - -.kg-btn:hover { - opacity: 0.85; -} - -.kg-btn:focus-visible { - outline: 2px solid var(--kg-focus); - outline-offset: 3px; -} - -.kg-btn--ghost { - background: transparent; - color: var(--kg-fg); -} - -.kg-btn--ghost:hover { - opacity: 1; - background: var(--kg-bg-raised); -} - -.kg-actions { - display: flex; - flex-wrap: wrap; - gap: var(--kg-space-2); -} - -/* —— structure —— */ -.kg-shell { - width: min(100% - 2rem, var(--kg-max)); - margin-inline: auto; -} - -.kg-rule { - border: 0; - border-top: 1px solid var(--kg-line); - margin: var(--kg-space-5) 0; -} - -.kg-rule--strong { - border-top-color: var(--kg-line-strong); -} - -.kg-bar { - display: flex; - align-items: center; - justify-content: space-between; - gap: var(--kg-space-3); - padding: var(--kg-space-3) 0; - border-bottom: 1px solid var(--kg-line); -} - -.kg-bar nav { - display: flex; - gap: var(--kg-space-3); -} - -.kg-bar nav a { - color: var(--kg-muted); - text-decoration: none; - font-size: 0.8125rem; - letter-spacing: 0.04em; -} - -.kg-bar nav a:hover, -.kg-bar nav a[aria-current="page"] { - color: var(--kg-fg); -} - -.kg-footer { - padding: var(--kg-space-4) 0 var(--kg-space-6); - color: var(--kg-faint); - font-size: 0.75rem; - letter-spacing: 0.06em; -} - -/* code / terminal strip */ -.kg-code { - display: block; - padding: var(--kg-space-3) var(--kg-space-4); - background: var(--kg-invert-bg); - color: var(--kg-invert-fg); - font-family: var(--kg-font); - font-size: 0.8125rem; - line-height: 1.6; - overflow-x: auto; - border-radius: var(--kg-radius); -} - -.kg-code .cm { - color: var(--kg-invert-muted); -} - -.kg-code .ok { - color: var(--kg-invert-fg); -} - -/* token swatches (brand preview only) */ -.kg-swatches { - display: grid; - grid-template-columns: repeat(auto-fill, minmax(7rem, 1fr)); - gap: var(--kg-space-2); -} - -.kg-swatch { - aspect-ratio: 1; - border: 1px solid var(--kg-line); - display: flex; - flex-direction: column; - justify-content: flex-end; - padding: var(--kg-space-2); - font-size: 0.6875rem; - letter-spacing: 0.04em; -} - -.kg-swatch span { - background: color-mix(in srgb, var(--kg-bg) 85%, transparent); - padding: 0.1em 0.25em; -} - -/* motion — presence, not noise */ -@keyframes kg-ink { - from { - opacity: 0; - transform: translateY(0.4rem); - } - to { - opacity: 1; - transform: translateY(0); - } -} - -@keyframes kg-caret { - 0%, - 49% { - opacity: 1; - } - 50%, - 100% { - opacity: 0; - } -} - -.kg-in { - animation: kg-ink 480ms ease both; -} - -.kg-in-2 { - animation: kg-ink 480ms ease 80ms both; -} - -.kg-in-3 { - animation: kg-ink 480ms ease 160ms both; -} - -.kg-caret::after { - content: "█"; - margin-left: 0.15em; - animation: kg-caret 1.1s step-end infinite; - font-weight: 400; -} - -@media (prefers-reduced-motion: reduce) { - .kg-in, - .kg-in-2, - .kg-in-3 { - animation: none; - } - - .kg-caret::after { - animation: none; - opacity: 1; - } -} @@ -5,6 +5,8 @@ AUTHENTIK_BOOTSTRAP_PASSWORD= AUTHENTIK_BOOTSTRAP_EMAIL=admin@tirbo.fish KITGIT_PUBLIC_URL=https://git.tirbo.fish +# Optional; prod compose sets this to 22 so clone URLs omit a non-default port. +# KITGIT_SSH_PUBLIC_PORT=22 KITGIT_SESSION_SECRET= KITGIT_OIDC_ISSUER=https://auth.tirbo.fish/application/o/kitgit/ KITGIT_OIDC_DISCOVERY_URL=http://authentik-server:9000/application/o/kitgit/ @@ -100,6 +100,8 @@ services: KITGIT_DATA_DIR: /data KITGIT_HTTP_BIND: 0.0.0.0:8080 KITGIT_SSH_BIND: 0.0.0.0:2222 + # Advertise classic git@host:… URLs (host publishes 22 → container 2222). + KITGIT_SSH_PUBLIC_PORT: "22" KITGIT_PUBLIC_URL: ${KITGIT_PUBLIC_URL} KITGIT_SESSION_SECRET: ${KITGIT_SESSION_SECRET} KITGIT_OIDC_ISSUER: ${KITGIT_OIDC_ISSUER} @@ -115,7 +117,8 @@ services: volumes: - kitgit-data:/data ports: - - "2222:2222" + # Host 22 = Git SSH (GitHub-style). Droplet admin sshd listens on 2222. + - "22:2222" depends_on: postgres: condition: service_healthy @@ -4,7 +4,8 @@ |----------|---------| | `KITGIT_DATABASE_URL` | Postgres | | `KITGIT_DATA_DIR` | Repos, avatars, SSH host key, releases | -| `KITGIT_HTTP_BIND` / `KITGIT_SSH_BIND` | Listen addresses | +| `KITGIT_HTTP_BIND` / `KITGIT_SSH_BIND` | Listen addresses (container-internal) | +| `KITGIT_SSH_PUBLIC_PORT` | Port in clone URLs / `ssh git@host` (default: bind port; use `22` when published as `22:2222`) | | `KITGIT_PUBLIC_URL` | Public base URL for clone links | | `KITGIT_SESSION_SECRET` | Session cookie secret | | `KITGIT_OIDC_ISSUER` | Public issuer (browser), e.g. `http://localhost:9000/application/o/kitgit/` | @@ -6,7 +6,8 @@ Minimal single-Droplet deploy under the **personal** project: |----------|-------| | Droplet | `kitgit` · `s-2vcpu-4gb` · `syd1` · Docker 1-Click | | Sites | https://git.tirbo.fish · https://auth.tirbo.fish | -| Git SSH | `git.tirbo.fish:2222` | +| Git SSH | `git@git.tirbo.fish` (host port 22 → kitgit) | +| Admin SSH | droplet port **2222** (system `sshd`; not Git) | | Cost | ~$24/mo (droplet only; no managed DB/LB/registry) | On the droplet, the stack lives in `/opt/kitgit` and is started with: @@ -17,3 +18,5 @@ docker compose up -d --build ``` Prod files: `deploy/docker-compose.prod.yml`, `deploy/Caddyfile`, `deploy/.env.prod.example`, `deploy/authentik/blueprints-prod/`. + +**SSH layout:** Git uses host port **22** (`ssh git@git.tirbo.fish`). Droplet admin `sshd` is on **2222** (`ssh -p 2222 root@…`). @@ -105,9 +105,9 @@ pub fn hash_token(token: &str) -> String { } pub fn new_session_token() -> String { - use rand::RngCore; + use rand::RngExt; let mut buf = [0u8; 32]; - rand::thread_rng().fill_bytes(&mut buf); + rand::rng().fill(&mut buf); hex::encode(buf) } @@ -23,6 +23,11 @@ pub struct Config { #[arg(long, env = "KITGIT_SSH_BIND", default_value = "0.0.0.0:2222")] pub ssh_bind: SocketAddr, + /// Port advertised in clone URLs / `ssh git@host`. Defaults to the + /// `KITGIT_SSH_BIND` port. Set to `22` in production when published as `22:2222`. + #[arg(long, env = "KITGIT_SSH_PUBLIC_PORT", default_value_t = 0)] + pub ssh_public_port: u16, + #[arg(long, env = "KITGIT_PUBLIC_URL", default_value = "http://localhost:8080")] pub public_url: String, @@ -163,4 +168,13 @@ impl Config { pub fn ssh_host_key_path(&self) -> PathBuf { self.data_dir.join("ssh_host_ed25519_key") } + + /// External SSH port for clone URLs. Falls back to the bind port when unset (0). + pub fn ssh_advertise_port(&self) -> u16 { + if self.ssh_public_port == 0 { + self.ssh_bind.port() + } else { + self.ssh_public_port + } + } } @@ -240,6 +240,23 @@ pub fn read_blob(repo: &G2Repo, reference: &str, path: &str) -> Result<(Vec<u8>, Ok((data, binary)) } +/// Whether `path` is a tree (directory) at `reference`. Missing paths are not trees. +pub fn path_is_dir(repo: &G2Repo, reference: &str, path: &str) -> bool { + if path.is_empty() { + return true; + } + let Ok(commit) = repo.revparse_single(reference).and_then(|o| o.peel_to_commit()) else { + return false; + }; + let Ok(tree) = commit.tree() else { + return false; + }; + let Ok(entry) = tree.get_path(Path::new(path)) else { + return false; + }; + entry.kind() == Some(ObjectType::Tree) +} + /// Find a README in `dir` only (GitHub-style). Empty `dir` = repo root. /// Does not fall back to parent/root READMEs when browsing a subdirectory. pub fn find_readme( @@ -3,9 +3,9 @@ use crate::git::repo::bare_path; use crate::state::AppState; use anyhow::{Context, Result}; use base64::Engine; -use russh::keys::{decode_secret_key, encode_pkcs8_pem, PublicKey as RPublicKey, PublicKeyBase64}; -use russh::server::{Auth, Handler, Msg, Server, Session}; -use russh::{Channel, ChannelId, CryptoVec, MethodKind, MethodSet}; +use russh::keys::{decode_secret_key, encode_pkcs8_pem, PublicKeyBase64}; +use russh::server::{Auth, ChannelOpenHandle, Handler, Msg, Server, Session}; +use russh::{Channel, ChannelId, MethodKind, MethodSet}; use sha2::{Digest, Sha256}; use std::path::PathBuf; use std::process::Stdio; @@ -20,6 +20,13 @@ fn publickey_methods() -> MethodSet { m } +fn auth_reject() -> Auth { + Auth::Reject { + proceed_with_methods: Some(publickey_methods()), + partial_success: false, + } +} + pub async fn run_ssh(state: AppState) -> Result<()> { std::fs::create_dir_all(&state.config.data_dir)?; let key_path = state.config.ssh_host_key_path(); @@ -30,6 +37,8 @@ pub async fn run_ssh(state: AppState) -> Result<()> { auth_rejection_time: std::time::Duration::from_secs(1), keys: vec![key], methods: publickey_methods(), + // Default Preferred leads with mlkem768x25519-sha256 (PQ hybrid KEX). + preferred: russh::Preferred::DEFAULT, ..Default::default() }; let bind = state.config.ssh_bind; @@ -46,7 +55,7 @@ fn load_or_create_host_key(path: &PathBuf) -> Result<russh::keys::PrivateKey> { return decode_secret_key(&data, None).context("decode host key"); } let key = russh::keys::PrivateKey::random( - &mut rand::thread_rng(), + &mut rand::rng(), russh::keys::Algorithm::Ed25519, )?; let mut pem = Vec::new(); @@ -64,7 +73,7 @@ pub fn fingerprint_ssh_pubkey(line: &str) -> Result<String> { Ok(ssh_fingerprint_sha256(&raw)) } -fn fingerprint_public_key(key: &RPublicKey) -> String { +fn fingerprint_public_key(key: &russh::keys::PublicKey) -> String { // Must match the authorized_keys blob (type || key material), same as // OpenSSH `ssh-keygen -lf` SHA256 fingerprints (base64, no padding). let blob = key.public_key_bytes(); @@ -91,6 +100,7 @@ impl Server for SshServer { SshHandler { state: self.state.clone(), user_id: None, + username: None, stdin: None, receive_meta: None, } @@ -100,27 +110,55 @@ impl Server for SshServer { struct SshHandler { state: AppState, user_id: Option<Uuid>, + username: Option<String>, stdin: Option<Arc<Mutex<tokio::process::ChildStdin>>>, receive_meta: Option<(String, String)>, } +impl SshHandler { + /// Print `static/text.txt` (with `{user}` substituted) and close — no shell access. + async fn greet_and_quit( + &self, + channel: ChannelId, + session: &mut Session, + ) -> Result<(), anyhow::Error> { + let username = self.username.as_deref().unwrap_or("git"); + let path = self.state.config.static_dir.join("text.txt"); + let mut msg = tokio::fs::read_to_string(&path).await.unwrap_or_else(|_| { + format!( + "Hi {username}! You've successfully authenticated, but kitgit does not provide shell access.\n" + ) + }); + msg = msg.replace("{user}", username); + if !msg.ends_with('\n') { + msg.push('\n'); + } + session.channel_success(channel)?; + session.data(channel, msg.into_bytes())?; + // Match GitHub: non-zero exit so clients don't treat this as a shell login. + session.exit_status_request(channel, 1)?; + session.eof(channel)?; + session.close(channel)?; + Ok(()) + } +} + impl Handler for SshHandler { type Error = anyhow::Error; async fn auth_publickey( &mut self, _user: &str, - public_key: &RPublicKey, + public_key: &russh::keys::PublicKey, ) -> Result<Auth, Self::Error> { let fp = fingerprint_public_key(public_key); if let Some(user) = queries::user_by_ssh_fingerprint(&self.state.pool, &fp).await? { self.user_id = Some(user.id); + self.username = Some(user.username); return Ok(Auth::Accept); } tracing::debug!("ssh publickey rejected fp={fp}"); - Ok(Auth::Reject { - proceed_with_methods: Some(publickey_methods()), - }) + Ok(auth_reject()) } async fn auth_password( @@ -129,17 +167,45 @@ impl Handler for SshHandler { _password: &str, ) -> Result<Auth, Self::Error> { // Password auth is not supported — keys only. - Ok(Auth::Reject { - proceed_with_methods: Some(publickey_methods()), - }) + Ok(auth_reject()) } async fn channel_open_session( &mut self, _channel: Channel<Msg>, + reply: ChannelOpenHandle, _session: &mut Session, - ) -> Result<bool, Self::Error> { - Ok(true) + ) -> Result<(), Self::Error> { + reply.accept().await; + Ok(()) + } + + async fn pty_request( + &mut self, + channel: ChannelId, + _term: &str, + _col_width: u32, + _row_height: u32, + _pix_width: u32, + _pix_height: u32, + _modes: &[(russh::Pty, u32)], + session: &mut Session, + ) -> Result<(), Self::Error> { + // Accept PTY so interactive `ssh git@host` can proceed to shell_request. + session.channel_success(channel)?; + Ok(()) + } + + async fn shell_request( + &mut self, + channel: ChannelId, + session: &mut Session, + ) -> Result<(), Self::Error> { + if self.user_id.is_none() { + session.channel_failure(channel)?; + return Ok(()); + } + self.greet_and_quit(channel, session).await } async fn exec_request( @@ -157,16 +223,13 @@ impl Handler for SshHandler { let (service, repo_path) = match parse_git_command(&cmd) { Ok(v) => v, Err(_) => { - session.data(channel, CryptoVec::from_slice(b"unsupported command\n"))?; - session.exit_status_request(channel, 1)?; - session.eof(channel)?; - session.close(channel)?; - return Ok(()); + // Non-git exec (e.g. `ssh host exit`) — same greeting as a bare SSH. + return self.greet_and_quit(channel, session).await; } }; let (owner, name) = split_repo_path(&repo_path)?; let Some((repo, _)) = queries::get_repo(&self.state.pool, &owner, &name).await? else { - session.data(channel, CryptoVec::from_slice(b"repository not found\n"))?; + session.data(channel, b"repository not found\n".as_slice())?; session.exit_status_request(channel, 1)?; session.eof(channel)?; session.close(channel)?; @@ -179,7 +242,7 @@ impl Handler for SshHandler { _ => false, }; if !allowed { - session.data(channel, CryptoVec::from_slice(b"access denied\n"))?; + session.data(channel, b"access denied\n".as_slice())?; session.exit_status_request(channel, 1)?; session.eof(channel)?; session.close(channel)?; @@ -208,7 +271,7 @@ impl Handler for SshHandler { match stdout.read(&mut buf).await { Ok(0) => break, Ok(n) => { - let _ = handle.data(channel, CryptoVec::from_slice(&buf[..n])).await; + let _ = handle.data(channel, buf[..n].to_vec()).await; } Err(_) => break, } @@ -1,9 +1,38 @@ -use pulldown_cmark::{html, Options, Parser}; +use pulldown_cmark::{Event, Options, Parser, Tag, html}; use std::borrow::Cow; +/// Where a Markdown file lives inside a repository, used to rewrite relative +/// links/images so they resolve under `/{owner}/{repo}/…` instead of replacing +/// the repo name in the browser URL (e.g. `/owner/docs`). +#[derive(Clone, Copy, Debug)] +pub struct MarkdownRepoBase<'a> { + pub owner: &'a str, + pub repo: &'a str, + pub git_ref: &'a str, + /// Directory containing the Markdown file (`""` for repo root). + pub dir: &'a str, +} + /// Render Markdown to HTML. Protects TeX math from Markdown emphasis/escaping, /// then leaves `$…$` / `$$…$$` for client-side KaTeX (+ KaTeX fonts). pub fn render_markdown(src: &str) -> String { + render_markdown_inner(src, None) +} + +/// Like [`render_markdown`], but rewrites relative links and images against a +/// repository path. `is_dir` should return true when `path` is a tree entry. +pub fn render_markdown_in_repo( + src: &str, + base: &MarkdownRepoBase<'_>, + is_dir: impl Fn(&str) -> bool, +) -> String { + render_markdown_inner(src, Some((base, &is_dir))) +} + +fn render_markdown_inner( + src: &str, + repo: Option<(&MarkdownRepoBase<'_>, &dyn Fn(&str) -> bool)>, +) -> String { let src = src.strip_prefix('\u{feff}').unwrap_or(src); let src = preprocess_math_fences(src); let (protected, slots) = protect_math(&src); @@ -14,10 +43,147 @@ pub fn render_markdown(src: &str) -> String { opts.insert(Options::ENABLE_FOOTNOTES); let parser = Parser::new_ext(&protected, opts); let mut out = String::new(); - html::push_html(&mut out, parser); + if let Some((base, is_dir)) = repo { + let events = parser.map(|ev| rewrite_event(ev, base, is_dir)); + html::push_html(&mut out, events); + } else { + html::push_html(&mut out, parser); + } restore_math(&out, &slots) } +fn rewrite_event<'a>( + event: Event<'a>, + base: &MarkdownRepoBase<'_>, + is_dir: &dyn Fn(&str) -> bool, +) -> Event<'a> { + match event { + Event::Start(Tag::Link { + link_type, + dest_url, + title, + id, + }) => Event::Start(Tag::Link { + link_type, + dest_url: rewrite_repo_url(&dest_url, base, is_dir, false).into(), + title, + id, + }), + Event::Start(Tag::Image { + link_type, + dest_url, + title, + id, + }) => Event::Start(Tag::Image { + link_type, + dest_url: rewrite_repo_url(&dest_url, base, is_dir, true).into(), + title, + id, + }), + other => other, + } +} + +fn rewrite_repo_url( + url: &str, + base: &MarkdownRepoBase<'_>, + is_dir: &dyn Fn(&str) -> bool, + image: bool, +) -> String { + if !is_relative_repo_path(url) { + return url.to_string(); + } + + let (path_part, suffix) = split_url_suffix(url); + let resolved = resolve_repo_path(base.dir, path_part); + + if image { + if resolved.is_empty() { + return format!( + "/{}/{}/tree/{}{suffix}", + base.owner, base.repo, base.git_ref + ); + } + return format!( + "/{}/{}/raw/{}/{}{suffix}", + base.owner, base.repo, base.git_ref, resolved + ); + } + + if resolved.is_empty() { + return format!( + "/{}/{}/tree/{}{suffix}", + base.owner, base.repo, base.git_ref + ); + } + + let kind = if path_part.ends_with('/') || is_dir(&resolved) { + "tree" + } else { + "blob" + }; + format!( + "/{}/{}/{}/{}/{}{suffix}", + base.owner, base.repo, kind, base.git_ref, resolved + ) +} + +fn is_relative_repo_path(url: &str) -> bool { + if url.is_empty() || url.starts_with('#') { + return false; + } + if url.starts_with('/') || url.starts_with("//") { + return false; + } + if url.contains("://") { + return false; + } + let scheme = url.split_once(':').map(|(s, _)| s); + if let Some(s) = scheme { + // `mailto:`, `tel:`, etc. — but allow Windows-ish drive letters? skip. + if s.chars().all(|c| c.is_ascii_alphabetic()) && s.len() > 1 { + return false; + } + } + true +} + +fn split_url_suffix(url: &str) -> (&str, &str) { + let bytes = url.as_bytes(); + for (i, &b) in bytes.iter().enumerate() { + if b == b'?' || b == b'#' { + return (&url[..i], &url[i..]); + } + } + (url, "") +} + +/// Join `rel` onto `dir` with `.` / `..` normalization (POSIX-style). +fn resolve_repo_path(dir: &str, rel: &str) -> String { + let mut stack: Vec<&str> = dir + .split('/') + .filter(|s| !s.is_empty()) + .collect(); + for part in rel.split('/') { + match part { + "" | "." => {} + ".." => { + stack.pop(); + } + p => stack.push(p), + } + } + stack.join("/") +} + +/// Parent directory of a repo-relative file path (`""` for root files). +pub fn parent_dir(path: &str) -> &str { + match path.rsplit_once('/') { + Some((dir, _)) => dir, + None => "", + } +} + fn preprocess_math_fences(src: &str) -> String { let mut out = String::with_capacity(src.len()); let mut lines = src.lines().peekable(); @@ -206,4 +372,98 @@ mod tests { assert!(html.contains("$$"), "{html}"); assert!(html.contains("\\frac{a}{b}"), "{html}"); } + + #[test] + fn relative_link_to_docs_dir_uses_tree() { + let base = MarkdownRepoBase { + owner: "tirbofish", + repo: "kitgit", + git_ref: "main", + dir: "", + }; + let html = render_markdown_in_repo( + "see the [docs](docs) folder", + &base, + |p| p == "docs", + ); + assert!( + html.contains(r#"href="/tirbofish/kitgit/tree/main/docs""#), + "{html}" + ); + assert!(!html.contains(r#"href="docs""#), "{html}"); + } + + #[test] + fn relative_link_to_file_uses_blob() { + let base = MarkdownRepoBase { + owner: "tirbofish", + repo: "kitgit", + git_ref: "main", + dir: "", + }; + let html = render_markdown_in_repo( + "[guide](docs/production.md)", + &base, + |_| false, + ); + assert!( + html.contains(r#"href="/tirbofish/kitgit/blob/main/docs/production.md""#), + "{html}" + ); + } + + #[test] + fn relative_link_resolves_from_file_dir() { + let base = MarkdownRepoBase { + owner: "o", + repo: "r", + git_ref: "main", + dir: "docs", + }; + let html = render_markdown_in_repo("[x](./brand.md)", &base, |_| false); + assert!( + html.contains(r#"href="/o/r/blob/main/docs/brand.md""#), + "{html}" + ); + } + + #[test] + fn relative_image_uses_raw() { + let base = MarkdownRepoBase { + owner: "o", + repo: "r", + git_ref: "main", + dir: "", + }; + let html = render_markdown_in_repo("", &base, |_| false); + assert!( + html.contains(r#"src="/o/r/raw/main/static/logo.png""#), + "{html}" + ); + } + + #[test] + fn absolute_and_fragment_links_untouched() { + let base = MarkdownRepoBase { + owner: "o", + repo: "r", + git_ref: "main", + dir: "", + }; + let html = render_markdown_in_repo( + "[a](https://example.com) [b](#section) [c](/already/absolute)", + &base, + |_| false, + ); + assert!(html.contains("href=\"https://example.com\""), "{html}"); + assert!(html.contains("href=\"#section\""), "{html}"); + assert!(html.contains("href=\"/already/absolute\""), "{html}"); + } + + #[test] + fn parent_dir_helpers() { + assert_eq!(parent_dir("README.md"), ""); + assert_eq!(parent_dir("docs/production.md"), "docs"); + assert_eq!(parent_dir("a/b/c.md"), "a/b"); + } } @@ -6,7 +6,7 @@ use data_encoding::BASE32_NOPAD; use hmac::{Hmac, Mac}; use qrcode::render::svg; use qrcode::QrCode; -use rand::RngCore; +use rand::RngExt; use sha1::Sha1; use sha2::{Digest, Sha256}; use std::time::{SystemTime, UNIX_EPOCH}; @@ -20,7 +20,7 @@ const RECOVERY_CODE_COUNT: usize = 8; pub fn generate_totp_secret() -> String { let mut buf = [0u8; 20]; - rand::thread_rng().fill_bytes(&mut buf); + rand::rng().fill(&mut buf); BASE32_NOPAD.encode(&buf) } @@ -104,10 +104,10 @@ pub fn verify_totp(secret_base32: &str, code: &str) -> bool { pub fn generate_recovery_codes() -> Vec<String> { let mut out = Vec::with_capacity(RECOVERY_CODE_COUNT); - let mut rng = rand::thread_rng(); + let mut rng = rand::rng(); for _ in 0..RECOVERY_CODE_COUNT { let mut buf = [0u8; 5]; - rng.fill_bytes(&mut buf); + rng.fill(&mut buf); let hex = hex::encode(buf); out.push(format!("{}-{}", &hex[..5], &hex[5..])); } @@ -7,7 +7,7 @@ use crate::db::queries; use crate::git; use crate::git::ssh::fingerprint_ssh_pubkey; use crate::highlight::highlight; -use crate::markdown::render_markdown; +use crate::markdown::{MarkdownRepoBase, parent_dir, render_markdown, render_markdown_in_repo}; use crate::state::AppState; use crate::web::templates::*; use axum::extract::{Form, Multipart, Path, Query, State}; @@ -265,9 +265,23 @@ fn html_escape(s: &str) -> String { .collect() } -fn readme_to_html(name: &str, src: &str) -> String { +fn readme_to_html( + name: &str, + src: &str, + owner: &str, + repo: &str, + git_ref: &str, + dir: &str, + grepo: &git2::Repository, +) -> String { if name.ends_with(".md") || name.ends_with(".MD") { - render_markdown(src) + let base = MarkdownRepoBase { + owner, + repo, + git_ref, + dir, + }; + render_markdown_in_repo(src, &base, |path| git::path_is_dir(grepo, git_ref, path)) } else { format!("<pre>{}</pre>", html_escape(src)) } @@ -600,10 +614,14 @@ fn clone_urls(state: &AppState, owner: &str, repo: &str) -> (String, String) { .ok() .and_then(|u| u.host_str().map(|h| h.to_string())) .unwrap_or_else(|| "localhost".into()); - let port = state.config.ssh_bind.port(); - // Always use ssh:// form. `git@host:2222/path` is parsed as host=host path=2222/path - // on port 22 — which hits the system sshd and asks for a password. - let ssh = format!("ssh://git@{host}:{port}/{owner}/{repo}.git"); + let port = state.config.ssh_advertise_port(); + // Port 22: GitHub-style `git@host:owner/repo.git` (default SSH port). + // Other ports: ssh:// form — `git@host:2222/path` is parsed as path `2222/path` on port 22. + let ssh = if port == 22 { + format!("git@{host}:{owner}/{repo}.git") + } else { + format!("ssh://git@{host}:{port}/{owner}/{repo}.git") + }; (http, ssh) } @@ -1507,7 +1525,15 @@ pub async fn repo_home( }) .collect(); if let Ok(Some((name, src))) = git::find_readme(g, ¤t_branch, "") { - readme_html = Some(readme_to_html(&name, &src)); + readme_html = Some(readme_to_html( + &name, + &src, + &owner, + &repo, + ¤t_branch, + "", + g, + )); } if languages.as_object().map(|o| o.is_empty()).unwrap_or(true) { if let Ok(files) = git::walk_files(g, ¤t_branch) { @@ -1590,7 +1616,15 @@ pub async fn repo_tree( }) .collect(); let readme_html = match git::find_readme(&grepo, &branch, &path) { - Ok(Some((name, src))) => Some(readme_to_html(&name, &src)), + Ok(Some((name, src))) => Some(readme_to_html( + &name, + &src, + &owner, + &repo, + &branch, + &path, + &grepo, + )), _ => None, }; let branches = git::list_branches(&grepo).unwrap_or_default(); @@ -1634,7 +1668,16 @@ pub async fn repo_blob( } else { let text = String::from_utf8_lossy(&data); if path.ends_with(".md") || path.ends_with(".MD") { - (Some(render_markdown(&text)), true) + let base = MarkdownRepoBase { + owner: &owner, + repo: &repo, + git_ref: &branch, + dir: parent_dir(&path), + }; + let html = render_markdown_in_repo(&text, &base, |p| { + git::path_is_dir(&grepo, &branch, p) + }); + (Some(html), true) } else { (Some(highlight(&path, &text)), false) } @@ -0,0 +1,28 @@ +Hi {user}! You have been authenticated. Take a break, and read this poem... + +I heard a cough +as if a thief was there +outside my sleep +a sharp intake of air + +a fox in her fox-fur +stepping across +the grass in her black gloves +barked at my house + +just so abrupt and odd +the way she went +hungrily asking +in the heart's thick accent + +in such serious sleepless +trespass she came +a woman with a man's voice +but no name + +as if to say: it's midnight +and my life +is laid beneath my children +like gold leaf + +Alice Oswald, "Fox" from Falling Awake