mirror of
https://git.ngram.ca/OpenJam/rc-servers
synced 2026-08-23 23:08:52 +00:00
Create RC primary service (load balancer)
This commit is contained in:
271
Cargo.lock
generated
271
Cargo.lock
generated
@@ -106,6 +106,12 @@ dependencies = [
|
||||
"num-traits 0.2.19",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "array-init"
|
||||
version = "2.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3d62b7694a562cdf5a74227903507c56ab2cc8bdd1f781ed5cb4cf9c9f810bfc"
|
||||
|
||||
[[package]]
|
||||
name = "async-stream"
|
||||
version = "0.3.6"
|
||||
@@ -207,6 +213,30 @@ version = "0.1.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "383d29d513d8764dcdc42ea295d979eb99c3c9f00607b3692cf68a431f7dca72"
|
||||
|
||||
[[package]]
|
||||
name = "binrw"
|
||||
version = "0.14.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7d4bca59c20d6f40c2cc0802afbe1e788b89096f61bdf7aeea6bf00f10c2909b"
|
||||
dependencies = [
|
||||
"array-init",
|
||||
"binrw_derive",
|
||||
"bytemuck",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "binrw_derive"
|
||||
version = "0.14.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d8ba42866ce5bced2645bfa15e97eef2c62d2bdb530510538de8dd3d04efff3c"
|
||||
dependencies = [
|
||||
"either",
|
||||
"owo-colors",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "1.3.2"
|
||||
@@ -300,6 +330,46 @@ dependencies = [
|
||||
"windows-targets 0.52.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "4.5.27"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "769b0145982b4b48713e01ec42d61614425f27b7058bda7180a3a41f30104796"
|
||||
dependencies = [
|
||||
"clap_builder",
|
||||
"clap_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap_builder"
|
||||
version = "4.5.27"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1b26884eb4b57140e4d2d93652abfa49498b938b3c9179f9fc487b0acc3edad7"
|
||||
dependencies = [
|
||||
"anstream",
|
||||
"anstyle",
|
||||
"clap_lex",
|
||||
"strsim",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap_derive"
|
||||
version = "4.5.24"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "54b755194d6389280185988721fffba69495eed5ee9feeee9a599b53db80318c"
|
||||
dependencies = [
|
||||
"heck",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.96",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap_lex"
|
||||
version = "0.7.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6"
|
||||
|
||||
[[package]]
|
||||
name = "colorchoice"
|
||||
version = "1.0.3"
|
||||
@@ -593,10 +663,22 @@ dependencies = [
|
||||
"cfg-if",
|
||||
"js-sys",
|
||||
"libc",
|
||||
"wasi",
|
||||
"wasi 0.11.0+wasi-snapshot-preview1",
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "getrandom"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "43a49c392881ce6d5c3b8cb70f98717b7c07aabbdff06687b9030dbfbe2725f8"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"wasi 0.13.3+wasi-0.2.2",
|
||||
"windows-targets 0.52.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gimli"
|
||||
version = "0.31.1"
|
||||
@@ -644,6 +726,12 @@ version = "0.15.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289"
|
||||
|
||||
[[package]]
|
||||
name = "heck"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
|
||||
|
||||
[[package]]
|
||||
name = "hermit-abi"
|
||||
version = "0.3.9"
|
||||
@@ -1184,7 +1272,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"wasi",
|
||||
"wasi 0.11.0+wasi-snapshot-preview1",
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
@@ -1217,6 +1305,20 @@ dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num"
|
||||
version = "0.4.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "35bd024e8b2ff75562e5f34e7f4905839deb4b22955ef5e73d2fea1b9813cb23"
|
||||
dependencies = [
|
||||
"num-bigint",
|
||||
"num-complex",
|
||||
"num-integer",
|
||||
"num-iter",
|
||||
"num-rational",
|
||||
"num-traits 0.2.19",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-bigint"
|
||||
version = "0.4.6"
|
||||
@@ -1227,6 +1329,15 @@ dependencies = [
|
||||
"num-traits 0.2.19",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-complex"
|
||||
version = "0.4.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "73f88a1307638156682bada9d7604135552957b7818057dcef22705b4d509495"
|
||||
dependencies = [
|
||||
"num-traits 0.2.19",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-conv"
|
||||
version = "0.1.0"
|
||||
@@ -1242,6 +1353,28 @@ dependencies = [
|
||||
"num-traits 0.2.19",
|
||||
]
|
||||
|
||||
[[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 0.2.19",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-rational"
|
||||
version = "0.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824"
|
||||
dependencies = [
|
||||
"num-bigint",
|
||||
"num-integer",
|
||||
"num-traits 0.2.19",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-traits"
|
||||
version = "0.1.43"
|
||||
@@ -1318,6 +1451,12 @@ version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39"
|
||||
|
||||
[[package]]
|
||||
name = "owo-colors"
|
||||
version = "3.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c1b04fb49957986fdce4d6ee7a65027d55d4b6d2265e5848bbb507b58ccfdb6f"
|
||||
|
||||
[[package]]
|
||||
name = "parking_lot"
|
||||
version = "0.12.3"
|
||||
@@ -1392,6 +1531,25 @@ version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
|
||||
|
||||
[[package]]
|
||||
name = "polariton"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"binrw",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "polariton_auth"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"log",
|
||||
"num",
|
||||
"polariton",
|
||||
"rand 0.9.0",
|
||||
"ring",
|
||||
"simple-rijndael",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "powerfmt"
|
||||
version = "0.2.0"
|
||||
@@ -1404,7 +1562,7 @@ version = "0.2.20"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04"
|
||||
dependencies = [
|
||||
"zerocopy",
|
||||
"zerocopy 0.7.35",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1464,7 +1622,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a2fe5ef3495d7d2e377ff17b1a8ce2ee2ec2a18cde8b6ad6619d65d0701c135d"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"getrandom",
|
||||
"getrandom 0.2.15",
|
||||
"rand 0.8.5",
|
||||
"ring",
|
||||
"rustc-hash",
|
||||
@@ -1520,10 +1678,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"rand_chacha",
|
||||
"rand_chacha 0.3.1",
|
||||
"rand_core 0.6.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand"
|
||||
version = "0.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3779b94aeb87e8bd4e834cee3650289ee9e0d5677f976ecdb6d219e5f4f6cd94"
|
||||
dependencies = [
|
||||
"rand_chacha 0.9.0",
|
||||
"rand_core 0.9.0",
|
||||
"zerocopy 0.8.14",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_chacha"
|
||||
version = "0.3.1"
|
||||
@@ -1534,6 +1703,16 @@ dependencies = [
|
||||
"rand_core 0.6.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_chacha"
|
||||
version = "0.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb"
|
||||
dependencies = [
|
||||
"ppv-lite86",
|
||||
"rand_core 0.9.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_core"
|
||||
version = "0.3.1"
|
||||
@@ -1555,7 +1734,29 @@ version = "0.6.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
|
||||
dependencies = [
|
||||
"getrandom",
|
||||
"getrandom 0.2.15",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_core"
|
||||
version = "0.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b08f3c9802962f7e1b25113931d94f43ed9725bebc59db9d0c3e9a23b67e15ff"
|
||||
dependencies = [
|
||||
"getrandom 0.3.1",
|
||||
"zerocopy 0.8.14",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rc_services"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"env_logger",
|
||||
"log",
|
||||
"polariton",
|
||||
"polariton_auth",
|
||||
"tokio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1701,7 +1902,7 @@ checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"cfg-if",
|
||||
"getrandom",
|
||||
"getrandom 0.2.15",
|
||||
"libc",
|
||||
"spin",
|
||||
"untrusted",
|
||||
@@ -1964,6 +2165,12 @@ dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "simple-rijndael"
|
||||
version = "0.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "843fc9945b08a629a18fb7eaf7d76d9e2ef2fa628c5ea1b7782627fc21bb2285"
|
||||
|
||||
[[package]]
|
||||
name = "simple_asn1"
|
||||
version = "0.6.3"
|
||||
@@ -2049,6 +2256,12 @@ version = "0.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7ef6b00f8fe8eaaaff22cb9b70822a48c1a5d772bc682c202a57c0b438175845"
|
||||
|
||||
[[package]]
|
||||
name = "strsim"
|
||||
version = "0.11.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
|
||||
|
||||
[[package]]
|
||||
name = "subtle"
|
||||
version = "2.6.1"
|
||||
@@ -2105,7 +2318,7 @@ checksum = "9a8a559c81686f576e8cd0290cd2a24a2a9ad80c98b3478856500fcbd7acd704"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"fastrand",
|
||||
"getrandom",
|
||||
"getrandom 0.2.15",
|
||||
"once_cell",
|
||||
"rustix",
|
||||
"windows-sys 0.59.0",
|
||||
@@ -2508,7 +2721,7 @@ version = "1.12.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b3758f5e68192bb96cc8f9b7e2c2cfdabb435499a28499a42f8f984092adad4b"
|
||||
dependencies = [
|
||||
"getrandom",
|
||||
"getrandom 0.2.15",
|
||||
"rand 0.8.5",
|
||||
]
|
||||
|
||||
@@ -2539,6 +2752,15 @@ version = "0.11.0+wasi-snapshot-preview1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
|
||||
|
||||
[[package]]
|
||||
name = "wasi"
|
||||
version = "0.13.3+wasi-0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "26816d2e1a4a36a2940b96c5296ce403917633dff8f3440e9b236ed6f6bacad2"
|
||||
dependencies = [
|
||||
"wit-bindgen-rt",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen"
|
||||
version = "0.2.100"
|
||||
@@ -2866,6 +3088,15 @@ dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wit-bindgen-rt"
|
||||
version = "0.33.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3268f3d866458b787f390cf61f4bbb563b922d091359f9608842999eaee3943c"
|
||||
dependencies = [
|
||||
"bitflags 2.8.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "write16"
|
||||
version = "1.0.0"
|
||||
@@ -2918,7 +3149,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0"
|
||||
dependencies = [
|
||||
"byteorder",
|
||||
"zerocopy-derive",
|
||||
"zerocopy-derive 0.7.35",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zerocopy"
|
||||
version = "0.8.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a367f292d93d4eab890745e75a778da40909cab4d6ff8173693812f79c4a2468"
|
||||
dependencies = [
|
||||
"zerocopy-derive 0.8.14",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2932,6 +3172,17 @@ dependencies = [
|
||||
"syn 2.0.96",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zerocopy-derive"
|
||||
version = "0.8.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d3931cb58c62c13adec22e38686b559c86a30565e16ad6e8510a337cedc611e1"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.96",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zerofrom"
|
||||
version = "0.1.5"
|
||||
|
||||
@@ -5,7 +5,7 @@ edition = "2021"
|
||||
|
||||
[workspace]
|
||||
members = [
|
||||
"auth", "rc_static_data",
|
||||
"auth", "polariton_auth", "rc_services", "rc_static_data",
|
||||
]
|
||||
|
||||
[workspace.dependencies]
|
||||
@@ -13,3 +13,5 @@ rocket = { version = "0.5.1", features = [ "json" ] }
|
||||
libfj = { version = "0.7.5", path = "../libfj" }
|
||||
log = "0.4"
|
||||
env_logger = "0.11"
|
||||
clap = { version = "4.5", features = [ "derive" ] }
|
||||
polariton = { version = "*", path = "../polariton" }
|
||||
|
||||
65
assets/robocraft/service_packets.md
Normal file
65
assets/robocraft/service_packets.md
Normal file
@@ -0,0 +1,65 @@
|
||||
# Connect to Photon
|
||||
|
||||
## TCP packet
|
||||
|
||||
Header 7 bytes
|
||||
Connect Data 41 bytes
|
||||
|
||||
### Header
|
||||
|
||||
0..1 =251 (mode?)
|
||||
1..5 packet length (big endian)
|
||||
5..6 =0 channel ID
|
||||
6..7 =1 reliable? (bool; 1->reliable, 0->unreliable)
|
||||
|
||||
### Connect Data
|
||||
|
||||
0..1 =243 1 byte (mode?)
|
||||
1..2 =0
|
||||
2..4 Version 2 bytes (always 1 6)
|
||||
4..5 =30 1 byte (client ID shifted by 1 -- 15 is ID)
|
||||
5..7 client version 3 bytes (4 bytes merged into 3 -- 0 is upper 4 bits of byte 0, 1 is OR-ed with 0, byte 1 is 2, byte 2 is 3)
|
||||
8..9 =0
|
||||
9..41 app ID string 32 bytes (if shorter than 32 bytes/chars the remaining bytes are 0; if longer than 32 bytes/chars the remaining app ID is ignored i.e. truncated)
|
||||
|
||||
### Ping Response Data
|
||||
|
||||
0..1 =240 1 byte
|
||||
1..5 tick count at time of server's receipt (big endian) (unit of game ticks?)
|
||||
5..9 tick count from client's request (big endian) (unit of game ticks?)
|
||||
|
||||
### Ping Request Data
|
||||
0..1 =240
|
||||
1..5 current tick count
|
||||
|
||||
### Modes
|
||||
|
||||
220 Region info (in)
|
||||
222 Friends list info (in)
|
||||
225 Join lobby info (in)
|
||||
226 Join lobby info (in)
|
||||
227 Join lobby info (in)
|
||||
228 Master server connect success (in)
|
||||
229 Lobby joined success (in)
|
||||
230 Join/connect info (in)
|
||||
231 Join/connect info (in)
|
||||
240 Ping (both)
|
||||
243 Connect (out)
|
||||
244 Connect? response? (in)
|
||||
254 Disconnect to Reconnect
|
||||
|
||||
### Parameters
|
||||
|
||||
#### Op code 230
|
||||
|
||||
192 Reset/redo Encryption? (Map<u8, Typed>)
|
||||
202 Nickname (string)
|
||||
225 User ID (string)
|
||||
230 Master server address (string)
|
||||
|
||||
#### Op code always???
|
||||
221 Auth token (string)
|
||||
|
||||
|
||||
|
||||
|
||||
12
polariton_auth/Cargo.toml
Normal file
12
polariton_auth/Cargo.toml
Normal file
@@ -0,0 +1,12 @@
|
||||
[package]
|
||||
name = "polariton_auth"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
log.workspace = true
|
||||
polariton.workspace = true
|
||||
num = "0.4"
|
||||
rand = "0.9"
|
||||
ring = "0.17"
|
||||
simple-rijndael = "0.3"
|
||||
86
polariton_auth/src/encryption.rs
Normal file
86
polariton_auth/src/encryption.rs
Normal file
@@ -0,0 +1,86 @@
|
||||
use num::BigInt;
|
||||
use rand::Rng;
|
||||
use simple_rijndael::impls::RijndaelCbc;
|
||||
use simple_rijndael::paddings::Pkcs7Padding;
|
||||
|
||||
pub struct Keys {
|
||||
pub pub_key: Vec<u8>,
|
||||
pub enc: CryptoImpl,
|
||||
}
|
||||
|
||||
const SECRET_LEN: usize = 160 / 8;
|
||||
const PRIME_768: &[u8] = &[255, 255, 255, 255, 255, 255, 255, 255, 201, 15,
|
||||
218, 162, 33, 104, 194, 52, 196, 198, 98, 139,
|
||||
128, 220, 28, 209, 41, 2, 78, 8, 138, 103,
|
||||
204, 116, 2, 11, 190, 166, 59, 19, 155, 34,
|
||||
81, 74, 8, 121, 142, 52, 4, 221, 239, 149,
|
||||
25, 179, 205, 58, 67, 27, 48, 43, 10, 109,
|
||||
242, 95, 20, 55, 79, 225, 53, 109, 109, 81,
|
||||
194, 69, 228, 133, 181, 118, 98, 94, 126, 198,
|
||||
244, 76, 66, 233, 166, 58, 54, 32, 255, 255,
|
||||
255, 255, 255, 255, 255, 255];
|
||||
const PRIME_ROOT: u8 = 22;
|
||||
|
||||
pub fn generate_encryption_details(client_pub_key: &[u8]) -> Keys {
|
||||
let client_num = BigInt::from_bytes_be(num::bigint::Sign::Plus, client_pub_key);
|
||||
let big_0 = BigInt::from(0);
|
||||
let prime_root = BigInt::from(PRIME_ROOT);
|
||||
let my_prime = BigInt::from_bytes_be(num::bigint::Sign::Plus, PRIME_768);
|
||||
log::debug!("Generating keys for client pub key {}", client_num.to_string());
|
||||
let mut rng = rand::rng();
|
||||
let mut bytes = rng.random::<[u8; SECRET_LEN]>();
|
||||
let mut my_secret = BigInt::from_bytes_be(num::bigint::Sign::Plus, &bytes);
|
||||
while my_secret >= &my_prime - 1 || my_secret == big_0 {
|
||||
bytes = rng.random::<[u8; SECRET_LEN]>();
|
||||
my_secret = BigInt::from_bytes_be(num::bigint::Sign::Plus, &bytes);
|
||||
log::debug!("Generated secret {} (prime to beat: {})", my_secret.to_string(), my_prime.to_string());
|
||||
}
|
||||
let my_pub_key = prime_root.modpow(&my_secret, &my_prime);
|
||||
let shared_key = client_num.modpow(&my_secret, &my_prime);
|
||||
log::debug!("Generated shared key {} and pub key {}", shared_key.to_string(), my_pub_key.to_string());
|
||||
let shared_key = shared_key.to_bytes_be().1;
|
||||
let enc_key: Vec<u8> = ring::digest::digest(&ring::digest::SHA256, &shared_key).as_ref().into();
|
||||
log::debug!("Encryption key is {:?}", enc_key.as_slice());
|
||||
Keys {
|
||||
pub_key: my_pub_key.to_signed_bytes_be(),
|
||||
enc: CryptoImpl::new(enc_key),
|
||||
}
|
||||
}
|
||||
|
||||
pub struct CryptoImpl {
|
||||
crypto: RijndaelCbc<Pkcs7Padding>,
|
||||
iv: [u8; 16],
|
||||
key: Vec<u8>
|
||||
}
|
||||
|
||||
impl CryptoImpl {
|
||||
fn new(key: Vec<u8>) -> Self {
|
||||
Self {
|
||||
crypto: RijndaelCbc::<Pkcs7Padding>::new(&key, 16).unwrap(),
|
||||
iv: [0u8; 16],
|
||||
key,
|
||||
}
|
||||
}
|
||||
|
||||
fn decrypt(&self, data: Vec<u8>) -> Vec<u8> {
|
||||
self.crypto.decrypt(&self.iv, data).unwrap_or_default()
|
||||
}
|
||||
|
||||
fn encrypt(&self, data: Vec<u8>) -> Vec<u8> {
|
||||
self.crypto.encrypt(&self.iv, data).unwrap_or_default()
|
||||
}
|
||||
}
|
||||
|
||||
impl polariton::packet::Cryptographer for CryptoImpl {
|
||||
fn decrypt(&self, data: Vec<u8>) -> Vec<u8> {
|
||||
self.decrypt(data)
|
||||
}
|
||||
|
||||
fn encrypt(&self, data: Vec<u8>) -> Vec<u8> {
|
||||
self.encrypt(data)
|
||||
}
|
||||
|
||||
fn secret(&self) -> &'_ [u8] {
|
||||
self.key.as_slice()
|
||||
}
|
||||
}
|
||||
198
polariton_auth/src/handshake.rs
Normal file
198
polariton_auth/src/handshake.rs
Normal file
@@ -0,0 +1,198 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use polariton::packet::{Packet, Message, StandardMessage, Data, Cryptographer};
|
||||
use polariton::operation::{Typed, ParameterTable, OperationResponse};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Handshake<T> {
|
||||
state: T,
|
||||
}
|
||||
|
||||
pub struct HandshakeAnd<T, X> {
|
||||
pub handshake: Handshake<T>,
|
||||
pub extra: X,
|
||||
}
|
||||
|
||||
pub struct Start<'a> {
|
||||
app_id: &'a str,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum ConnectError<'b, 'a> {
|
||||
UnexpectedPacket,
|
||||
WrongAppId { got: &'b str, expected: &'a str },
|
||||
}
|
||||
|
||||
// TODO impl core::fmt::Display for ConnectError
|
||||
// TODO impl std::error::Error for ConnectError
|
||||
|
||||
impl <'a> Handshake<Start<'a>> {
|
||||
pub fn new(app_id: &'a str) -> Self {
|
||||
Self {
|
||||
state: Start { app_id },
|
||||
}
|
||||
}
|
||||
|
||||
pub fn connect<'b>(self, packet: &'b Packet) -> Result<HandshakeAnd<Connected, Packet>, HandshakeAnd<Start<'a>, ConnectError<'b, 'a>>> {
|
||||
if let Packet::Packet(packet) = &packet {
|
||||
if let Message::Standard(conn) = &packet.message {
|
||||
if let Data::InitStart(info) = &conn.data {
|
||||
if info.app_id != self.state.app_id {
|
||||
let err = ConnectError::WrongAppId { got: &info.app_id, expected: &self.state.app_id };
|
||||
return Err(HandshakeAnd {
|
||||
handshake: self,
|
||||
extra: err,
|
||||
});
|
||||
}
|
||||
let new_self = Handshake::<Connected> {
|
||||
state: Connected,
|
||||
};
|
||||
return Ok(HandshakeAnd {
|
||||
handshake: new_self,
|
||||
extra: Packet::from_message(
|
||||
Message::Standard(StandardMessage {
|
||||
flags: 0,
|
||||
data: Data::InitAck ,
|
||||
}),
|
||||
packet.header.channel, true, None).unwrap()
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(HandshakeAnd {
|
||||
handshake: self,
|
||||
extra: ConnectError::UnexpectedPacket,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Connected;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum EncryptError {
|
||||
UnexpectedPacket,
|
||||
MissingParameter(u8),
|
||||
}
|
||||
|
||||
impl Handshake<Connected> {
|
||||
const PUBLIC_KEY_PARAM_KEY: u8 = 1;
|
||||
|
||||
pub fn encrypt<'a>(self, packet: &'a Packet) -> Result<HandshakeAnd<Encrypted, (Packet, Box<Arc<dyn Cryptographer>>)>, HandshakeAnd<Connected, EncryptError>> {
|
||||
if let Packet::Packet(packet) = &packet {
|
||||
if let Message::Standard(conn) = &packet.message {
|
||||
if let Data::InternalOpReq(req) = &conn.data {
|
||||
if req.code == 0 {
|
||||
let params = req.params.to_owned().to_dict();
|
||||
if let Some(Typed::Bytes(pub_key)) = params.get(&Self::PUBLIC_KEY_PARAM_KEY) {
|
||||
let keys = crate::encryption::generate_encryption_details(&pub_key.vec);
|
||||
let mut response_params = std::collections::HashMap::with_capacity(1);
|
||||
response_params.insert(Self::PUBLIC_KEY_PARAM_KEY, Typed::Bytes(keys.pub_key.into()));
|
||||
let resp_packet = Packet::from_message(
|
||||
Message::Standard(
|
||||
StandardMessage {
|
||||
flags: 0,
|
||||
data: Data::InternalOpResp(OperationResponse {
|
||||
code: req.code,
|
||||
return_code: 0,
|
||||
message: Typed::Null,
|
||||
params: ParameterTable::from_dict(response_params) })
|
||||
}), 0, true, None).unwrap();
|
||||
let new_self = Handshake::<Encrypted> {
|
||||
state: Encrypted,
|
||||
};
|
||||
return Ok(HandshakeAnd {
|
||||
handshake: new_self,
|
||||
extra: (resp_packet, Box::new(Arc::new(keys.enc))),
|
||||
});
|
||||
} else {
|
||||
return Err(HandshakeAnd {
|
||||
handshake: self,
|
||||
extra: EncryptError::MissingParameter(Self::PUBLIC_KEY_PARAM_KEY),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(HandshakeAnd {
|
||||
handshake: self,
|
||||
extra: EncryptError::UnexpectedPacket,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Encrypted;
|
||||
|
||||
impl Handshake<Encrypted> {
|
||||
pub fn with_auth<T: AuthProvider<E>, E>(self, auth: T) -> Handshake<Auth<T, E>> {
|
||||
Handshake {
|
||||
state: Auth {
|
||||
authenticator: auth,
|
||||
_e: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub trait AuthProvider<E> {
|
||||
fn validate(&mut self, params: &std::collections::HashMap<u8, Typed>) -> Result<std::collections::HashMap<u8, Typed>, E>;
|
||||
}
|
||||
|
||||
pub struct Auth<T: AuthProvider<E>, E> {
|
||||
authenticator: T,
|
||||
_e: std::marker::PhantomData<E>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum AuthError<E> {
|
||||
Validation(E),
|
||||
UnexpectedPacket
|
||||
}
|
||||
|
||||
impl <T: AuthProvider<E>, E> Handshake<Auth<T, E>> {
|
||||
//const SERVER_ADDRESS_KEY: u8 = 230;
|
||||
const AUTH_REQUEST_CODE: u8 = 230;
|
||||
const USER_ID_KEY: u8 = 225;
|
||||
const NICKNAME_KEY: u8 = 225;
|
||||
pub fn authenticate<'a>(mut self, packet: &'a Packet, crypto: Box<Arc<dyn Cryptographer>>) -> Result<Packet, HandshakeAnd<Auth<T, E>, AuthError<E>>> {
|
||||
if let Packet::Packet(packet) = &packet {
|
||||
if let Message::Standard(conn) = &packet.message {
|
||||
if let Data::OpReq(req) = &conn.data {
|
||||
if req.code == Self::AUTH_REQUEST_CODE /* or 231 ???*/ {
|
||||
let req_dict = req.params.to_owned().to_dict();
|
||||
let mut params_resp = match self.state.authenticator.validate(&req_dict) {
|
||||
Ok(x) => x,
|
||||
Err(e) => {
|
||||
return Err(HandshakeAnd {
|
||||
handshake: self,
|
||||
extra: AuthError::Validation(e),
|
||||
});
|
||||
}
|
||||
};
|
||||
if let Some(user_id) = req_dict.get(&Self::USER_ID_KEY) {
|
||||
params_resp.insert(Self::USER_ID_KEY, user_id.to_owned());
|
||||
params_resp.insert(Self::NICKNAME_KEY, user_id.to_owned());
|
||||
}
|
||||
return Ok(Packet::from_message(
|
||||
Message::Standard(
|
||||
StandardMessage {
|
||||
flags: 0,
|
||||
data: Data::OpResp(OperationResponse {
|
||||
code: Self::AUTH_REQUEST_CODE,
|
||||
return_code: 0,
|
||||
message: Typed::Null,
|
||||
params: params_resp.into(),
|
||||
})
|
||||
}.encrypt(conn.is_encrypted())
|
||||
), packet.header.channel, true, Some(crypto)).unwrap());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(HandshakeAnd {
|
||||
handshake: self,
|
||||
extra: AuthError::UnexpectedPacket,
|
||||
})
|
||||
}
|
||||
}
|
||||
7
polariton_auth/src/lib.rs
Normal file
7
polariton_auth/src/lib.rs
Normal file
@@ -0,0 +1,7 @@
|
||||
mod encryption;
|
||||
|
||||
mod handshake;
|
||||
pub use handshake::{Handshake, AuthProvider, AuthError};
|
||||
|
||||
mod ping_pong;
|
||||
pub use ping_pong::ping_pong;
|
||||
11
polariton_auth/src/ping_pong.rs
Normal file
11
polariton_auth/src/ping_pong.rs
Normal file
@@ -0,0 +1,11 @@
|
||||
use polariton::packet::Ping;
|
||||
|
||||
#[inline]
|
||||
pub fn ping_pong(mut ping: Ping) -> Ping {
|
||||
if ping.tick2.is_some() {
|
||||
ping.tick2 = None;
|
||||
} else {
|
||||
ping.tick2 = Some(ping.tick1);
|
||||
}
|
||||
ping
|
||||
}
|
||||
12
rc_services/Cargo.toml
Normal file
12
rc_services/Cargo.toml
Normal file
@@ -0,0 +1,12 @@
|
||||
[package]
|
||||
name = "rc_services"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
log.workspace = true
|
||||
env_logger.workspace = true
|
||||
tokio = { version = "1.43", features = [ "net", "macros", "rt-multi-thread", "io-util" ] }
|
||||
clap.workspace = true
|
||||
polariton.workspace = true
|
||||
polariton_auth = { version = "*", path = "../polariton_auth" }
|
||||
3
rc_services/build_arm64.sh
Executable file
3
rc_services/build_arm64.sh
Executable file
@@ -0,0 +1,3 @@
|
||||
#!/bin/bash
|
||||
|
||||
cargo build --release --target aarch64-unknown-linux-musl
|
||||
3
rc_services/run_debug.sh
Executable file
3
rc_services/run_debug.sh
Executable file
@@ -0,0 +1,3 @@
|
||||
#!/bin/bash
|
||||
|
||||
RUST_BACKTRACE=1 RUST_LOG=debug cargo run
|
||||
31
rc_services/src/cli.rs
Normal file
31
rc_services/src/cli.rs
Normal file
@@ -0,0 +1,31 @@
|
||||
use clap::Parser;
|
||||
|
||||
#[derive(Parser, Debug)]
|
||||
#[command(version, about, long_about = None)]
|
||||
pub struct CliArgs {
|
||||
/// TCP port on which to accept connections
|
||||
#[arg(short, long, default_value_t = 4532)]
|
||||
pub port: u16,
|
||||
|
||||
/// IP Address on which to accept connections
|
||||
#[arg(long, default_value_t = {"127.0.0.1".to_string()})]
|
||||
pub ip: String,
|
||||
|
||||
/// Socket read tries before giving up (0 to never give up)
|
||||
#[arg(long, default_value_t = 5)]
|
||||
pub retries: usize,
|
||||
|
||||
/// Domain and port of the game server to send new connections
|
||||
#[arg(long, default_value_t = {"127.0.0.1:4533".to_string()})]
|
||||
pub redirect: String,
|
||||
|
||||
/// Name of game server to send new connections
|
||||
#[arg(long, default_value_t = {"ngram_is_ngnius".to_string()})]
|
||||
pub room_name: String,
|
||||
}
|
||||
|
||||
impl CliArgs {
|
||||
pub fn get() -> Self {
|
||||
Self::parse()
|
||||
}
|
||||
}
|
||||
340
rc_services/src/main.rs
Normal file
340
rc_services/src/main.rs
Normal file
@@ -0,0 +1,340 @@
|
||||
mod cli;
|
||||
mod state;
|
||||
|
||||
use std::num::NonZero;
|
||||
use std::sync::Arc;
|
||||
|
||||
use polariton_auth::Handshake;
|
||||
use tokio::io::{AsyncReadExt, AsyncWriteExt};
|
||||
use tokio::net;
|
||||
|
||||
use polariton::packet::{Cryptographer, Data, Message, Packet, Ping, StandardMessage, StandardPacket};
|
||||
use polariton::operation::{OperationResponse, Typed};
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> std::io::Result<()> {
|
||||
env_logger::init();
|
||||
let args = cli::CliArgs::get();
|
||||
log::debug!("Got cli args {:?}", args);
|
||||
let ip_addr: std::net::IpAddr = args.ip.parse().expect("Invalid IP address");
|
||||
|
||||
let listener = net::TcpListener::bind(std::net::SocketAddr::new(ip_addr, args.port)).await?;
|
||||
|
||||
loop {
|
||||
let (socket, address) = listener.accept().await?;
|
||||
process_socket(socket, address, NonZero::new(args.retries), &args.redirect, &args.room_name).await;
|
||||
}
|
||||
}
|
||||
|
||||
async fn process_socket(mut socket: net::TcpStream, address: std::net::SocketAddr, retries: Option<NonZero<usize>>, game_server_url: &str, game_server_name: &str) {
|
||||
log::debug!("Accepting connection from address {}", address);
|
||||
|
||||
let mut buf = Vec::new();
|
||||
let enc = match do_connect_handshake(&mut buf, &mut socket, retries, game_server_url, game_server_name).await {
|
||||
Some(x) => x,
|
||||
None => {
|
||||
log::error!("Failed to do connect handshake with {}", address);
|
||||
return;
|
||||
}
|
||||
};
|
||||
buf.clear();
|
||||
}
|
||||
|
||||
async fn handle_ping(ping: Ping, buf: &mut Vec<u8>, socket: &mut net::TcpStream) {
|
||||
let resp = Packet::Ping(polariton_auth::ping_pong(ping));
|
||||
resp.to_buf(buf, None).unwrap();
|
||||
let write_count = socket.write(buf).await.unwrap();
|
||||
log::debug!("(ping) Write {} bytes to socket: {:?}", write_count, buf);
|
||||
}
|
||||
|
||||
fn buf_likely_valid(buf: &[u8]) -> bool {
|
||||
buf.is_empty() || buf[0] == Packet::PING_MAGIC || buf[0] == Packet::FRAMED_MAGIC
|
||||
}
|
||||
|
||||
async fn read_more(buf: &mut Vec<u8>, socket: &mut net::TcpStream) -> Result<usize, std::io::Error> {
|
||||
let read_count = socket.read_buf(buf).await?;
|
||||
log::debug!("Read {} bytes from socket: {:?}", read_count, buf);
|
||||
Ok(read_count)
|
||||
}
|
||||
|
||||
async fn receive_packet(buf: &mut Vec<u8>, socket: &mut net::TcpStream, max_retries: Option<NonZero<usize>>, args: Option<Box<Arc<dyn Cryptographer>>>) -> Result<Packet, std::io::Error> {
|
||||
buf.clear();
|
||||
let read_count = read_more(buf, socket).await?;
|
||||
if read_count == 0 { return Err(std::io::Error::new(std::io::ErrorKind::InvalidData, "socket did not read any bytes")); } // bad packet
|
||||
let mut last_err = None;
|
||||
let mut must_succeed_next = false;
|
||||
if let Some(max_retries) = max_retries {
|
||||
for _ in 0..max_retries.get() {
|
||||
match Packet::from_buf(&buf, args.clone()) {
|
||||
Ok(packet) => {
|
||||
log::debug!("(connect) Received packet {:?}", packet);
|
||||
return Ok(packet);
|
||||
},
|
||||
Err(e) => last_err = Some(e),
|
||||
}
|
||||
if must_succeed_next {
|
||||
break;
|
||||
}
|
||||
must_succeed_next = read_more(buf, socket).await? == 0;
|
||||
}
|
||||
return Err(std::io::Error::new(std::io::ErrorKind::InvalidData, last_err.unwrap()));
|
||||
} else {
|
||||
while buf_likely_valid(buf.as_slice()) {
|
||||
match Packet::from_buf(&buf, args.clone()) {
|
||||
Ok(packet) => {
|
||||
log::debug!("(connect) Received packet {:?}", packet);
|
||||
return Ok(packet);
|
||||
},
|
||||
Err(e) => last_err = Some(e),
|
||||
}
|
||||
if must_succeed_next {
|
||||
break;
|
||||
}
|
||||
must_succeed_next = read_more(buf, socket).await? == 0;
|
||||
}
|
||||
return Err(std::io::Error::new(std::io::ErrorKind::InvalidData, last_err.unwrap()));
|
||||
}
|
||||
}
|
||||
|
||||
async fn send_packet(packet: Packet, buf: &mut Vec<u8>, socket: &mut net::TcpStream, args: Option<Box<Arc<dyn Cryptographer>>>) -> Result<(), std::io::Error> {
|
||||
log::debug!("Sending packet {:?}", packet);
|
||||
buf.clear();
|
||||
packet.to_buf(buf, args).map_err(|e| std::io::Error::new(std::io::ErrorKind::NotFound, e))?;
|
||||
let write_count = socket.write(buf).await?;
|
||||
log::debug!("Write {} bytes to socket: {:?}", write_count, buf);
|
||||
#[cfg(debug_assertions)]
|
||||
{
|
||||
// print out unencrypted packet too
|
||||
if let Packet::Packet(standard_p) = packet {
|
||||
if let Message::Standard(standard_m) = standard_p.message {
|
||||
if standard_m.is_encrypted() {
|
||||
let standard_m = standard_m.encrypt(false);
|
||||
let packet = Packet::Packet(StandardPacket { header: standard_p.header, message: Message::Standard(standard_m) });
|
||||
packet.to_buf(buf, None).map_err(|e| std::io::Error::new(std::io::ErrorKind::NotFound, e))?;
|
||||
log::debug!("Unencrypted bytes of packet: {:?} (len: {})", buf, buf.len());
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
const APP_ID: &str = "WebServicesServer";
|
||||
|
||||
struct AuthImpl;
|
||||
|
||||
const TOKEN_KEY: u8 = 216; // token;refresh_token
|
||||
//const UNKNOWN_BYTE_KEY: u8 = 217;
|
||||
const SERVICE_KEY: u8 = 224;
|
||||
const USERNAME_KEY: u8 = 225;
|
||||
|
||||
//const CCU_KEY: u8 = 245;
|
||||
|
||||
#[derive(Debug)]
|
||||
enum AuthError {
|
||||
WrongService { expected: String, actual: String },
|
||||
MissingService,
|
||||
MissingToken,
|
||||
MissingUsername,
|
||||
}
|
||||
|
||||
impl AuthError {
|
||||
fn log_err(&self) {
|
||||
match self {
|
||||
Self::WrongService { expected, actual } => log::error!("(auth fail) Got unexpected service {}, expected {}", actual, expected),
|
||||
Self::MissingService => log::error!("(auth fail) No service name param ({}) received", SERVICE_KEY),
|
||||
Self::MissingToken => log::error!("(auth fail) No token param ({}) received", TOKEN_KEY),
|
||||
Self::MissingUsername => log::error!("(auth fail) No username param ({}) received", USERNAME_KEY),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl polariton_auth::AuthProvider<AuthError> for AuthImpl {
|
||||
fn validate(&mut self, params: &std::collections::HashMap<u8, Typed>) -> Result<std::collections::HashMap<u8, Typed>, AuthError> {
|
||||
if let Some(Typed::Str(token)) = params.get(&TOKEN_KEY) {
|
||||
if let Some(Typed::Str(service)) = params.get(&SERVICE_KEY) {
|
||||
if let Some(Typed::Str(user)) = params.get(&USERNAME_KEY) {
|
||||
if service.string == APP_ID {
|
||||
let params_resp = std::collections::HashMap::<u8, Typed>::new();
|
||||
//params_resp.insert(CCU_KEY, Typed::Byte(0));
|
||||
log::debug!("Auth success for {} (token: {})", user.string, token.string);
|
||||
Ok(params_resp)
|
||||
} else { Err(AuthError::WrongService { expected: APP_ID.to_owned(), actual: service.string.to_owned() }) }
|
||||
} else { Err(AuthError::MissingUsername) }
|
||||
} else { Err(AuthError::MissingService) }
|
||||
} else { Err(AuthError::MissingToken) }
|
||||
}
|
||||
}
|
||||
|
||||
async fn do_connect_handshake(
|
||||
buf: &mut Vec<u8>,
|
||||
socket: &mut net::TcpStream,
|
||||
max_retries: Option<NonZero<usize>>,
|
||||
game_server_url: &str,
|
||||
game_server_name: &str,
|
||||
) -> Option<Box<std::sync::Arc<dyn Cryptographer>>> {
|
||||
let handshake = Handshake::new(APP_ID);
|
||||
// connect
|
||||
log::debug!("(connect) Handling first packet");
|
||||
let packet1 = match receive_packet(buf, socket, max_retries, None).await {
|
||||
Ok(x) => x,
|
||||
Err(e) => {
|
||||
log::error!("Failed to read connect packet: {}", e);
|
||||
return None;
|
||||
}
|
||||
};
|
||||
let (handshake, to_send) = match handshake.connect(&packet1) {
|
||||
Ok(x) => (x.handshake, x.extra),
|
||||
Err(e) => {
|
||||
log::error!("Failed to handle connect handshake: {:?}", e.extra);
|
||||
return None;
|
||||
}
|
||||
};
|
||||
match send_packet(to_send, buf, socket, None).await {
|
||||
Ok(_) => {},
|
||||
Err(e) => {
|
||||
log::error!("Failed to send connect ack packet: {}", e);
|
||||
return None;
|
||||
}
|
||||
}
|
||||
// encrypt
|
||||
log::debug!("(connect) Handling second packet");
|
||||
let mut packet2 = match receive_packet(buf, socket, max_retries, None).await {
|
||||
Ok(x) => x,
|
||||
Err(e) => {
|
||||
log::error!("Failed to read (maybe) public key packet: {}", e);
|
||||
return None;
|
||||
}
|
||||
};
|
||||
while let Packet::Ping(ping) = packet2 {
|
||||
handle_ping(ping, buf, socket).await;
|
||||
packet2 = match receive_packet(buf, socket, max_retries, None).await {
|
||||
Ok(x) => x,
|
||||
Err(e) => {
|
||||
log::error!("Failed to read (maybe) public key packet: {}", e);
|
||||
return None;
|
||||
}
|
||||
};
|
||||
}
|
||||
let (handshake, to_send, crypto) = match handshake.encrypt(&packet2) {
|
||||
Ok(x) => (x.handshake, x.extra.0, x.extra.1),
|
||||
Err(e) => {
|
||||
log::error!("Failed to handle encryption handshake: {:?}", e.extra);
|
||||
return None;
|
||||
}
|
||||
};
|
||||
match send_packet(to_send, buf, socket, None).await {
|
||||
Ok(_) => {},
|
||||
Err(e) => {
|
||||
log::error!("Failed to send encryption ack packet: {}", e);
|
||||
return None;
|
||||
}
|
||||
}
|
||||
// pre-auth
|
||||
let handshake = handshake.with_auth(AuthImpl);
|
||||
// authenticate
|
||||
log::debug!("(connect) Handling third packet");
|
||||
let mut packet3 = match receive_packet(buf, socket, max_retries, Some(crypto.clone())).await {
|
||||
Ok(x) => x,
|
||||
Err(e) => {
|
||||
log::error!("Failed to read (maybe) auth packet: {}", e);
|
||||
return None;
|
||||
}
|
||||
};
|
||||
while let Packet::Ping(ping) = packet3 {
|
||||
handle_ping(ping, buf, socket).await;
|
||||
packet3 = match receive_packet(buf, socket, max_retries, Some(crypto.clone())).await {
|
||||
Ok(x) => x,
|
||||
Err(e) => {
|
||||
log::error!("Failed to read (maybe) auth packet: {}", e);
|
||||
return None;
|
||||
}
|
||||
};
|
||||
}
|
||||
let to_send = match handshake.authenticate(&packet3, crypto.clone()) {
|
||||
Ok(x) => x,
|
||||
Err(h) => match h.extra {
|
||||
polariton_auth::AuthError::Validation(e) => {
|
||||
e.log_err();
|
||||
return None;
|
||||
},
|
||||
e => {
|
||||
log::error!("Failed to handle auth handshake: {:?}", e);
|
||||
return None;
|
||||
},
|
||||
},
|
||||
};
|
||||
match send_packet(to_send, buf, socket, Some(crypto.clone())).await {
|
||||
Ok(_) => {},
|
||||
Err(e) => {
|
||||
log::error!("Failed to send auth ack packet: {}", e);
|
||||
return None;
|
||||
}
|
||||
}
|
||||
|
||||
// send CCU passed event
|
||||
let ccu_passed_event = Packet::from_message(
|
||||
Message::Standard(
|
||||
StandardMessage { flags: 0,
|
||||
data: Data::Event(polariton::operation::Event {
|
||||
code: 14, // CCU passed event code for Web service
|
||||
params: std::collections::HashMap::new().into(),
|
||||
}),
|
||||
}.encrypt(true)), 0, true, Some(crypto.clone())).unwrap();
|
||||
match send_packet(ccu_passed_event, buf, socket, Some(crypto.clone())).await {
|
||||
Ok(_) => {},
|
||||
Err(e) => {
|
||||
log::error!("Failed to send CCU event packet: {}", e);
|
||||
return None;
|
||||
}
|
||||
}
|
||||
let mut packet_j = match receive_packet(buf, socket, max_retries, Some(crypto.clone())).await {
|
||||
Ok(x) => x,
|
||||
Err(e) => {
|
||||
log::error!("Failed to read (maybe) join packet: {}", e);
|
||||
return None;
|
||||
}
|
||||
};
|
||||
while let Packet::Ping(ping) = packet_j {
|
||||
handle_ping(ping, buf, socket).await;
|
||||
packet_j = match receive_packet(buf, socket, max_retries, Some(crypto.clone())).await {
|
||||
Ok(x) => x,
|
||||
Err(e) => {
|
||||
log::error!("Failed to read (maybe) join packet: {}", e);
|
||||
return None;
|
||||
}
|
||||
};
|
||||
}
|
||||
if let Packet::Packet(msg) = &packet_j {
|
||||
if let Message::Standard(st) = &msg.message {
|
||||
if let Data::OpReq(req) = &st.data {
|
||||
if req.code == 225 { // join lobby
|
||||
log::debug!("Max players from lobby join request: {:?}", req.params.to_owned().to_dict().get(&255));
|
||||
let mut params = std::collections::HashMap::<u8, Typed>::new();
|
||||
params.insert(230 /* game server address */, Typed::Str(game_server_url.into()));
|
||||
params.insert(255 /* room name */, Typed::Str(game_server_name.into()));
|
||||
let resp = Packet::from_message(
|
||||
Message::Standard(
|
||||
StandardMessage { flags: 0,
|
||||
data: Data::OpResp(OperationResponse {
|
||||
code: req.code,
|
||||
return_code: 0,
|
||||
message: Typed::Null,
|
||||
params: params.into(),
|
||||
}),
|
||||
}.encrypt(true)), 0, true, Some(crypto.clone())).unwrap();
|
||||
match send_packet(resp, buf, socket, Some(crypto.clone())).await {
|
||||
Ok(_) => {},
|
||||
Err(e) => {
|
||||
log::error!("Failed to send lobby ack packet: {}", e);
|
||||
return None;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Some(crypto)
|
||||
}
|
||||
17
rc_services/src/state.rs
Normal file
17
rc_services/src/state.rs
Normal file
@@ -0,0 +1,17 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
pub struct State {
|
||||
pub crypto: Box<Arc<dyn polariton::packet::Cryptographer>>,
|
||||
}
|
||||
|
||||
impl State {
|
||||
pub fn new(c: Box<Arc<dyn polariton::packet::Cryptographer>>) -> Self {
|
||||
Self {
|
||||
crypto: c,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn binrw_args(&self) -> polariton::packet::WriteArgs {
|
||||
Some(self.crypto.clone())
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user