Merge pull request #909 from Fate-JH/sentry20210803

Sentry Fixes
This commit is contained in:
Fate-JH 2021-08-04 22:50:57 -04:00 committed by GitHub
commit 276dcd307f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 200 additions and 31 deletions

View file

@ -23,6 +23,8 @@ import net.psforever.packet._
import net.psforever.packet.control._
import net.psforever.packet.crypto.{ClientChallengeXchg, ClientFinished, ServerChallengeXchg, ServerFinished}
import net.psforever.packet.game._
import net.psforever.packet.crypto._
import net.psforever.packet.game.{ChangeFireModeMessage, CharacterInfoMessage, KeepAliveMessage, PingMsg}
import net.psforever.packet.PacketCoding.CryptoCoding
import net.psforever.util.{Config, DiffieHellman, Md5Mac}
@ -382,7 +384,7 @@ class MiddlewareActor(
PacketCoding.unmarshalPacket(msg, None, CryptoPacketOpcode.ClientFinished) match {
case Successful(packet) =>
packet match {
case (ClientFinished(clientPubKey, _), Some(_)) =>
case (ClientFinished(_, clientPubKey, _), Some(_)) =>
serverMACBuffer ++= msg.drop(3)
val agreedKey = dh.agree(clientPubKey.toArray)
val agreedMessage = ByteVector("master secret".getBytes) ++ clientChallenge ++
@ -439,6 +441,8 @@ class MiddlewareActor(
.receiveMessage[Command] {
case Receive(msg) =>
PacketCoding.unmarshalPacket(msg, crypto) match {
case Successful((Ignore(data), _)) =>
log.info(s"caught CryptoPacket Ignore with hex - $data")
case Successful((packet, Some(sequence))) =>
activeSequenceFunc(packet, sequence)
case Successful((packet, None)) =>

View file

@ -374,7 +374,7 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con
case out @ Some(obj) if obj.HasGUID =>
out
case None if id.nonEmpty && id.get != PlanetSideGUID(0) =>
case None if !id.contains(PlanetSideGUID(0)) =>
//delete stale entity reference from client
log.error(s"${player.Name} has an invalid reference to GUID ${id.get.guid} in zone ${continent.id}")
sendResponse(ObjectDeleteMessage(id.get, 0))
@ -4873,6 +4873,7 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con
log.error(
s"telepad@${object_guid.guid} is linked to wrong kind of object - ${o.Definition.Name}, ${obj.Router}"
)
obj.Actor ! Deployable.Deconstruct()
case None => ;
}
}
@ -5427,6 +5428,7 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con
dismountWarning(
s"DismountVehicleMsg: player ${player.Name}_guid not considered seated in a mountable entity"
)
sendResponse(DismountVehicleMsg(player_guid, bailType, wasKickedByDriver))
None
}) match {
case Some(_) if serverVehicleControlVelocity.nonEmpty =>
@ -5710,6 +5712,9 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con
progressBarUpdate.cancel()
progressBarValue = None
case msg @ TradeMessage(_,_) =>
log.info(s"${player.Name} wants to trade, for some reason - $msg")
case _ =>
log.warn(s"Unhandled GamePacket $pkt")
}
@ -6362,39 +6367,42 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con
FindEquipmentStock(obj, FindAmmoBoxThatUses(requestedAmmoType), fullMagazine, CountAmmunition).reverse match {
case Nil => ;
case x :: xs =>
val (deleteFunc, modifyFunc): (Equipment => Future[Any], (AmmoBox, Int) => Unit) = obj match {
case veh: Vehicle =>
(RemoveOldEquipmentFromInventory(veh), ModifyAmmunitionInVehicle(veh))
case _ =>
(RemoveOldEquipmentFromInventory(obj), ModifyAmmunition(obj))
val modifyFunc: (AmmoBox, Int) => Unit = obj match {
case veh: Vehicle => ModifyAmmunitionInVehicle(veh)
case _ => ModifyAmmunition(obj)
}
val (stowNewFunc, stowFunc): (Equipment => TaskResolver.GiveTask, Equipment => Future[Any]) =
(PutNewEquipmentInInventoryOrDrop(obj), PutEquipmentInInventoryOrDrop(obj))
val stowNewFunc: Equipment => TaskResolver.GiveTask = PutNewEquipmentInInventoryOrDrop(obj)
val stowFunc: Equipment => Future[Any] = PutEquipmentInInventoryOrDrop(obj)
xs.foreach(item => {
obj.Inventory -= x.start
deleteFunc(item.obj)
obj.Inventory -= item.start
sendResponse(ObjectDeleteMessage(item.obj.GUID, 0))
continent.tasks ! GUIDTask.UnregisterObjectTask(item.obj)(continent.GUID)
})
//box will be the replacement ammo; give it the discovered magazine and load it into the weapon @ 0
//box will be the replacement ammo; give it the discovered magazine and load it into the weapon
val box = x.obj.asInstanceOf[AmmoBox]
//previousBox is the current magazine in tool; it will be removed from the weapon
val previousBox = tool.AmmoSlot.Box
val originalBoxCapacity = box.Capacity
val tailReloadValue: Int = if (xs.isEmpty) { 0 }
else { xs.map(_.obj.asInstanceOf[AmmoBox].Capacity).sum }
val tailReloadValue: Int = if (xs.isEmpty) {
0
} else {
xs.map(_.obj.asInstanceOf[AmmoBox].Capacity).sum
}
val sumReloadValue: Int = originalBoxCapacity + tailReloadValue
val previousBox = tool.AmmoSlot.Box //current magazine in tool
sendResponse(ObjectDetachMessage(tool.GUID, previousBox.GUID, Vector3.Zero, 0f))
sendResponse(ObjectDetachMessage(player.GUID, box.GUID, Vector3.Zero, 0f))
val ammoSlotIndex = tool.FireMode.AmmoSlotIndex
val box_guid = box.GUID
val tool_guid = tool.GUID
obj.Inventory -= x.start //remove replacement ammo from inventory
val ammoSlotIndex = tool.FireMode.AmmoSlotIndex
tool.AmmoSlots(ammoSlotIndex).Box = box //put replacement ammo in tool
sendResponse(ObjectAttachMessage(tool.GUID, box.GUID, ammoSlotIndex))
sendResponse(ObjectDetachMessage(tool_guid, previousBox.GUID, Vector3.Zero, 0f))
sendResponse(ObjectDetachMessage(obj.GUID, box_guid, Vector3.Zero, 0f))
sendResponse(ObjectAttachMessage(tool_guid, box_guid, ammoSlotIndex))
//announce swapped ammunition box in weapon
val previous_box_guid = previousBox.GUID
val boxDef = box.Definition
val box_guid = box.GUID
val tool_guid = tool.GUID
sendResponse(ChangeAmmoMessage(tool_guid, box.Capacity))
continent.AvatarEvents ! AvatarServiceMessage(
continent.id,

View file

@ -277,7 +277,7 @@ class Player(var avatar: Avatar)
None
} else {
val slot = iter.next()
if (slot.Equipment.isDefined && slot.Equipment.get.GUID == guid) {
if (slot.Equipment match { case Some(o) => o.GUID == guid; case _ => false }) {
Some(index)
} else {
findInHolsters(iter, guid, index + 1)

View file

@ -167,9 +167,10 @@ class TelepadControl(obj: InternalTelepad) extends akka.actor.Actor {
obj.Active = false
val zone = obj.Zone
zone.GUID(obj.Telepad) match {
case Some(oldTpad: TelepadDeployable) if !obj.Active && !setup.isCancelled =>
case Some(oldTpad: TelepadDeployable)
if !obj.Active && !setup.isCancelled =>
oldTpad.Actor ! TelepadLike.SeverLink(obj)
case None => ;
case _ => ;
}
obj.Telepad = None
zone.LocalEvents ! LocalServiceMessage(zone.id, LocalAction.SendResponse(ObjectDeleteMessage(obj.GUID, 0)))

View file

@ -8,8 +8,9 @@ object CryptoPacketOpcode extends Enumeration {
type Type = Value
val Ignore, ClientChallengeXchg, ServerChallengeXchg, ClientFinished, ServerFinished = Value
def getPacketDecoder(opcode: CryptoPacketOpcode.Type): (BitVector) => Attempt[DecodeResult[PlanetSideCryptoPacket]] =
def getPacketDecoder(opcode: CryptoPacketOpcode.Type): BitVector => Attempt[DecodeResult[PlanetSideCryptoPacket]] =
opcode match {
case Ignore => crypto.Ignore.decode
case ClientChallengeXchg => crypto.ClientChallengeXchg.decode
case ServerChallengeXchg => crypto.ServerChallengeXchg.decode
case ServerFinished => crypto.ServerFinished.decode
@ -17,7 +18,7 @@ object CryptoPacketOpcode extends Enumeration {
case default =>
(a: BitVector) =>
Attempt.failure(
Err(s"Could not find a marshaller for crypto packet ${opcode}")
Err(s"Could not find a marshaller for crypto packet $opcode")
.pushContext("get_marshaller")
)
}

View file

@ -446,7 +446,7 @@ object GamePacketOpcode extends Enumeration {
case 0x77 => game.SquadState.decode
// 0x78
case 0x78 => game.OxygenStateMessage.decode
case 0x79 => noDecoder(TradeMessage)
case 0x79 => game.TradeMessage.decode
case 0x7a => noDecoder(UnknownMessage122)
case 0x7b => game.DamageFeedbackMessage.decode
case 0x7c => game.DismountBuildingMsg.decode

View file

@ -2,22 +2,43 @@
package net.psforever.packet.crypto
import net.psforever.packet.{CryptoPacketOpcode, Marshallable, PlanetSideCryptoPacket}
import scodec.Attempt.Successful
import scodec.Codec
import scodec.bits.{ByteVector, _}
import scodec.codecs._
import shapeless.{::, HNil}
final case class ClientFinished(pubKey: ByteVector, challengeResult: ByteVector) extends PlanetSideCryptoPacket {
final case class ClientFinished(
obj_type: Int,
pubKey: ByteVector,
challengeResult: ByteVector
) extends PlanetSideCryptoPacket {
type Packet = ClientFinished
def opcode = CryptoPacketOpcode.ClientFinished
def encode = ClientFinished.encode(this)
}
object ClientFinished extends Marshallable[ClientFinished] {
def apply(pubKey: ByteVector, challengeResult: ByteVector): ClientFinished =
ClientFinished(16, pubKey, challengeResult)
implicit val codec: Codec[ClientFinished] = (
("obj_type?" | constant(hex"10".bits)) ::
("obj_type?" | uint8) ::
("pub_key_len" | constant(hex"1000")) ::
("pub_key" | bytes(16)) ::
("unknown" | constant(hex"0114".bits)) ::
("challenge_result" | bytes(0xc))
).as[ClientFinished]
).exmap[ClientFinished](
{
case 16 :: () :: c :: () :: e :: HNil =>
Successful(ClientFinished(16, c, e))
case a :: () :: c :: () :: e :: HNil =>
org.log4s.getLogger("ClientFinished").warn(s"obj_type?: expected 16 but got $a; attempting to bypass")
Successful(ClientFinished(a, c, e))
},
{
case ClientFinished(a, c, e) =>
Successful(a :: () :: c :: () :: e :: HNil)
}
)
}

View file

@ -0,0 +1,18 @@
// Copyright (c) 2021 PSForever
package net.psforever.packet.crypto
import net.psforever.packet.{CryptoPacketOpcode, Marshallable, PlanetSideCryptoPacket}
import scodec.Codec
import scodec.bits.ByteVector
import scodec.codecs._
final case class Ignore(data: ByteVector) extends PlanetSideCryptoPacket {
type Packet = Ignore
def opcode = CryptoPacketOpcode.Ignore
def encode = Ignore.encode(this)
}
object Ignore extends Marshallable[Ignore] {
implicit val codec: Codec[Ignore] = ("data" | bytes).as[Ignore]
}

View file

@ -0,0 +1,111 @@
// Copyright (c) 2021 PSForever
package net.psforever.packet.game
import net.psforever.packet.{GamePacketOpcode, Marshallable, PlanetSideGamePacket}
import net.psforever.types.PlanetSideGUID
import scodec.Codec
import scodec.codecs._
import shapeless.{::, HNil}
sealed trait Trade {
def value: Int
}
final case class NoTrade(value: Int) extends Trade {
assert(value == 1 || value == 2 || value == 3, s"NoTrade has wrong code value - $value not in [a-f]")
}
final case class TradeOne(value: Int, unk1: PlanetSideGUID, unk2: PlanetSideGUID, unk3: PlanetSideGUID) extends Trade {
assert(value == 1 || value == 2 || value == 3, s"TradeOne has wrong code value - $value not in [1,2,3]")
}
final case class TradeTwo(value: Int, unk1: PlanetSideGUID, unk2: PlanetSideGUID) extends Trade {
assert(value == 4 || value == 5 || value == 7, s"TradeTwo has wrong code value - $value not in [4,5,7]")
}
final case class TradeThree(value: Int, unk: PlanetSideGUID) extends Trade {
assert(value == 6 || value == 8, s"TradeThree has wrong code value - $value not in [6,8]")
}
final case class TradeFour(value: Int, unk: Int) extends Trade {
assert(value == 9, s"TradeFour has wrong code value - $value not in [9]")
}
final case class TradeMessage(unk: Int, trade: Trade)
extends PlanetSideGamePacket {
type Packet = TradeMessage
def opcode = GamePacketOpcode.TradeMessage
def encode = TradeMessage.encode(this)
}
object TradeMessage extends Marshallable[TradeMessage] {
private def tradeOneCodec(value: Int): Codec[TradeOne] = (
("u1" | PlanetSideGUID.codec) ::
("u2" | PlanetSideGUID.codec) ::
("u3" | PlanetSideGUID.codec)
).xmap[TradeOne](
{
case a :: b :: c :: HNil => TradeOne(value, a, b, c)
},
{
case TradeOne(_, a, b, c) => a :: b :: c :: HNil
}
)
private def tradeTwoCodec(value: Int): Codec[TradeTwo] = (
("u1" | PlanetSideGUID.codec) ::
("u2" | PlanetSideGUID.codec)
).xmap[TradeTwo](
{
case a :: b :: HNil => TradeTwo(value, a, b)
},
{
case TradeTwo(_, a, b) => a :: b :: HNil
}
)
private def tradeThreeCodec(value: Int): Codec[TradeThree] = ("u1" | PlanetSideGUID.codec).xmap[TradeThree](
a => TradeThree(value, a),
{
case TradeThree(_, a) => a
}
)
private def tradeFourCodec(value: Int): Codec[TradeFour] = ("u1" | uint4).xmap[TradeFour](
a => TradeFour(value, a),
{
case TradeFour(_, a) => a
}
)
private def noTradeCodec(value: Int): Codec[NoTrade] = conditional(included = false, ignore(size = 1)).xmap[NoTrade](
_ => NoTrade(value),
{
case NoTrade(_) => None
}
)
private def selectTradeCodec(code: Int): Codec[Trade] = {
(code match {
case 1 | 2 | 3 => tradeOneCodec(code)
case 4 | 5 | 7 => tradeTwoCodec(code)
case 6 | 8 => tradeThreeCodec(code)
case 9 => tradeFourCodec(code)
case _ => noTradeCodec(code)
}).asInstanceOf[Codec[Trade]]
}
implicit val codec: Codec[TradeMessage] = (
("unk" | uint8) ::
(uint4 >>:~ { code =>
("trade" | selectTradeCodec(code)).hlist
})
).xmap[TradeMessage](
{
case unk :: _ :: trade :: HNil => TradeMessage(unk, trade)
},
{
case TradeMessage(unk, trade) => unk :: trade.value :: trade :: HNil
}
)
}

View file

@ -2067,7 +2067,12 @@ class SquadService extends Actor {
case (Some((fromMember, fromPosition)), (toMember, _)) if fromPosition != 0 =>
val name = fromMember.Name
SwapMemberPosition(toMember, fromMember)
Publish(squadFeatures(guid).ToChannel, SquadResponse.AssignMember(squad, fromPosition, position))
squadFeatures.get(guid) match {
case Some(features) =>
Publish(features.ToChannel, SquadResponse.AssignMember(squad, fromPosition, position))
case None =>
//we might be in trouble; we might not ...
}
UpdateSquadDetail(
squad.GUID,
SquadDetail().Members(