mirror of
https://github.com/2revoemag/PSF-BotServer.git
synced 2026-07-14 07:55:07 +00:00
Fix thread safety issues
* Synchronize RC5 cipher access * Replace avatar using message to self in AvatarActor
This commit is contained in:
parent
2f0c6d98fd
commit
4c1b9a64d3
6 changed files with 25 additions and 25 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -13,6 +13,7 @@ out/
|
||||||
project/metals.sbt
|
project/metals.sbt
|
||||||
/docs
|
/docs
|
||||||
.vscode
|
.vscode
|
||||||
|
.bsp
|
||||||
|
|
||||||
# User configs
|
# User configs
|
||||||
config/psforever.conf
|
config/psforever.conf
|
||||||
|
|
|
||||||
|
|
@ -1 +1 @@
|
||||||
sbt.version = 1.3.13
|
sbt.version = 1.4.5
|
||||||
|
|
|
||||||
|
|
@ -166,6 +166,7 @@ class MiddlewareActor(
|
||||||
val queueProcessor: Cancellable = {
|
val queueProcessor: Cancellable = {
|
||||||
context.system.scheduler.scheduleWithFixedDelay(10.milliseconds, 10.milliseconds)(() => {
|
context.system.scheduler.scheduleWithFixedDelay(10.milliseconds, 10.milliseconds)(() => {
|
||||||
try {
|
try {
|
||||||
|
|
||||||
if (outQueue.nonEmpty && outQueueBundled.isEmpty) {
|
if (outQueue.nonEmpty && outQueueBundled.isEmpty) {
|
||||||
var length = 0L
|
var length = 0L
|
||||||
val bundle = outQueue
|
val bundle = outQueue
|
||||||
|
|
|
||||||
|
|
@ -407,6 +407,10 @@ class AvatarActor(
|
||||||
|
|
||||||
case ReplaceAvatar(newAvatar) =>
|
case ReplaceAvatar(newAvatar) =>
|
||||||
avatar = newAvatar
|
avatar = newAvatar
|
||||||
|
avatar.deployables.UpdateMaxCounts(avatar.certifications)
|
||||||
|
updateDeployableUIElements(
|
||||||
|
avatar.deployables.UpdateUI()
|
||||||
|
)
|
||||||
Behaviors.same
|
Behaviors.same
|
||||||
|
|
||||||
case AddFirstTimeEvent(event) =>
|
case AddFirstTimeEvent(event) =>
|
||||||
|
|
@ -461,15 +465,12 @@ class AvatarActor(
|
||||||
sessionActor ! SessionActor.SendResponse(
|
sessionActor ! SessionActor.SendResponse(
|
||||||
PlanetsideAttributeMessage(session.get.player.GUID, 24, certification.value)
|
PlanetsideAttributeMessage(session.get.player.GUID, 24, certification.value)
|
||||||
)
|
)
|
||||||
avatar = avatar.copy(certifications = avatar.certifications.diff(replace) + certification)
|
context.self ! ReplaceAvatar(
|
||||||
|
avatar.copy(certifications = avatar.certifications.diff(replace) + certification)
|
||||||
|
)
|
||||||
sessionActor ! SessionActor.SendResponse(
|
sessionActor ! SessionActor.SendResponse(
|
||||||
ItemTransactionResultMessage(terminalGuid, TransactionType.Sell, success = true)
|
ItemTransactionResultMessage(terminalGuid, TransactionType.Sell, success = true)
|
||||||
)
|
)
|
||||||
|
|
||||||
avatar.deployables.UpdateMaxCounts(avatar.certifications)
|
|
||||||
updateDeployableUIElements(
|
|
||||||
avatar.deployables.UpdateUI()
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -510,19 +511,15 @@ class AvatarActor(
|
||||||
ItemTransactionResultMessage(terminalGuid, TransactionType.Sell, success = false)
|
ItemTransactionResultMessage(terminalGuid, TransactionType.Sell, success = false)
|
||||||
)
|
)
|
||||||
case Success(certs) =>
|
case Success(certs) =>
|
||||||
|
context.self ! ReplaceAvatar(avatar.copy(certifications = avatar.certifications.diff(remove)))
|
||||||
certs.foreach { cert =>
|
certs.foreach { cert =>
|
||||||
sessionActor ! SessionActor.SendResponse(
|
sessionActor ! SessionActor.SendResponse(
|
||||||
PlanetsideAttributeMessage(session.get.player.GUID, 25, cert.value)
|
PlanetsideAttributeMessage(session.get.player.GUID, 25, cert.value)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
avatar = avatar.copy(certifications = avatar.certifications.diff(remove))
|
|
||||||
sessionActor ! SessionActor.SendResponse(
|
sessionActor ! SessionActor.SendResponse(
|
||||||
ItemTransactionResultMessage(terminalGuid, TransactionType.Sell, success = true)
|
ItemTransactionResultMessage(terminalGuid, TransactionType.Sell, success = true)
|
||||||
)
|
)
|
||||||
avatar.deployables.UpdateMaxCounts(avatar.certifications)
|
|
||||||
updateDeployableUIElements(
|
|
||||||
avatar.deployables.UpdateUI()
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Behaviors.same
|
Behaviors.same
|
||||||
|
|
@ -560,11 +557,7 @@ class AvatarActor(
|
||||||
)
|
)
|
||||||
.onComplete {
|
.onComplete {
|
||||||
case Success(_) =>
|
case Success(_) =>
|
||||||
avatar = avatar.copy(certifications = certifications)
|
context.self ! ReplaceAvatar(avatar.copy(certifications = certifications))
|
||||||
avatar.deployables.UpdateMaxCounts(avatar.certifications)
|
|
||||||
updateDeployableUIElements(
|
|
||||||
avatar.deployables.UpdateUI()
|
|
||||||
)
|
|
||||||
case Failure(exception) =>
|
case Failure(exception) =>
|
||||||
log.error(exception)("db failure")
|
log.error(exception)("db failure")
|
||||||
}
|
}
|
||||||
|
|
@ -600,7 +593,9 @@ class AvatarActor(
|
||||||
.run(query[persistence.Implant].insert(_.name -> lift(definition.Name), _.avatarId -> lift(avatar.id)))
|
.run(query[persistence.Implant].insert(_.name -> lift(definition.Name), _.avatarId -> lift(avatar.id)))
|
||||||
.onComplete {
|
.onComplete {
|
||||||
case Success(_) =>
|
case Success(_) =>
|
||||||
avatar = avatar.copy(implants = avatar.implants.updated(index, Some(Implant(definition))))
|
context.self ! ReplaceAvatar(
|
||||||
|
avatar.copy(implants = avatar.implants.updated(index, Some(Implant(definition))))
|
||||||
|
)
|
||||||
sessionActor ! SessionActor.SendResponse(
|
sessionActor ! SessionActor.SendResponse(
|
||||||
AvatarImplantMessage(
|
AvatarImplantMessage(
|
||||||
session.get.player.GUID,
|
session.get.player.GUID,
|
||||||
|
|
@ -641,7 +636,7 @@ class AvatarActor(
|
||||||
)
|
)
|
||||||
.onComplete {
|
.onComplete {
|
||||||
case Success(_) =>
|
case Success(_) =>
|
||||||
avatar = avatar.copy(implants = avatar.implants.updated(index, None))
|
context.self ! ReplaceAvatar(avatar.copy(implants = avatar.implants.updated(index, None)))
|
||||||
sessionActor ! SessionActor.SendResponse(
|
sessionActor ! SessionActor.SendResponse(
|
||||||
AvatarImplantMessage(session.get.player.GUID, ImplantAction.Remove, index, 0)
|
AvatarImplantMessage(session.get.player.GUID, ImplantAction.Remove, index, 0)
|
||||||
)
|
)
|
||||||
|
|
@ -668,7 +663,7 @@ class AvatarActor(
|
||||||
case Success(_) =>
|
case Success(_) =>
|
||||||
loadLoadouts().onComplete {
|
loadLoadouts().onComplete {
|
||||||
case Success(loadouts) =>
|
case Success(loadouts) =>
|
||||||
avatar = avatar.copy(loadouts = loadouts)
|
context.self ! ReplaceAvatar(avatar.copy(loadouts = loadouts))
|
||||||
context.self ! RefreshLoadouts()
|
context.self ! RefreshLoadouts()
|
||||||
case Failure(exception) => log.error(exception)("db failure")
|
case Failure(exception) => log.error(exception)("db failure")
|
||||||
}
|
}
|
||||||
|
|
@ -694,7 +689,7 @@ class AvatarActor(
|
||||||
)
|
)
|
||||||
.onComplete {
|
.onComplete {
|
||||||
case Success(_) =>
|
case Success(_) =>
|
||||||
avatar = avatar.copy(loadouts = avatar.loadouts.updated(number, None))
|
context.self ! ReplaceAvatar(avatar.copy(loadouts = avatar.loadouts.updated(number, None)))
|
||||||
sessionActor ! SessionActor.SendResponse(FavoritesMessage(loadoutType, player.GUID, number, ""))
|
sessionActor ! SessionActor.SendResponse(FavoritesMessage(loadoutType, player.GUID, number, ""))
|
||||||
case Failure(exception) =>
|
case Failure(exception) =>
|
||||||
log.error(exception)("db failure")
|
log.error(exception)("db failure")
|
||||||
|
|
|
||||||
|
|
@ -249,7 +249,6 @@ object PacketCoding {
|
||||||
macEncryptionKey: ByteVector,
|
macEncryptionKey: ByteVector,
|
||||||
macDecryptionKey: ByteVector
|
macDecryptionKey: ByteVector
|
||||||
) {
|
) {
|
||||||
private val iv = BigInt(64, random)
|
|
||||||
private val rc5Spec = new RC5ParameterSpec(0, 16, 32)
|
private val rc5Spec = new RC5ParameterSpec(0, 16, 32)
|
||||||
private val rc5Encrypt = Cipher.getInstance("RC5/ECB/NoPadding")
|
private val rc5Encrypt = Cipher.getInstance("RC5/ECB/NoPadding")
|
||||||
private val rc5Decrypt = Cipher.getInstance("RC5/ECB/NoPadding")
|
private val rc5Decrypt = Cipher.getInstance("RC5/ECB/NoPadding")
|
||||||
|
|
@ -276,7 +275,9 @@ object PacketCoding {
|
||||||
val packetWithPadding = packetNoPadding ++ ByteVector.fill(paddingNeeded)(0x00) ++ paddingEncoded.toByteVector
|
val packetWithPadding = packetNoPadding ++ ByteVector.fill(paddingNeeded)(0x00) ++ paddingEncoded.toByteVector
|
||||||
// raw packets plus MAC, padded to the nearest 8 byte boundary
|
// raw packets plus MAC, padded to the nearest 8 byte boundary
|
||||||
try {
|
try {
|
||||||
Successful(ByteVector.view(rc5Encrypt.doFinal(packetWithPadding.toArray)))
|
rc5Encrypt.synchronized {
|
||||||
|
Successful(ByteVector.view(rc5Encrypt.doFinal(packetWithPadding.toArray)))
|
||||||
|
}
|
||||||
} catch {
|
} catch {
|
||||||
case e: Throwable => Failure(Err(s"encrypt error: '${e.getMessage}' data: ${packetWithPadding.toHex}"))
|
case e: Throwable => Failure(Err(s"encrypt error: '${e.getMessage}' data: ${packetWithPadding.toHex}"))
|
||||||
}
|
}
|
||||||
|
|
@ -285,7 +286,9 @@ object PacketCoding {
|
||||||
def decrypt(data: ByteVector): Attempt[ByteVector] = {
|
def decrypt(data: ByteVector): Attempt[ByteVector] = {
|
||||||
val payloadDecrypted =
|
val payloadDecrypted =
|
||||||
try {
|
try {
|
||||||
ByteVector.view(rc5Decrypt.doFinal(data.toArray))
|
rc5Decrypt.synchronized {
|
||||||
|
ByteVector.view(rc5Decrypt.doFinal(data.toArray))
|
||||||
|
}
|
||||||
} catch {
|
} catch {
|
||||||
case e: Throwable => return Failure(Err(e.getMessage))
|
case e: Throwable => return Failure(Err(e.getMessage))
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -57,7 +57,7 @@ class Md5Mac(val key: ByteVector) {
|
||||||
assert(key.length == KEYLENGTH, s"key length must be ${KEYLENGTH}, not ${key.length}")
|
assert(key.length == KEYLENGTH, s"key length must be ${KEYLENGTH}, not ${key.length}")
|
||||||
doKey()
|
doKey()
|
||||||
|
|
||||||
private def doKey() = {
|
private def doKey(): Unit = {
|
||||||
val ek: ListBuffer[Byte] = ListBuffer.fill(48)(0)
|
val ek: ListBuffer[Byte] = ListBuffer.fill(48)(0)
|
||||||
val data: ListBuffer[Byte] = ListBuffer.fill(128)(0)
|
val data: ListBuffer[Byte] = ListBuffer.fill(128)(0)
|
||||||
(0 until 16).foreach(j => {
|
(0 until 16).foreach(j => {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue