Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
sss.openstar.controller.EncryptedMessageHelper.scala Maven / Gradle / Ivy
package sss.openstar.controller
import sss.ancillary.{Guid, Logging}
import sss.openstar.Currency
import sss.openstar.account.NodeSigner.KeyType
import sss.openstar.account.{NodeIdentity, NodeVerifier}
import sss.openstar.balanceledger.TxIndex
import sss.openstar.chains.TxWriterActor.{InternalCommit, InternalTempNack}
import sss.openstar.contract.SaleOrReturnSecretEnc
import sss.openstar.controller.SendMessage.SubmitMessage
import sss.openstar.crypto.SeedBytes
import sss.openstar.identityledger.IdentityServiceQuery
import sss.openstar.message.payloads.MessageEcryption
import sss.openstar.message.payloads.MessageEcryption.{EmbeddedBounty, MessageAttachments}
import sss.openstar.ui.rpc._
import sss.openstar.wallet.UnlockedWallet
import sss.openstar.wallet.Wallet.CreditTooLow
import scala.concurrent.{ExecutionContext, Future}
/**
* Created by alan on 6/10/16.
*/
object EncryptedMessageHelper extends Logging {
// The storage providers should be claiming the storage reward immediately
private val numBlocksForProviderToClaimWithin = 2
private def toVerifier(identityServiceQuery: IdentityServiceQuery,
keyType: KeyType,
tos: Seq[String])(implicit ec: ExecutionContext): Future[Seq[NodeVerifier]] = Future {
tos.map { to =>
identityServiceQuery.accountOpt(to) match {
case Some(pkAc) if pkAc.typedPublicKey.keyType == keyType =>
Some(identityServiceQuery.toVerifier((pkAc)))
case Some(pkAc) =>
log.info(s"Default keyTypes do not match, sender: ${keyType}, recip: ${pkAc.typedPublicKey.keyType}")
None
case None =>
log.info(s"No such user $to in $tos, dropping message recipient")
None
}
}.collect { case Some(pki) => pki }
}
private def setupEmbeddedBounty(userWallet: UnlockedWallet[Currency],
amountValue: Long,
secretOpt: Option[Array[Byte]],
sender: NodeIdentity,
foundTos: Seq[NodeVerifier],
numBlocksToLive:Int)(implicit ec: ExecutionContext): Future[Result[EmbeddedBounty]] = {
val returnBlockHeight = userWallet.w.currentBlockHeight() + numBlocksToLive
val amount = userWallet.w.amount(amountValue)
Future.fromTry(userWallet.w.createTx((amount * foundTos.size).get, numBlocksToLive)).flatMap { baseTx =>
val paymentsOut = foundTos map { foundTo =>
userWallet.w.output(amount, SaleOrReturnSecretEnc(sender.id, foundTo.nodeIdTag.nodeId, secretOpt,
returnBlockHeight))
}
val startToPaymentIndex = baseTx.outs.size
val tx = userWallet.w.appendOutputs(baseTx, paymentsOut: _*)
userWallet.payAsync(tx).map(r => (tx, startToPaymentIndex, foundTos, returnBlockHeight, r))
}.map {
case (tx, startToPaymentIndex, tos, returnBlockHeight, _: InternalCommit) =>
log.info(s"Successfully committed base tx for $amountValue tos: ${tos.map(_.nodeIdTag.nodeId)} author: ${sender.id}")
success(
EmbeddedBounty(
amountValue,
returnBlockHeight,
TxIndex(tx.txId, startToPaymentIndex),
)
)
case (_, _, _, _, _: InternalTempNack) =>
problem(s"Network busy, try again.")
case x =>
log.error(s"Problem paying for message delivery")
log.error(x.toString)
problem(s"Problem paying for message delivery, see log.")
}
}
def sendMessageToMany(
guid: Guid,
text: String,
attachments: Option[MessageAttachments],
amountValue: Long,
tos: Seq[String],
numBlocksToLive: Int,
parentGuidOpt: Option[Guid]
)
(implicit userWallet: UnlockedWallet[Currency],
identityServiceQuery: IdentityServiceQuery,
sender: NodeIdentity,
submitMessage: SubmitMessage,
ec: ExecutionContext
): Future[Result[Boolean]] = {
if (tos.isEmpty) Future.successful(problem("Message has no recipients"))
else if (text.trim.isEmpty && attachments.isEmpty) Future.successful(problem("Message has no body and no attachments"))
else {
val receiversMustHaveMatchingKeyType = sender.defaultNodeVerifier.verifier.typedPublicKey.keyType
toVerifier(identityServiceQuery, receiversMustHaveMatchingKeyType, tos)
}.flatMap { foundTos =>
val secret = SeedBytes.secureSeed(16)
val secretOpt = Option(secret)
require(foundTos.nonEmpty, s"No valid recipients in ${tos} ")
(if (amountValue > 0) {
setupEmbeddedBounty(
userWallet,
amountValue,
secretOpt,
sender,
foundTos,
numBlocksToLive).map(_.map(Some(_)))
} else {
Future.successful(success[Option[EmbeddedBounty]](None))
})
.flatMap {
case Left(p) =>
Future.successful(problem(p))
case Right(bountyOpt) =>
val encryptedMessageF = MessageEcryption.encryptWithEmbeddedSecret(
bountyOpt,
sender,
foundTos,
text,
attachments,
secret,
guid,
Seq.empty
)
encryptedMessageF
.flatMap(encryptedMessage =>
submitMessage(
sender.id,
userWallet,
numBlocksForProviderToClaimWithin,
foundTos.map(_.nodeIdTag.nodeId).toSet,
encryptedMessage,
parentGuidOpt,
encryptedMessage.guid
)
).recover {
case _: CreditTooLow => problem(CreditTooLowProblem)
}.map(_ => ok())
}
}
}
}