mirror of
https://github.com/Pumpkin-MC/Pumpkin.git
synced 2026-08-30 20:14:23 +00:00
added encrytion
This commit is contained in:
372
Cargo.lock
generated
372
Cargo.lock
generated
@@ -8,6 +8,23 @@ version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
|
||||
|
||||
[[package]]
|
||||
name = "aes"
|
||||
version = "0.8.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"cipher",
|
||||
"cpufeatures",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anyhow"
|
||||
version = "1.0.86"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da"
|
||||
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
version = "1.3.0"
|
||||
@@ -20,6 +37,12 @@ version = "0.22.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
|
||||
|
||||
[[package]]
|
||||
name = "base64ct"
|
||||
version = "1.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b"
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "1.3.2"
|
||||
@@ -44,12 +67,37 @@ version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8f1fe948ff07f4bd06c30984e69f5b4899c516a3ef74f34df92a2df2ab535495"
|
||||
|
||||
[[package]]
|
||||
name = "bytes"
|
||||
version = "1.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a12916984aab3fa6e39d655a33e09c0071eb36d6ab3aea5c2d78551f1df6d952"
|
||||
|
||||
[[package]]
|
||||
name = "cfb8"
|
||||
version = "0.8.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "014c0a0e1ad0dae6a86c082db2f9bd7fe8c2c734227047d0d8b4d4a3a094a1e1"
|
||||
dependencies = [
|
||||
"cipher",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||
|
||||
[[package]]
|
||||
name = "cipher"
|
||||
version = "0.4.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad"
|
||||
dependencies = [
|
||||
"crypto-common",
|
||||
"inout",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "colored"
|
||||
version = "2.1.0"
|
||||
@@ -60,6 +108,21 @@ dependencies = [
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "const-oid"
|
||||
version = "0.9.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8"
|
||||
|
||||
[[package]]
|
||||
name = "cpufeatures"
|
||||
version = "0.2.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crc32fast"
|
||||
version = "1.4.2"
|
||||
@@ -84,6 +147,27 @@ version = "0.8.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "248e3bacc7dc6baa3b21e405ee045c3047101a49145e7e9eca583ab4c2ca5345"
|
||||
|
||||
[[package]]
|
||||
name = "crypto-common"
|
||||
version = "0.1.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3"
|
||||
dependencies = [
|
||||
"generic-array",
|
||||
"typenum",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "der"
|
||||
version = "0.7.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f55bf8e7b65898637379c1b74eb1551107c8294ed26d855ceb9fd1a09cfc9bc0"
|
||||
dependencies = [
|
||||
"const-oid",
|
||||
"pem-rfc7468",
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "deranged"
|
||||
version = "0.3.11"
|
||||
@@ -93,6 +177,16 @@ dependencies = [
|
||||
"powerfmt",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "digest"
|
||||
version = "0.10.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292"
|
||||
dependencies = [
|
||||
"const-oid",
|
||||
"crypto-common",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fdeflate"
|
||||
version = "0.3.4"
|
||||
@@ -112,6 +206,27 @@ dependencies = [
|
||||
"miniz_oxide",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "generic-array"
|
||||
version = "0.14.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a"
|
||||
dependencies = [
|
||||
"typenum",
|
||||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "getrandom"
|
||||
version = "0.2.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"wasi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hermit-abi"
|
||||
version = "0.3.9"
|
||||
@@ -130,6 +245,15 @@ dependencies = [
|
||||
"png",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "inout"
|
||||
version = "0.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5"
|
||||
dependencies = [
|
||||
"generic-array",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "1.0.11"
|
||||
@@ -141,6 +265,9 @@ name = "lazy_static"
|
||||
version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
|
||||
dependencies = [
|
||||
"spin",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
@@ -148,6 +275,12 @@ version = "0.2.155"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c"
|
||||
|
||||
[[package]]
|
||||
name = "libm"
|
||||
version = "0.2.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058"
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.4.21"
|
||||
@@ -177,12 +310,59 @@ dependencies = [
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-bigint"
|
||||
version = "0.4.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9"
|
||||
dependencies = [
|
||||
"num-integer",
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-bigint-dig"
|
||||
version = "0.8.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dc84195820f291c7697304f3cbdadd1cb7199c0efc917ff5eafd71225c136151"
|
||||
dependencies = [
|
||||
"byteorder",
|
||||
"lazy_static",
|
||||
"libm",
|
||||
"num-integer",
|
||||
"num-iter",
|
||||
"num-traits",
|
||||
"rand",
|
||||
"smallvec",
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-conv"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9"
|
||||
|
||||
[[package]]
|
||||
name = "num-integer"
|
||||
version = "0.1.46"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f"
|
||||
dependencies = [
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-iter"
|
||||
version = "0.1.45"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"num-integer",
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-traits"
|
||||
version = "0.2.19"
|
||||
@@ -190,6 +370,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"libm",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -201,6 +382,36 @@ dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pem-rfc7468"
|
||||
version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "88b39c9bfcfc231068454382784bb460aae594343fb030d46e9f50a645418412"
|
||||
dependencies = [
|
||||
"base64ct",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pkcs1"
|
||||
version = "0.7.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c8ffb9f10fa047879315e6625af03c164b16962a5368d724ed16323b68ace47f"
|
||||
dependencies = [
|
||||
"der",
|
||||
"pkcs8",
|
||||
"spki",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pkcs8"
|
||||
version = "0.10.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7"
|
||||
dependencies = [
|
||||
"der",
|
||||
"spki",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "png"
|
||||
version = "0.17.13"
|
||||
@@ -220,6 +431,12 @@ version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391"
|
||||
|
||||
[[package]]
|
||||
name = "ppv-lite86"
|
||||
version = "0.2.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.86"
|
||||
@@ -233,12 +450,20 @@ dependencies = [
|
||||
name = "pumpkin"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"aes",
|
||||
"anyhow",
|
||||
"base64",
|
||||
"byteorder",
|
||||
"bytes",
|
||||
"cfb8",
|
||||
"crossbeam-channel",
|
||||
"flate2",
|
||||
"image",
|
||||
"log",
|
||||
"mio",
|
||||
"rand",
|
||||
"rsa",
|
||||
"rsa-der",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"simple_logger",
|
||||
@@ -254,6 +479,65 @@ dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand"
|
||||
version = "0.8.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"rand_chacha",
|
||||
"rand_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_chacha"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
|
||||
dependencies = [
|
||||
"ppv-lite86",
|
||||
"rand_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_core"
|
||||
version = "0.6.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
|
||||
dependencies = [
|
||||
"getrandom",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rsa"
|
||||
version = "0.9.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5d0e5124fcb30e76a7e79bfee683a2746db83784b86289f6251b54b7950a0dfc"
|
||||
dependencies = [
|
||||
"const-oid",
|
||||
"digest",
|
||||
"num-bigint-dig",
|
||||
"num-integer",
|
||||
"num-traits",
|
||||
"pkcs1",
|
||||
"pkcs8",
|
||||
"rand_core",
|
||||
"signature",
|
||||
"spki",
|
||||
"subtle",
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rsa-der"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a19473b2de3164677ff38e4309c42448ba8d0fe5ad5fa722e7d278f991859aa6"
|
||||
dependencies = [
|
||||
"simple_asn1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ryu"
|
||||
version = "1.0.18"
|
||||
@@ -291,12 +575,34 @@ dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "signature"
|
||||
version = "2.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de"
|
||||
dependencies = [
|
||||
"digest",
|
||||
"rand_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "simd-adler32"
|
||||
version = "0.3.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe"
|
||||
|
||||
[[package]]
|
||||
name = "simple_asn1"
|
||||
version = "0.6.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "adc4e5204eb1910f40f9cfa375f6f05b68c3abac4b6fd879c8ff5e7ae8a0a085"
|
||||
dependencies = [
|
||||
"num-bigint",
|
||||
"num-traits",
|
||||
"thiserror",
|
||||
"time",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "simple_logger"
|
||||
version = "5.0.0"
|
||||
@@ -309,6 +615,34 @@ dependencies = [
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "smallvec"
|
||||
version = "1.13.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67"
|
||||
|
||||
[[package]]
|
||||
name = "spin"
|
||||
version = "0.9.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67"
|
||||
|
||||
[[package]]
|
||||
name = "spki"
|
||||
version = "0.7.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d"
|
||||
dependencies = [
|
||||
"base64ct",
|
||||
"der",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "subtle"
|
||||
version = "2.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292"
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.72"
|
||||
@@ -320,6 +654,26 @@ dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "1.0.63"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c0342370b38b6a11b6cc11d6a805569958d54cfa061a29969c3b5ce2ea405724"
|
||||
dependencies = [
|
||||
"thiserror-impl",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror-impl"
|
||||
version = "1.0.63"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "time"
|
||||
version = "0.3.36"
|
||||
@@ -353,6 +707,12 @@ dependencies = [
|
||||
"time-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "typenum"
|
||||
version = "1.17.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.12"
|
||||
@@ -365,6 +725,12 @@ version = "1.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "81dfa00651efa65069b0b6b651f4aaa31ba9e3c3ce0137aaad053604ee7e0314"
|
||||
|
||||
[[package]]
|
||||
name = "version_check"
|
||||
version = "0.9.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
|
||||
|
||||
[[package]]
|
||||
name = "wasi"
|
||||
version = "0.11.0+wasi-snapshot-preview1"
|
||||
@@ -509,3 +875,9 @@ name = "windows_x86_64_msvc"
|
||||
version = "0.52.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0"
|
||||
|
||||
[[package]]
|
||||
name = "zeroize"
|
||||
version = "1.8.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde"
|
||||
|
||||
@@ -8,6 +8,18 @@ edition = "2021"
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
serde_json = "1.0"
|
||||
|
||||
rand = "0.8.5"
|
||||
|
||||
rsa = "0.9.6"
|
||||
rsa-der = "0.3.0"
|
||||
|
||||
aes = "0.8.4"
|
||||
cfb8 = "0.8.1"
|
||||
flate2 = "1.0.30"
|
||||
bytes = "1.6.1"
|
||||
|
||||
anyhow = "1.0.86"
|
||||
|
||||
base64 = "0.22.1"
|
||||
image = { version = "0.25", default-features = false, features = ["png"]}
|
||||
|
||||
|
||||
@@ -1,11 +1,15 @@
|
||||
|
||||
|
||||
use crate::protocol::{
|
||||
client::status::{CPingResponse, CStatusResponse},
|
||||
client::{
|
||||
login::{CEncryptionRequest, CLoginSuccess},
|
||||
status::{CPingResponse, CStatusResponse},
|
||||
},
|
||||
server::{
|
||||
handshake::SHandShake,
|
||||
login::{SEncryptionResponse, SLoginAcknowledged, SLoginPluginResponse, SLoginStart},
|
||||
status::{SPingRequest, SStatusRequest},
|
||||
},
|
||||
ConnectionState,
|
||||
};
|
||||
|
||||
use super::Client;
|
||||
@@ -16,6 +20,11 @@ pub trait ClientPacketProcessor {
|
||||
// Status
|
||||
fn handle_status_request(&mut self, status_request: SStatusRequest);
|
||||
fn handle_ping_request(&mut self, ping_request: SPingRequest);
|
||||
// Login
|
||||
fn handle_login_start(&mut self, login_start: SLoginStart);
|
||||
fn handle_encryption_response(&mut self, encryption_response: SEncryptionResponse);
|
||||
fn handle_plugin_response(&mut self, plugin_response: SLoginPluginResponse);
|
||||
fn handle_login_acknowledged(&mut self, login_acknowledged: SLoginAcknowledged);
|
||||
}
|
||||
|
||||
impl ClientPacketProcessor for Client {
|
||||
@@ -38,4 +47,42 @@ impl ClientPacketProcessor for Client {
|
||||
self.send_packet(CPingResponse::new(ping_request.payload));
|
||||
self.close();
|
||||
}
|
||||
|
||||
fn handle_login_start(&mut self, login_start: SLoginStart) {
|
||||
dbg!("login start");
|
||||
self.name = Some(login_start.name);
|
||||
self.uuid = Some(login_start.uuid);
|
||||
let verify_token: [u8; 4] = rand::random();
|
||||
let public_key_der = &self.server.to_owned().public_key_der;
|
||||
let packet = CEncryptionRequest::new(
|
||||
"".into(),
|
||||
public_key_der.len() as i32,
|
||||
public_key_der,
|
||||
verify_token.len() as i32,
|
||||
&verify_token,
|
||||
false, // TODO
|
||||
);
|
||||
self.send_packet(packet);
|
||||
}
|
||||
|
||||
fn handle_encryption_response(&mut self, encryption_response: SEncryptionResponse) {
|
||||
dbg!("encryption response");
|
||||
// should be impossible
|
||||
if self.uuid.is_none() || self.name.is_none() {
|
||||
self.kick("UUID or Name is none".into());
|
||||
return;
|
||||
}
|
||||
self.enable_encryption(encryption_response.shared_secret)
|
||||
.unwrap();
|
||||
|
||||
let packet = CLoginSuccess::new(self.uuid.unwrap(), self.name.clone().unwrap(), 0, false);
|
||||
self.send_packet(packet);
|
||||
}
|
||||
|
||||
fn handle_plugin_response(&mut self, plugin_response: SLoginPluginResponse) {}
|
||||
|
||||
fn handle_login_acknowledged(&mut self, login_acknowledged: SLoginAcknowledged) {
|
||||
self.connection_state = ConnectionState::Config;
|
||||
dbg!("login achnowlaged");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,8 +6,10 @@ use std::{
|
||||
|
||||
use crate::{
|
||||
protocol::{
|
||||
client::login::CLoginDisconnect,
|
||||
server::{
|
||||
handshake::SHandShake,
|
||||
login::{SEncryptionResponse, SLoginAcknowledged, SLoginPluginResponse, SLoginStart},
|
||||
status::{SPingRequest, SStatusRequest},
|
||||
},
|
||||
ClientPacket, RawPacket,
|
||||
@@ -15,30 +17,48 @@ use crate::{
|
||||
server::Server,
|
||||
};
|
||||
|
||||
use crate::protocol::{bytebuf::buffer::ByteBuffer, ConnectionState};
|
||||
use crate::protocol::ConnectionState;
|
||||
use anyhow::Context;
|
||||
use mio::{event::Event, net::TcpStream, Registry};
|
||||
use packet_decoder::PacketDecoder;
|
||||
use packet_encoder::PacketEncoder;
|
||||
use rsa::Pkcs1v15Encrypt;
|
||||
use std::io::Read;
|
||||
|
||||
mod client_packet;
|
||||
pub mod player;
|
||||
|
||||
mod packet_decoder;
|
||||
mod packet_encoder;
|
||||
|
||||
use client_packet::ClientPacketProcessor;
|
||||
|
||||
pub const MAX_PACKET_SIZE: i32 = 2097152;
|
||||
|
||||
pub struct Client {
|
||||
pub name: Option<String>,
|
||||
pub uuid: Option<uuid::Uuid>,
|
||||
pub server: Rc<Server>,
|
||||
pub connection_state: ConnectionState,
|
||||
pub encrytion: bool,
|
||||
pub closed: bool,
|
||||
pub connection: TcpStream,
|
||||
// Packets coming from the client -> server
|
||||
client_packets_queue: VecDeque<RawPacket>,
|
||||
enc: PacketEncoder,
|
||||
dec: PacketDecoder,
|
||||
pub client_packets_queue: VecDeque<RawPacket>,
|
||||
}
|
||||
|
||||
impl Client {
|
||||
pub fn new(server: Rc<Server>, connection: TcpStream) -> Self {
|
||||
Self {
|
||||
name: None,
|
||||
uuid: None,
|
||||
server,
|
||||
connection_state: ConnectionState::HandShake,
|
||||
connection,
|
||||
enc: PacketEncoder::default(),
|
||||
dec: PacketDecoder::default(),
|
||||
encrytion: true,
|
||||
closed: false,
|
||||
client_packets_queue: VecDeque::new(),
|
||||
}
|
||||
@@ -48,26 +68,26 @@ impl Client {
|
||||
self.client_packets_queue.push_back(packet);
|
||||
}
|
||||
|
||||
pub fn send_packet<P: ClientPacket>(&mut self, packet: P) {
|
||||
dbg!("WRITING");
|
||||
let mut packet_buf = ByteBuffer::new();
|
||||
packet.write(&mut packet_buf);
|
||||
// Creating empty packet's buffer
|
||||
let mut packet = ByteBuffer::new();
|
||||
// Creating length's bytes buffer and fill it as VarInt
|
||||
let mut len_bytes = ByteBuffer::new();
|
||||
len_bytes.write_var_int(P::PACKET_ID);
|
||||
// Writing full packet's length(content + length's bytes)
|
||||
packet.write_var_int((packet_buf.len() + len_bytes.len()) as i32);
|
||||
// Writing length bytes
|
||||
packet.write_all(len_bytes.as_bytes()).unwrap();
|
||||
// Drop(Free) length bytes buffer
|
||||
drop(len_bytes);
|
||||
// Writing some packet's content
|
||||
packet.write_all(packet_buf.as_bytes()).unwrap();
|
||||
pub fn enable_encryption(&mut self, shared_secret: Vec<u8>) -> anyhow::Result<()> {
|
||||
self.encrytion = true;
|
||||
let shared_secret = self
|
||||
.server
|
||||
.private_key
|
||||
.decrypt(Pkcs1v15Encrypt, &shared_secret)
|
||||
.context("failed to decrypt shared secret")?;
|
||||
let crypt_key: [u8; 16] = shared_secret
|
||||
.as_slice()
|
||||
.try_into()
|
||||
.context("shared secret has the wrong length")?;
|
||||
self.dec.enable_encryption(&crypt_key);
|
||||
self.enc.enable_encryption(&crypt_key);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
self.connection.write_all(packet.as_bytes()).unwrap();
|
||||
self.connection.flush().unwrap(); // todo do not flush every time
|
||||
pub fn send_packet<P: ClientPacket>(&mut self, packet: P) {
|
||||
dbg!("sending packet");
|
||||
self.enc.append_packet(packet).unwrap();
|
||||
self.connection.write_all(&self.enc.take()).unwrap();
|
||||
}
|
||||
|
||||
pub fn procress_packets(&mut self) {
|
||||
@@ -100,16 +120,28 @@ impl Client {
|
||||
packet.id
|
||||
),
|
||||
},
|
||||
crate::protocol::ConnectionState::Login => match packet.id {
|
||||
SLoginStart::PACKET_ID => self.handle_login_start(SLoginStart::read(bytebuf)),
|
||||
SEncryptionResponse::PACKET_ID => {
|
||||
self.handle_encryption_response(SEncryptionResponse::read(bytebuf))
|
||||
}
|
||||
SLoginPluginResponse::PACKET_ID => {
|
||||
self.handle_plugin_response(SLoginPluginResponse::read(bytebuf))
|
||||
}
|
||||
SLoginAcknowledged::PACKET_ID => {
|
||||
self.handle_login_acknowledged(SLoginAcknowledged::read(bytebuf))
|
||||
}
|
||||
_ => log::error!(
|
||||
"Failed to handle packet id {} while in Login state",
|
||||
packet.id
|
||||
),
|
||||
},
|
||||
_ => log::error!("Invalid Connection state {:?}", self.connection_state),
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns `true` if the connection is done.
|
||||
pub fn handle_connection_event(
|
||||
&mut self,
|
||||
_registry: &Registry,
|
||||
event: &Event,
|
||||
) -> io::Result<()> {
|
||||
pub fn poll(&mut self, _registry: &Registry, event: &Event) -> anyhow::Result<()> {
|
||||
if event.is_readable() {
|
||||
let mut received_data = vec![0; 4096];
|
||||
let mut bytes_read = 0;
|
||||
@@ -133,33 +165,32 @@ impl Client {
|
||||
Err(ref err) if would_block(err) => break,
|
||||
Err(ref err) if interrupted(err) => continue,
|
||||
// Other errors we'll consider fatal.
|
||||
Err(err) => return Err(err),
|
||||
Err(err) => return anyhow::bail!(err),
|
||||
}
|
||||
}
|
||||
|
||||
if bytes_read != 0 {
|
||||
let received_data = &received_data[..bytes_read];
|
||||
let mut bytebuf = ByteBuffer::from_bytes(received_data);
|
||||
let packet = RawPacket {
|
||||
len: bytebuf.read_var_int().unwrap(),
|
||||
id: bytebuf.read_var_int().unwrap(),
|
||||
bytebuf,
|
||||
};
|
||||
if packet.len + 1 != received_data.len() as i32 {
|
||||
log::error!(
|
||||
"Packet length does not match Data length: {} {}",
|
||||
packet.len,
|
||||
received_data.len()
|
||||
);
|
||||
self.dec.reserve(4096);
|
||||
self.dec.queue_slice(&received_data[..bytes_read]);
|
||||
if let Some(packet) = self.dec.decode()? {
|
||||
self.add_packet(packet);
|
||||
self.procress_packets();
|
||||
}
|
||||
dbg!(&packet);
|
||||
self.add_packet(packet);
|
||||
self.procress_packets();
|
||||
self.dec.clear();
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn kick(&mut self, reason: String) {
|
||||
// Todo
|
||||
if self.connection_state == ConnectionState::Login {
|
||||
self.send_packet(CLoginDisconnect::new(reason));
|
||||
}
|
||||
self.close()
|
||||
}
|
||||
|
||||
// Kick before when needed
|
||||
pub fn close(&mut self) {
|
||||
self.closed = true;
|
||||
}
|
||||
|
||||
112
pumpkin/src/client/packet_decoder.rs
Normal file
112
pumpkin/src/client/packet_decoder.rs
Normal file
@@ -0,0 +1,112 @@
|
||||
|
||||
use aes::cipher::{generic_array::GenericArray, BlockDecryptMut, BlockSizeUser, KeyIvInit};
|
||||
use anyhow::{bail, ensure, Context};
|
||||
use bytes::{Buf, BytesMut};
|
||||
|
||||
use crate::{
|
||||
client::MAX_PACKET_SIZE,
|
||||
protocol::{bytebuf::buffer::ByteBuffer, RawPacket, VarInt32, VarIntDecodeError},
|
||||
};
|
||||
|
||||
type Cipher = cfb8::Decryptor<aes::Aes128>;
|
||||
|
||||
// Decoder: Client -> Server
|
||||
#[derive(Default)]
|
||||
pub struct PacketDecoder {
|
||||
buf: BytesMut,
|
||||
|
||||
cipher: Option<Cipher>,
|
||||
}
|
||||
|
||||
impl PacketDecoder {
|
||||
pub fn decode(&mut self) -> anyhow::Result<Option<RawPacket>> {
|
||||
let mut r = &self.buf[..];
|
||||
|
||||
let packet_len = match VarInt32::decode_partial(&mut r) {
|
||||
Ok(len) => len,
|
||||
Err(VarIntDecodeError::Incomplete) => return Ok(None),
|
||||
Err(VarIntDecodeError::TooLarge) => bail!("malformed packet length VarInt"),
|
||||
};
|
||||
|
||||
ensure!(
|
||||
(0..=MAX_PACKET_SIZE).contains(&packet_len),
|
||||
"packet length of {packet_len} is out of bounds"
|
||||
);
|
||||
|
||||
if r.len() < packet_len as usize {
|
||||
// Not enough data arrived yet.
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
let packet_len_len = VarInt32(packet_len).written_size();
|
||||
|
||||
let mut data;
|
||||
|
||||
// no compression
|
||||
|
||||
self.buf.advance(packet_len_len);
|
||||
data = self.buf.split_to(packet_len as usize);
|
||||
|
||||
r = &data[..];
|
||||
let packet_id = VarInt32::decode(&mut r)
|
||||
.context("failed to decode packet ID")?
|
||||
.0;
|
||||
|
||||
data.advance(data.len() - r.len());
|
||||
dbg!(packet_id);
|
||||
Ok(Some(RawPacket {
|
||||
len: packet_len,
|
||||
id: packet_id,
|
||||
bytebuf: ByteBuffer::from_bytes(&data),
|
||||
}))
|
||||
}
|
||||
|
||||
pub fn enable_encryption(&mut self, key: &[u8; 16]) {
|
||||
assert!(self.cipher.is_none(), "encryption is already enabled");
|
||||
|
||||
let mut cipher = Cipher::new_from_slices(key, key).expect("invalid key");
|
||||
|
||||
// Don't forget to decrypt the data we already have.
|
||||
Self::decrypt_bytes(&mut cipher, &mut self.buf);
|
||||
|
||||
self.cipher = Some(cipher);
|
||||
}
|
||||
|
||||
fn decrypt_bytes(cipher: &mut Cipher, bytes: &mut [u8]) {
|
||||
for chunk in bytes.chunks_mut(Cipher::block_size()) {
|
||||
let gen_arr = GenericArray::from_mut_slice(chunk);
|
||||
cipher.decrypt_block_mut(gen_arr);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn queue_bytes(&mut self, mut bytes: BytesMut) {
|
||||
if let Some(cipher) = &mut self.cipher {
|
||||
Self::decrypt_bytes(cipher, &mut bytes);
|
||||
}
|
||||
|
||||
self.buf.unsplit(bytes);
|
||||
}
|
||||
|
||||
pub fn queue_slice(&mut self, bytes: &[u8]) {
|
||||
let len = self.buf.len();
|
||||
|
||||
self.buf.extend_from_slice(bytes);
|
||||
|
||||
if let Some(cipher) = &mut self.cipher {
|
||||
let slice = &mut self.buf[len..];
|
||||
Self::decrypt_bytes(cipher, slice);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn take_capacity(&mut self) -> BytesMut {
|
||||
self.buf.split_off(self.buf.len())
|
||||
}
|
||||
|
||||
pub fn clear(&mut self) {
|
||||
self.buf.clear()
|
||||
}
|
||||
|
||||
pub fn reserve(&mut self, additional: usize) {
|
||||
self.buf.reserve(additional);
|
||||
}
|
||||
}
|
||||
74
pumpkin/src/client/packet_encoder.rs
Normal file
74
pumpkin/src/client/packet_encoder.rs
Normal file
@@ -0,0 +1,74 @@
|
||||
use std::io::Write;
|
||||
|
||||
use aes::cipher::{generic_array::GenericArray, BlockEncryptMut, BlockSizeUser, KeyIvInit};
|
||||
use anyhow::{ensure, Context};
|
||||
use bytes::{BufMut, BytesMut};
|
||||
use rsa::pkcs8::der::Encode;
|
||||
|
||||
use crate::{
|
||||
client::MAX_PACKET_SIZE,
|
||||
protocol::{bytebuf::buffer::ByteBuffer, ClientPacket, VarInt32},
|
||||
};
|
||||
|
||||
type Cipher = cfb8::Encryptor<aes::Aes128>;
|
||||
|
||||
// Encoder: Server -> Client
|
||||
#[derive(Default)]
|
||||
pub struct PacketEncoder {
|
||||
buf: BytesMut,
|
||||
|
||||
cipher: Option<Cipher>,
|
||||
}
|
||||
|
||||
impl PacketEncoder {
|
||||
pub fn append_packet<P: ClientPacket>(&mut self, packet: P) -> anyhow::Result<()> {
|
||||
let start_len = self.buf.len();
|
||||
|
||||
let mut writer = (&mut self.buf).writer();
|
||||
|
||||
let mut packet_buf = ByteBuffer::new();
|
||||
VarInt32(P::PACKET_ID)
|
||||
.encode(&mut writer)
|
||||
.context("failed to encode packet ID")?;
|
||||
packet.write(&mut packet_buf);
|
||||
|
||||
writer.write(packet_buf.as_bytes()).unwrap();
|
||||
|
||||
let data_len = self.buf.len() - start_len;
|
||||
|
||||
if false { // compression
|
||||
}
|
||||
let packet_len = data_len;
|
||||
|
||||
ensure!(
|
||||
packet_len <= MAX_PACKET_SIZE as usize,
|
||||
"packet exceeds maximum length"
|
||||
);
|
||||
|
||||
let packet_len_size = VarInt32(packet_len as i32).written_size();
|
||||
|
||||
self.buf.put_bytes(0, packet_len_size);
|
||||
self.buf
|
||||
.copy_within(start_len..start_len + data_len, start_len + packet_len_size);
|
||||
|
||||
let front = &mut self.buf[start_len..];
|
||||
VarInt32(packet_len as i32).encode(front)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn enable_encryption(&mut self, key: &[u8; 16]) {
|
||||
assert!(self.cipher.is_none(), "encryption is already enabled");
|
||||
self.cipher = Some(Cipher::new_from_slices(key, key).expect("invalid key"));
|
||||
}
|
||||
|
||||
pub fn take(&mut self) -> BytesMut {
|
||||
if let Some(cipher) = &mut self.cipher {
|
||||
for chunk in self.buf.chunks_mut(Cipher::block_size()) {
|
||||
let gen_arr = GenericArray::from_mut_slice(chunk);
|
||||
cipher.encrypt_block_mut(gen_arr);
|
||||
}
|
||||
}
|
||||
|
||||
self.buf.split()
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,5 @@
|
||||
#![feature(read_buf)]
|
||||
|
||||
use mio::net::TcpListener;
|
||||
use mio::{Events, Interest, Poll, Token};
|
||||
use std::collections::HashMap;
|
||||
@@ -9,6 +11,7 @@ const SERVER: Token = Token(0);
|
||||
pub mod client;
|
||||
pub mod protocol;
|
||||
pub mod server;
|
||||
pub mod util;
|
||||
|
||||
#[cfg(not(target_os = "wasi"))]
|
||||
fn main() -> io::Result<()> {
|
||||
@@ -37,8 +40,7 @@ fn main() -> io::Result<()> {
|
||||
// Unique token for each incoming connection.
|
||||
let mut unique_token = Token(SERVER.0 + 1);
|
||||
|
||||
log::info!("You can connect to the server using `nc`:");
|
||||
log::info!(" $ nc 127.0.0.1 9000");
|
||||
log::info!("You now can connect to the server");
|
||||
|
||||
let server = Rc::new(Server::new());
|
||||
|
||||
@@ -85,7 +87,7 @@ fn main() -> io::Result<()> {
|
||||
token => {
|
||||
// Maybe received an event for a TCP connection.
|
||||
let done = if let Some(client) = connections.get_mut(&token) {
|
||||
client.handle_connection_event(poll.registry(), event)?;
|
||||
client.poll(poll.registry(), event).unwrap();
|
||||
client.closed
|
||||
} else {
|
||||
// Sporadic events happen, we can safely ignore them.
|
||||
|
||||
@@ -219,6 +219,33 @@ impl ByteBuffer {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn write_bool(&mut self, v: bool) {
|
||||
if v {
|
||||
self.write_u8(1);
|
||||
} else {
|
||||
self.write_u8(0);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn write_bytes_len(&mut self, bytes: &[u8], max_len: usize) {
|
||||
self.flush_bits();
|
||||
|
||||
let size = bytes.len() + self.wpos;
|
||||
if size > max_len {
|
||||
eprintln!("Write: size > max size");
|
||||
return;
|
||||
}
|
||||
|
||||
if size > self.data.len() {
|
||||
self.resize(size);
|
||||
}
|
||||
|
||||
for v in bytes {
|
||||
self.data[self.wpos] = *v;
|
||||
self.wpos += 1;
|
||||
}
|
||||
}
|
||||
|
||||
/// Append a byte (8 bits value) to the buffer
|
||||
/// _Note_: This method resets the read and write cursor for bitwise reading.
|
||||
///
|
||||
@@ -388,8 +415,12 @@ impl ByteBuffer {
|
||||
/// buffer.write_string("Hello")
|
||||
/// ```
|
||||
pub fn write_string(&mut self, val: &str) {
|
||||
self.write_string_len(val, 32767)
|
||||
}
|
||||
|
||||
pub fn write_string_len(&mut self, val: &str, max_len: usize) {
|
||||
self.write_var_int(val.len() as VarInt);
|
||||
self.write_bytes(val.as_bytes());
|
||||
self.write_bytes_len(val.as_bytes(), max_len);
|
||||
}
|
||||
|
||||
// Read operations
|
||||
@@ -435,6 +466,10 @@ impl ByteBuffer {
|
||||
Ok(self.data[pos])
|
||||
}
|
||||
|
||||
pub fn read_bool(&mut self) -> Result<bool> {
|
||||
Ok(self.read_u8()? != 0)
|
||||
}
|
||||
|
||||
/// Same as `read_u8()` but for signed values
|
||||
pub fn read_i8(&mut self) -> Result<i8> {
|
||||
Ok(self.read_u8()? as i8)
|
||||
@@ -494,6 +529,25 @@ impl ByteBuffer {
|
||||
read_number!(self, read_u64, 8)
|
||||
}
|
||||
|
||||
/// Reads a boolean. If true, the closure is called, and the returned value is
|
||||
/// wrapped in Some. Otherwise, this returns None.
|
||||
pub fn read_option<T>(&mut self, val: impl FnOnce(&mut ByteBuffer) -> T) -> Result<Option<T>> {
|
||||
if self.read_bool()? {
|
||||
Ok(Some(val(self)))
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
/// Writes `true` if the option is Some, or `false` if None. If the option is
|
||||
/// some, then it also calls the `write` closure.
|
||||
pub fn write_option<T>(&mut self, val: &Option<T>, write: impl FnOnce(&mut ByteBuffer, &T)) {
|
||||
self.write_bool(val.is_some());
|
||||
match val {
|
||||
Some(v) => write(self, v),
|
||||
None => {}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn read_var_int(&mut self) -> Result<VarInt> {
|
||||
let mut value: i32 = 0;
|
||||
let mut position: i32 = 0;
|
||||
@@ -564,13 +618,42 @@ impl ByteBuffer {
|
||||
/// that must be encoded as UTF8.
|
||||
/// _Note_: This method resets the read and write cursor for bitwise reading.
|
||||
pub fn read_string(&mut self) -> Result<String> {
|
||||
self.read_string_len(32767)
|
||||
}
|
||||
|
||||
pub fn read_string_len(&mut self, max_size: usize) -> Result<String> {
|
||||
let size = self.read_var_int()?;
|
||||
match String::from_utf8(self.read_bytes(size as usize)?) {
|
||||
if size as usize > max_size {
|
||||
return Err(Error::new(
|
||||
ErrorKind::InvalidData,
|
||||
"String length is bigger than max size",
|
||||
));
|
||||
}
|
||||
let data = self.read_bytes(size as usize)?;
|
||||
if data.len() > max_size {
|
||||
return Err(Error::new(
|
||||
ErrorKind::InvalidData,
|
||||
"String is bigger than max size",
|
||||
));
|
||||
}
|
||||
match String::from_utf8(data) {
|
||||
Ok(string_result) => Ok(string_result),
|
||||
Err(e) => Err(Error::new(ErrorKind::InvalidData, e)),
|
||||
}
|
||||
}
|
||||
|
||||
/// Reads 16 bytes from the buffer, and returns that as a big endian UUID.
|
||||
pub fn read_uuid(&mut self) -> Result<uuid::Uuid> {
|
||||
let mut bytes = [0u8; 16];
|
||||
self.read_exact(&mut bytes)?;
|
||||
uuid::Uuid::from_slice(&bytes).map_err(|e| Error::new(ErrorKind::InvalidData, e))
|
||||
}
|
||||
|
||||
/// This writes a UUID into the buffer (in big endian format).
|
||||
pub fn write_uuid(&mut self, v: uuid::Uuid) {
|
||||
self.write_bytes(v.as_bytes());
|
||||
}
|
||||
|
||||
// Other
|
||||
|
||||
/// Dump the byte buffer to a string.
|
||||
|
||||
122
pumpkin/src/protocol/client/login/mod.rs
Normal file
122
pumpkin/src/protocol/client/login/mod.rs
Normal file
@@ -0,0 +1,122 @@
|
||||
use crate::protocol::{bytebuf::buffer::ByteBuffer, ClientPacket, VarInt};
|
||||
|
||||
pub struct CLoginDisconnect {
|
||||
reason: String,
|
||||
}
|
||||
|
||||
impl CLoginDisconnect {
|
||||
pub fn new(reason: String) -> Self {
|
||||
Self { reason }
|
||||
}
|
||||
}
|
||||
|
||||
impl ClientPacket for CLoginDisconnect {
|
||||
const PACKET_ID: VarInt = 0;
|
||||
|
||||
fn write(&self, bytebuf: &mut ByteBuffer) {
|
||||
bytebuf.write_string(&serde_json::to_string_pretty(&self.reason).unwrap());
|
||||
}
|
||||
}
|
||||
|
||||
pub struct CEncryptionRequest<'a> {
|
||||
server_id: String, // 20
|
||||
public_key_length: VarInt,
|
||||
public_key: &'a [u8],
|
||||
verify_token_length: VarInt,
|
||||
verify_token: &'a [u8],
|
||||
should_authenticate: bool,
|
||||
}
|
||||
|
||||
impl<'a> CEncryptionRequest<'a> {
|
||||
pub fn new(
|
||||
server_id: String,
|
||||
public_key_length: VarInt,
|
||||
public_key: &'a [u8],
|
||||
verify_token_length: VarInt,
|
||||
verify_token: &'a [u8],
|
||||
should_authenticate: bool,
|
||||
) -> Self {
|
||||
Self {
|
||||
server_id,
|
||||
public_key_length,
|
||||
public_key,
|
||||
verify_token_length,
|
||||
verify_token,
|
||||
should_authenticate,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> ClientPacket for CEncryptionRequest<'a> {
|
||||
const PACKET_ID: VarInt = 1;
|
||||
|
||||
fn write(&self, bytebuf: &mut ByteBuffer) {
|
||||
bytebuf.write_string_len(self.server_id.as_str(), 20);
|
||||
bytebuf.write_var_int(self.public_key_length);
|
||||
bytebuf.write_bytes(self.public_key);
|
||||
bytebuf.write_var_int(self.verify_token_length);
|
||||
bytebuf.write_bytes(self.verify_token);
|
||||
bytebuf.write_bool(self.should_authenticate);
|
||||
}
|
||||
}
|
||||
|
||||
pub struct CSetCompression {
|
||||
threshold: VarInt,
|
||||
}
|
||||
|
||||
pub struct CLoginSuccess {
|
||||
pub uuid: uuid::Uuid,
|
||||
pub username: String, // 16
|
||||
pub num_of_props: VarInt,
|
||||
// pub property: Property,
|
||||
pub strict_error_handling: bool,
|
||||
}
|
||||
|
||||
impl CLoginSuccess {
|
||||
pub fn new(
|
||||
uuid: uuid::Uuid,
|
||||
username: String,
|
||||
num_of_props: VarInt,
|
||||
strict_error_handling: bool,
|
||||
) -> Self {
|
||||
Self {
|
||||
uuid,
|
||||
username,
|
||||
num_of_props,
|
||||
strict_error_handling,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Property {
|
||||
name: String,
|
||||
value: String,
|
||||
is_signed: bool,
|
||||
signature: Option<String>,
|
||||
}
|
||||
|
||||
impl ClientPacket for CLoginSuccess {
|
||||
const PACKET_ID: VarInt = 2;
|
||||
|
||||
fn write(&self, bytebuf: &mut ByteBuffer) {
|
||||
bytebuf.write_uuid(self.uuid);
|
||||
bytebuf.write_string(&self.username);
|
||||
bytebuf.write_var_int(self.num_of_props);
|
||||
// Todo
|
||||
bytebuf.write_bool(self.strict_error_handling);
|
||||
}
|
||||
}
|
||||
|
||||
impl CSetCompression {
|
||||
pub fn new(threshold: VarInt) -> Self {
|
||||
Self { threshold }
|
||||
}
|
||||
}
|
||||
|
||||
impl ClientPacket for CSetCompression {
|
||||
const PACKET_ID: VarInt = 3;
|
||||
|
||||
fn write(&self, bytebuf: &mut ByteBuffer) {
|
||||
bytebuf.write_var_int(self.threshold);
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
// Clientbound Packets
|
||||
// Server -> Client
|
||||
//
|
||||
pub mod login;
|
||||
pub mod status;
|
||||
|
||||
@@ -1,4 +1,8 @@
|
||||
use std::io::{Read, Write};
|
||||
|
||||
use anyhow::bail;
|
||||
use bytebuf::buffer::ByteBuffer;
|
||||
use byteorder::ReadBytesExt;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
pub mod bytebuf;
|
||||
@@ -6,15 +10,90 @@ pub mod bytebuf;
|
||||
pub mod client;
|
||||
pub mod server;
|
||||
|
||||
type VarInt = i32;
|
||||
type VarLong = i64;
|
||||
pub type VarInt = i32;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct VarInt32(pub i32);
|
||||
|
||||
impl VarInt32 {
|
||||
/// The maximum number of bytes a `VarInt` could occupy when read from and
|
||||
/// written to the Minecraft protocol.
|
||||
pub const MAX_SIZE: usize = 5;
|
||||
|
||||
/// Returns the exact number of bytes this varint will write when
|
||||
/// [`Encode::encode`] is called, assuming no error occurs.
|
||||
pub const fn written_size(self) -> usize {
|
||||
match self.0 {
|
||||
0 => 1,
|
||||
n => (31 - n.leading_zeros() as usize) / 7 + 1,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn decode_partial<R: Read>(mut r: R) -> Result<i32, VarIntDecodeError> {
|
||||
let mut val = 0;
|
||||
for i in 0..Self::MAX_SIZE {
|
||||
let byte = r.read_u8().map_err(|_| VarIntDecodeError::Incomplete)?;
|
||||
val |= (i32::from(byte) & 0b01111111) << (i * 7);
|
||||
if byte & 0b10000000 == 0 {
|
||||
return Ok(val);
|
||||
}
|
||||
}
|
||||
|
||||
Err(VarIntDecodeError::TooLarge)
|
||||
}
|
||||
|
||||
pub fn encode(&self, mut w: impl Write) -> anyhow::Result<()> {
|
||||
let x = self.0 as u64;
|
||||
let stage1 = (x & 0x000000000000007f)
|
||||
| ((x & 0x0000000000003f80) << 1)
|
||||
| ((x & 0x00000000001fc000) << 2)
|
||||
| ((x & 0x000000000fe00000) << 3)
|
||||
| ((x & 0x00000000f0000000) << 4);
|
||||
|
||||
let leading = stage1.leading_zeros();
|
||||
|
||||
let unused_bytes = (leading - 1) >> 3;
|
||||
let bytes_needed = 8 - unused_bytes;
|
||||
|
||||
// set all but the last MSBs
|
||||
let msbs = 0x8080808080808080;
|
||||
let msbmask = 0xffffffffffffffff >> (((8 - bytes_needed + 1) << 3) - 1);
|
||||
|
||||
let merged = stage1 | (msbs & msbmask);
|
||||
let bytes = merged.to_le_bytes();
|
||||
|
||||
w.write_all(unsafe { bytes.get_unchecked(..bytes_needed as usize) })?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn decode(r: &mut &[u8]) -> anyhow::Result<Self> {
|
||||
let mut val = 0;
|
||||
for i in 0..Self::MAX_SIZE {
|
||||
let byte = r.read_u8()?;
|
||||
val |= (i32::from(byte) & 0b01111111) << (i * 7);
|
||||
if byte & 0b10000000 == 0 {
|
||||
return Ok(VarInt32(val));
|
||||
}
|
||||
}
|
||||
bail!("VarInt is too large")
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
|
||||
pub enum VarIntDecodeError {
|
||||
Incomplete,
|
||||
TooLarge,
|
||||
}
|
||||
|
||||
pub type VarLong = i64;
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub enum ConnectionState {
|
||||
HandShake,
|
||||
Status,
|
||||
Login,
|
||||
Transfer,
|
||||
Config,
|
||||
}
|
||||
|
||||
impl ConnectionState {
|
||||
|
||||
@@ -13,7 +13,7 @@ impl SHandShake {
|
||||
pub fn read(bytebuf: &mut ByteBuffer) -> Self {
|
||||
Self {
|
||||
protocol_version: bytebuf.read_var_int().unwrap(),
|
||||
server_address: bytebuf.read_string().unwrap(),
|
||||
server_address: bytebuf.read_string_len(255).unwrap(),
|
||||
server_port: bytebuf.read_u16().unwrap(),
|
||||
next_state: ConnectionState::from_varint(bytebuf.read_var_int().unwrap()),
|
||||
}
|
||||
|
||||
72
pumpkin/src/protocol/server/login/mod.rs
Normal file
72
pumpkin/src/protocol/server/login/mod.rs
Normal file
@@ -0,0 +1,72 @@
|
||||
use crate::protocol::{bytebuf::buffer::ByteBuffer, VarInt};
|
||||
|
||||
pub struct SLoginStart {
|
||||
pub name: String, // 16
|
||||
pub uuid: uuid::Uuid,
|
||||
}
|
||||
|
||||
impl SLoginStart {
|
||||
pub const PACKET_ID: VarInt = 0;
|
||||
|
||||
pub fn read(bytebuf: &mut ByteBuffer) -> Self {
|
||||
Self {
|
||||
name: bytebuf.read_string_len(16).unwrap(),
|
||||
uuid: bytebuf.read_uuid().unwrap(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct SEncryptionResponse {
|
||||
pub shared_secret_length: VarInt,
|
||||
pub shared_secret: Vec<u8>,
|
||||
pub verify_token_length: VarInt,
|
||||
pub verify_token: Vec<u8>,
|
||||
}
|
||||
|
||||
impl SEncryptionResponse {
|
||||
pub const PACKET_ID: VarInt = 1;
|
||||
|
||||
pub fn read(bytebuf: &mut ByteBuffer) -> Self {
|
||||
let shared_secret_length = bytebuf.read_var_int().unwrap();
|
||||
let shared_secret = bytebuf.read_bytes(shared_secret_length as usize).unwrap();
|
||||
let verify_token_length = bytebuf.read_var_int().unwrap();
|
||||
let verify_token = bytebuf.read_bytes(shared_secret_length as usize).unwrap();
|
||||
Self {
|
||||
shared_secret_length,
|
||||
shared_secret,
|
||||
verify_token_length,
|
||||
verify_token,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct SLoginPluginResponse<'a> {
|
||||
message_id: VarInt,
|
||||
successful: bool,
|
||||
data: Option<&'a [u8]>,
|
||||
}
|
||||
|
||||
impl<'a> SLoginPluginResponse<'a> {
|
||||
pub const PACKET_ID: VarInt = 2;
|
||||
|
||||
pub fn read(bytebuf: &mut ByteBuffer) -> Self {
|
||||
Self {
|
||||
message_id: bytebuf.read_var_int().unwrap(),
|
||||
successful: bytebuf.read_bool().unwrap(),
|
||||
data: None, // TODO
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Acknowledgement to the Login Success packet sent to the server.
|
||||
pub struct SLoginAcknowledged {
|
||||
// empty
|
||||
}
|
||||
|
||||
impl SLoginAcknowledged {
|
||||
pub const PACKET_ID: VarInt = 3;
|
||||
|
||||
pub fn read(_bytebuf: &mut ByteBuffer) -> Self {
|
||||
Self {}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
// Serverbound Packets
|
||||
// Client -> Server
|
||||
pub mod handshake;
|
||||
pub mod login;
|
||||
pub mod status;
|
||||
|
||||
@@ -1,10 +1,19 @@
|
||||
use std::io::Cursor;
|
||||
|
||||
use base64::{engine::general_purpose, Engine};
|
||||
use rsa::{rand_core::OsRng, traits::PublicKeyParts, RsaPrivateKey, RsaPublicKey};
|
||||
|
||||
use crate::protocol::{Players, Sample, StatusResponse, Version};
|
||||
|
||||
pub struct Server {
|
||||
pub compression_threshold: Option<u8>,
|
||||
|
||||
pub online_mode: bool,
|
||||
pub encriyption: bool, // encription is always required when online_mode is disabled
|
||||
pub public_key: RsaPublicKey,
|
||||
pub private_key: RsaPrivateKey,
|
||||
pub public_key_der: Box<[u8]>,
|
||||
|
||||
pub status_response: StatusResponse,
|
||||
}
|
||||
|
||||
@@ -16,9 +25,32 @@ impl Default for Server {
|
||||
|
||||
impl Server {
|
||||
pub fn new() -> Self {
|
||||
let status_response = Self::default_response();
|
||||
|
||||
// todo, only create when needed
|
||||
let (public_key, private_key) = Self::generate_keys();
|
||||
|
||||
let public_key_der = rsa_der::public_key_to_der(
|
||||
&private_key.n().to_bytes_be(),
|
||||
&private_key.e().to_bytes_be(),
|
||||
)
|
||||
.into_boxed_slice();
|
||||
|
||||
Self {
|
||||
online_mode: true,
|
||||
encriyption: true,
|
||||
compression_threshold: None, // 256
|
||||
public_key,
|
||||
private_key,
|
||||
status_response,
|
||||
public_key_der,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn default_response() -> StatusResponse {
|
||||
let path = concat!(env!("CARGO_MANIFEST_DIR"), "/icon.png");
|
||||
|
||||
let status_response = StatusResponse {
|
||||
StatusResponse {
|
||||
version: Version {
|
||||
name: "1.21".into(),
|
||||
protocol: 767,
|
||||
@@ -33,8 +65,7 @@ impl Server {
|
||||
},
|
||||
description: "Pumpkin Server".into(),
|
||||
favicon: Self::load_icon(path),
|
||||
};
|
||||
Self { status_response }
|
||||
}
|
||||
}
|
||||
|
||||
pub fn load_icon(path: &str) -> String {
|
||||
@@ -50,4 +81,10 @@ impl Server {
|
||||
general_purpose::STANDARD.encode_string(image, &mut result);
|
||||
result
|
||||
}
|
||||
|
||||
pub fn generate_keys() -> (RsaPublicKey, RsaPrivateKey) {
|
||||
let priv_key = RsaPrivateKey::new(&mut OsRng, 1024).expect("failed to generate a key");
|
||||
let pub_key = RsaPublicKey::from(&priv_key);
|
||||
(pub_key, priv_key)
|
||||
}
|
||||
}
|
||||
|
||||
1
pumpkin/src/util/mod.rs
Normal file
1
pumpkin/src/util/mod.rs
Normal file
@@ -0,0 +1 @@
|
||||
|
||||
Reference in New Issue
Block a user