mirror of
https://github.com/2revoemag/PSF-BotServer.git
synced 2026-07-15 08:24:39 +00:00
encode and decode of only known packet of the ResetSequence type (#752)
This commit is contained in:
parent
41b3eb5f66
commit
b548260257
6 changed files with 92 additions and 9 deletions
|
|
@ -1,7 +1,7 @@
|
||||||
package net.psforever.actors.net
|
package net.psforever.actors.net
|
||||||
|
|
||||||
import akka.actor.Cancellable
|
import akka.actor.Cancellable
|
||||||
import akka.actor.typed.{ActorRef, ActorTags, Behavior, PostStop, Signal}
|
import akka.actor.typed._
|
||||||
import akka.actor.typed.scaladsl.{ActorContext, Behaviors}
|
import akka.actor.typed.scaladsl.{ActorContext, Behaviors}
|
||||||
import akka.io.Udp
|
import akka.io.Udp
|
||||||
import java.net.InetSocketAddress
|
import java.net.InetSocketAddress
|
||||||
|
|
@ -19,8 +19,8 @@ import scodec.Attempt.{Failure, Successful}
|
||||||
import scodec.bits.{BitVector, ByteVector, HexStringSyntax}
|
import scodec.bits.{BitVector, ByteVector, HexStringSyntax}
|
||||||
import scodec.interop.akka.EnrichedByteVector
|
import scodec.interop.akka.EnrichedByteVector
|
||||||
import net.psforever.objects.Default
|
import net.psforever.objects.Default
|
||||||
import net.psforever.packet.{CryptoPacketOpcode, PacketCoding, PlanetSideControlPacket, PlanetSideCryptoPacket, PlanetSideGamePacket, PlanetSidePacket}
|
import net.psforever.packet._
|
||||||
import net.psforever.packet.control.{ClientStart, ConnectionClose, ControlSync, ControlSyncResp, HandleGamePacket, MultiPacket, MultiPacketEx, RelatedA, RelatedB, ServerStart, SlottedMetaPacket, TeardownConnection}
|
import net.psforever.packet.control._
|
||||||
import net.psforever.packet.crypto.{ClientChallengeXchg, ClientFinished, ServerChallengeXchg, ServerFinished}
|
import net.psforever.packet.crypto.{ClientChallengeXchg, ClientFinished, ServerChallengeXchg, ServerFinished}
|
||||||
import net.psforever.packet.game.{ChangeFireModeMessage, CharacterInfoMessage, KeepAliveMessage, PingMsg}
|
import net.psforever.packet.game.{ChangeFireModeMessage, CharacterInfoMessage, KeepAliveMessage, PingMsg}
|
||||||
import net.psforever.packet.PacketCoding.CryptoCoding
|
import net.psforever.packet.PacketCoding.CryptoCoding
|
||||||
|
|
@ -522,8 +522,9 @@ class MiddlewareActor(
|
||||||
log.error(s"Unexpected crypto packet '$packet'")
|
log.error(s"Unexpected crypto packet '$packet'")
|
||||||
Behaviors.same
|
Behaviors.same
|
||||||
|
|
||||||
case packet =>
|
case _: PlanetSideResetSequencePacket =>
|
||||||
log.error(s"Unexpected type of packet '$packet'")
|
log.debug("Received sequence reset request from client; complying")
|
||||||
|
outSequence = 0
|
||||||
Behaviors.same
|
Behaviors.same
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -40,7 +40,9 @@ trait PlanetSideCryptoPacket extends PlanetSidePacket {
|
||||||
}
|
}
|
||||||
|
|
||||||
/** PlanetSide ResetSequence packets: self-contained? */
|
/** PlanetSide ResetSequence packets: self-contained? */
|
||||||
trait PlanetSideResetSequencePacket extends PlanetSidePacket { }
|
trait PlanetSideResetSequencePacket extends PlanetSidePacket {
|
||||||
|
def opcode: ResetSequenceOpcode.Type
|
||||||
|
}
|
||||||
|
|
||||||
/** PlanetSide packet type. Used in more complicated packet headers
|
/** PlanetSide packet type. Used in more complicated packet headers
|
||||||
*
|
*
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ import java.security.{Key, Security}
|
||||||
|
|
||||||
import javax.crypto.Cipher
|
import javax.crypto.Cipher
|
||||||
import javax.crypto.spec.RC5ParameterSpec
|
import javax.crypto.spec.RC5ParameterSpec
|
||||||
|
import net.psforever.packet.reset.ResetSequence
|
||||||
import scodec.Attempt.{Failure, Successful}
|
import scodec.Attempt.{Failure, Successful}
|
||||||
import scodec.bits._
|
import scodec.bits._
|
||||||
import scodec.{Attempt, Codec, DecodeResult, Err}
|
import scodec.{Attempt, Codec, DecodeResult, Err}
|
||||||
|
|
@ -118,6 +119,13 @@ object PacketCoding {
|
||||||
case Successful(opcode) => Successful(opcode ++ payload)
|
case Successful(opcode) => Successful(opcode ++ payload)
|
||||||
case f @ Failure(_) => f
|
case f @ Failure(_) => f
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case packet: PlanetSideResetSequencePacket =>
|
||||||
|
ResetSequenceOpcode.codec.encode(packet.opcode) match {
|
||||||
|
case Successful(opcode) => Successful(opcode)
|
||||||
|
case f @ Failure(_) => f
|
||||||
|
}
|
||||||
|
|
||||||
case _ =>
|
case _ =>
|
||||||
Failure(Err("packet not supported"))
|
Failure(Err("packet not supported"))
|
||||||
}
|
}
|
||||||
|
|
@ -208,8 +216,11 @@ object PacketCoding {
|
||||||
case (PacketType.Normal, None) =>
|
case (PacketType.Normal, None) =>
|
||||||
Failure(Err("Cannot unmarshal encrypted packet without a cipher"))
|
Failure(Err("Cannot unmarshal encrypted packet without a cipher"))
|
||||||
case (PacketType.ResetSequence, Some(_crypto)) =>
|
case (PacketType.ResetSequence, Some(_crypto)) =>
|
||||||
val test = _crypto.decrypt(payload.drop(1))
|
_crypto.decrypt(payload.drop(1)) match {
|
||||||
Failure(Err(s"ResetSequence not completely supported, but: $flags, $sequence, and $payload; decrypt: $test"))
|
case Successful(p) if p == hex"01" => Successful((ResetSequence(), sequence))
|
||||||
|
case Successful(p) => Failure(Err(s"ResetSequence decrypted to unsupported value - $p"))
|
||||||
|
case _ => Failure(Err(s"ResetSequence did not decrypt properly"))
|
||||||
|
}
|
||||||
case (ptype, _) =>
|
case (ptype, _) =>
|
||||||
Failure(Err(s"Cannot unmarshal $ptype packet at all"))
|
Failure(Err(s"Cannot unmarshal $ptype packet at all"))
|
||||||
}
|
}
|
||||||
|
|
@ -243,9 +254,12 @@ object PacketCoding {
|
||||||
GamePacketOpcode.codec.decode(msg.bits) match {
|
GamePacketOpcode.codec.decode(msg.bits) match {
|
||||||
case Successful(opcode) =>
|
case Successful(opcode) =>
|
||||||
GamePacketOpcode.getPacketDecoder(opcode.value)(opcode.remainder) match {
|
GamePacketOpcode.getPacketDecoder(opcode.value)(opcode.remainder) match {
|
||||||
|
case Failure(_) if opcode.value.id == 1 =>
|
||||||
|
Successful(ResetSequence())
|
||||||
case Failure(e) =>
|
case Failure(e) =>
|
||||||
Failure(Err(f"Failed to parse game packet 0x${opcode.value.id}%02x: " + e.messageWithContext))
|
Failure(Err(f"Failed to parse game packet 0x${opcode.value.id}%02x: " + e.messageWithContext))
|
||||||
case Successful(p) => Successful(p.value)
|
case Successful(p) =>
|
||||||
|
Successful(p.value)
|
||||||
}
|
}
|
||||||
case Failure(e) => Failure(Err("Failed to decode game packet's opcode: " + e.message))
|
case Failure(e) => Failure(Err("Failed to decode game packet's opcode: " + e.message))
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,24 @@
|
||||||
|
// Copyright (c) 2020 PSForever
|
||||||
|
package net.psforever.packet
|
||||||
|
|
||||||
|
import scodec.bits.BitVector
|
||||||
|
import scodec.{Attempt, Codec, DecodeResult, Err}
|
||||||
|
import scodec.codecs.uint8L
|
||||||
|
|
||||||
|
object ResetSequenceOpcode extends Enumeration(1) {
|
||||||
|
type Type = Value
|
||||||
|
val ResetSequence = Value
|
||||||
|
|
||||||
|
def getPacketDecoder(opcode: ResetSequenceOpcode.Type): BitVector => Attempt[DecodeResult[PlanetSideResetSequencePacket]] =
|
||||||
|
opcode match {
|
||||||
|
case ResetSequence => reset.ResetSequence.decode
|
||||||
|
case _ =>
|
||||||
|
(_: BitVector) =>
|
||||||
|
Attempt.failure(
|
||||||
|
Err(s"Could not find a marshaller for reset sequence packet $opcode")
|
||||||
|
.pushContext("get_marshaller")
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
implicit val codec: Codec[this.Value] = PacketHelpers.createEnumerationCodec(this, uint8L)
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,17 @@
|
||||||
|
// Copyright (c) 2020 PSForever
|
||||||
|
package net.psforever.packet.reset
|
||||||
|
|
||||||
|
import net.psforever.packet.{Marshallable, PacketHelpers, PlanetSideResetSequencePacket, ResetSequenceOpcode}
|
||||||
|
import scodec.{Attempt, Codec}
|
||||||
|
import scodec.bits.BitVector
|
||||||
|
|
||||||
|
final case class ResetSequence()
|
||||||
|
extends PlanetSideResetSequencePacket {
|
||||||
|
type Packet = ResetSequence
|
||||||
|
def opcode: ResetSequenceOpcode.Type = ResetSequenceOpcode.ResetSequence
|
||||||
|
def encode: Attempt[BitVector] = ResetSequence.encode(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
object ResetSequence extends Marshallable[ResetSequence] {
|
||||||
|
implicit val codec: Codec[ResetSequence] = PacketHelpers.emptyCodec[ResetSequence](ResetSequence())
|
||||||
|
}
|
||||||
25
src/test/scala/reset/ResetSequenceTest.scala
Normal file
25
src/test/scala/reset/ResetSequenceTest.scala
Normal file
|
|
@ -0,0 +1,25 @@
|
||||||
|
// Copyright (c) 2021 PSForever
|
||||||
|
package reset
|
||||||
|
|
||||||
|
import net.psforever.packet._
|
||||||
|
import net.psforever.packet.reset.ResetSequence
|
||||||
|
import org.specs2.mutable._
|
||||||
|
import scodec.bits._
|
||||||
|
|
||||||
|
class ResetSequenceTest extends Specification {
|
||||||
|
val string = hex"01"
|
||||||
|
|
||||||
|
"decode" in {
|
||||||
|
PacketCoding.decodePacket(string).require match {
|
||||||
|
case ResetSequence() => ok
|
||||||
|
case _ => ko
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
"encode" in {
|
||||||
|
val msg = ResetSequence()
|
||||||
|
val pkt = PacketCoding.encodePacket(msg).require.toByteVector
|
||||||
|
|
||||||
|
pkt mustEqual string
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue