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.control._
import net.psforever.packet.crypto.{ClientChallengeXchg, ClientFinished, ServerChallengeXchg, ServerFinished} import net.psforever.packet.crypto.{ClientChallengeXchg, ClientFinished, ServerChallengeXchg, ServerFinished}
import net.psforever.packet.game._ 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.packet.PacketCoding.CryptoCoding
import net.psforever.util.{Config, DiffieHellman, Md5Mac} import net.psforever.util.{Config, DiffieHellman, Md5Mac}
@ -382,7 +384,7 @@ class MiddlewareActor(
PacketCoding.unmarshalPacket(msg, None, CryptoPacketOpcode.ClientFinished) match { PacketCoding.unmarshalPacket(msg, None, CryptoPacketOpcode.ClientFinished) match {
case Successful(packet) => case Successful(packet) =>
packet match { packet match {
case (ClientFinished(clientPubKey, _), Some(_)) => case (ClientFinished(_, clientPubKey, _), Some(_)) =>
serverMACBuffer ++= msg.drop(3) serverMACBuffer ++= msg.drop(3)
val agreedKey = dh.agree(clientPubKey.toArray) val agreedKey = dh.agree(clientPubKey.toArray)
val agreedMessage = ByteVector("master secret".getBytes) ++ clientChallenge ++ val agreedMessage = ByteVector("master secret".getBytes) ++ clientChallenge ++
@ -439,6 +441,8 @@ class MiddlewareActor(
.receiveMessage[Command] { .receiveMessage[Command] {
case Receive(msg) => case Receive(msg) =>
PacketCoding.unmarshalPacket(msg, crypto) match { PacketCoding.unmarshalPacket(msg, crypto) match {
case Successful((Ignore(data), _)) =>
log.info(s"caught CryptoPacket Ignore with hex - $data")
case Successful((packet, Some(sequence))) => case Successful((packet, Some(sequence))) =>
activeSequenceFunc(packet, sequence) activeSequenceFunc(packet, sequence)
case Successful((packet, None)) => 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 => case out @ Some(obj) if obj.HasGUID =>
out out
case None if id.nonEmpty && id.get != PlanetSideGUID(0) => case None if !id.contains(PlanetSideGUID(0)) =>
//delete stale entity reference from client //delete stale entity reference from client
log.error(s"${player.Name} has an invalid reference to GUID ${id.get.guid} in zone ${continent.id}") log.error(s"${player.Name} has an invalid reference to GUID ${id.get.guid} in zone ${continent.id}")
sendResponse(ObjectDeleteMessage(id.get, 0)) sendResponse(ObjectDeleteMessage(id.get, 0))
@ -4873,6 +4873,7 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con
log.error( log.error(
s"telepad@${object_guid.guid} is linked to wrong kind of object - ${o.Definition.Name}, ${obj.Router}" s"telepad@${object_guid.guid} is linked to wrong kind of object - ${o.Definition.Name}, ${obj.Router}"
) )
obj.Actor ! Deployable.Deconstruct()
case None => ; case None => ;
} }
} }
@ -5427,6 +5428,7 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con
dismountWarning( dismountWarning(
s"DismountVehicleMsg: player ${player.Name}_guid not considered seated in a mountable entity" s"DismountVehicleMsg: player ${player.Name}_guid not considered seated in a mountable entity"
) )
sendResponse(DismountVehicleMsg(player_guid, bailType, wasKickedByDriver))
None None
}) match { }) match {
case Some(_) if serverVehicleControlVelocity.nonEmpty => case Some(_) if serverVehicleControlVelocity.nonEmpty =>
@ -5710,6 +5712,9 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con
progressBarUpdate.cancel() progressBarUpdate.cancel()
progressBarValue = None progressBarValue = None
case msg @ TradeMessage(_,_) =>
log.info(s"${player.Name} wants to trade, for some reason - $msg")
case _ => case _ =>
log.warn(s"Unhandled GamePacket $pkt") 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 { FindEquipmentStock(obj, FindAmmoBoxThatUses(requestedAmmoType), fullMagazine, CountAmmunition).reverse match {
case Nil => ; case Nil => ;
case x :: xs => case x :: xs =>
val (deleteFunc, modifyFunc): (Equipment => Future[Any], (AmmoBox, Int) => Unit) = obj match { val modifyFunc: (AmmoBox, Int) => Unit = obj match {
case veh: Vehicle => case veh: Vehicle => ModifyAmmunitionInVehicle(veh)
(RemoveOldEquipmentFromInventory(veh), ModifyAmmunitionInVehicle(veh)) case _ => ModifyAmmunition(obj)
case _ =>
(RemoveOldEquipmentFromInventory(obj), ModifyAmmunition(obj))
} }
val (stowNewFunc, stowFunc): (Equipment => TaskResolver.GiveTask, Equipment => Future[Any]) = val stowNewFunc: Equipment => TaskResolver.GiveTask = PutNewEquipmentInInventoryOrDrop(obj)
(PutNewEquipmentInInventoryOrDrop(obj), PutEquipmentInInventoryOrDrop(obj)) val stowFunc: Equipment => Future[Any] = PutEquipmentInInventoryOrDrop(obj)
xs.foreach(item => { xs.foreach(item => {
obj.Inventory -= x.start obj.Inventory -= item.start
deleteFunc(item.obj) 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] 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 originalBoxCapacity = box.Capacity
val tailReloadValue: Int = if (xs.isEmpty) { 0 } val tailReloadValue: Int = if (xs.isEmpty) {
else { xs.map(_.obj.asInstanceOf[AmmoBox].Capacity).sum } 0
} else {
xs.map(_.obj.asInstanceOf[AmmoBox].Capacity).sum
}
val sumReloadValue: Int = originalBoxCapacity + tailReloadValue val sumReloadValue: Int = originalBoxCapacity + tailReloadValue
val previousBox = tool.AmmoSlot.Box //current magazine in tool val ammoSlotIndex = tool.FireMode.AmmoSlotIndex
sendResponse(ObjectDetachMessage(tool.GUID, previousBox.GUID, Vector3.Zero, 0f)) val box_guid = box.GUID
sendResponse(ObjectDetachMessage(player.GUID, box.GUID, Vector3.Zero, 0f)) val tool_guid = tool.GUID
obj.Inventory -= x.start //remove replacement ammo from inventory obj.Inventory -= x.start //remove replacement ammo from inventory
val ammoSlotIndex = tool.FireMode.AmmoSlotIndex
tool.AmmoSlots(ammoSlotIndex).Box = box //put replacement ammo in tool 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 //announce swapped ammunition box in weapon
val previous_box_guid = previousBox.GUID val previous_box_guid = previousBox.GUID
val boxDef = box.Definition val boxDef = box.Definition
val box_guid = box.GUID
val tool_guid = tool.GUID
sendResponse(ChangeAmmoMessage(tool_guid, box.Capacity)) sendResponse(ChangeAmmoMessage(tool_guid, box.Capacity))
continent.AvatarEvents ! AvatarServiceMessage( continent.AvatarEvents ! AvatarServiceMessage(
continent.id, continent.id,

View file

@ -277,7 +277,7 @@ class Player(var avatar: Avatar)
None None
} else { } else {
val slot = iter.next() 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) Some(index)
} else { } else {
findInHolsters(iter, guid, index + 1) findInHolsters(iter, guid, index + 1)

View file

@ -167,9 +167,10 @@ class TelepadControl(obj: InternalTelepad) extends akka.actor.Actor {
obj.Active = false obj.Active = false
val zone = obj.Zone val zone = obj.Zone
zone.GUID(obj.Telepad) match { 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) oldTpad.Actor ! TelepadLike.SeverLink(obj)
case None => ; case _ => ;
} }
obj.Telepad = None obj.Telepad = None
zone.LocalEvents ! LocalServiceMessage(zone.id, LocalAction.SendResponse(ObjectDeleteMessage(obj.GUID, 0))) zone.LocalEvents ! LocalServiceMessage(zone.id, LocalAction.SendResponse(ObjectDeleteMessage(obj.GUID, 0)))

View file

@ -8,8 +8,9 @@ object CryptoPacketOpcode extends Enumeration {
type Type = Value type Type = Value
val Ignore, ClientChallengeXchg, ServerChallengeXchg, ClientFinished, ServerFinished = 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 { opcode match {
case Ignore => crypto.Ignore.decode
case ClientChallengeXchg => crypto.ClientChallengeXchg.decode case ClientChallengeXchg => crypto.ClientChallengeXchg.decode
case ServerChallengeXchg => crypto.ServerChallengeXchg.decode case ServerChallengeXchg => crypto.ServerChallengeXchg.decode
case ServerFinished => crypto.ServerFinished.decode case ServerFinished => crypto.ServerFinished.decode
@ -17,7 +18,7 @@ object CryptoPacketOpcode extends Enumeration {
case default => case default =>
(a: BitVector) => (a: BitVector) =>
Attempt.failure( 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") .pushContext("get_marshaller")
) )
} }

View file

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

View file

@ -2,22 +2,43 @@
package net.psforever.packet.crypto package net.psforever.packet.crypto
import net.psforever.packet.{CryptoPacketOpcode, Marshallable, PlanetSideCryptoPacket} import net.psforever.packet.{CryptoPacketOpcode, Marshallable, PlanetSideCryptoPacket}
import scodec.Attempt.Successful
import scodec.Codec import scodec.Codec
import scodec.bits.{ByteVector, _} import scodec.bits.{ByteVector, _}
import scodec.codecs._ 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 type Packet = ClientFinished
def opcode = CryptoPacketOpcode.ClientFinished def opcode = CryptoPacketOpcode.ClientFinished
def encode = ClientFinished.encode(this) def encode = ClientFinished.encode(this)
} }
object ClientFinished extends Marshallable[ClientFinished] { object ClientFinished extends Marshallable[ClientFinished] {
def apply(pubKey: ByteVector, challengeResult: ByteVector): ClientFinished =
ClientFinished(16, pubKey, challengeResult)
implicit val codec: Codec[ClientFinished] = ( implicit val codec: Codec[ClientFinished] = (
("obj_type?" | constant(hex"10".bits)) :: ("obj_type?" | uint8) ::
("pub_key_len" | constant(hex"1000")) :: ("pub_key_len" | constant(hex"1000")) ::
("pub_key" | bytes(16)) :: ("pub_key" | bytes(16)) ::
("unknown" | constant(hex"0114".bits)) :: ("unknown" | constant(hex"0114".bits)) ::
("challenge_result" | bytes(0xc)) ("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 => case (Some((fromMember, fromPosition)), (toMember, _)) if fromPosition != 0 =>
val name = fromMember.Name val name = fromMember.Name
SwapMemberPosition(toMember, fromMember) 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( UpdateSquadDetail(
squad.GUID, squad.GUID,
SquadDetail().Members( SquadDetail().Members(