Skip to content
This repository has been archived by the owner on Feb 17, 2023. It is now read-only.

Add IR/Magfa sms gateway #1021

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,14 @@ services {
}
}

magfa {
service : ""
domain : ""
username: ""
password : ""
from: ""
}

actor-activation {
uri: "https://gate.actor.im"
auth-token: ""
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package im.actor.server.activation.magfa

import akka.actor.ActorSystem
import akka.pattern.ask
import akka.util.Timeout
import cats.data.Xor
import im.actor.config.ActorConfig
import im.actor.server.activation.common.ActivationStateActor.{ ForgetSentCode, Send, SendAck }
import im.actor.server.activation.common._
import im.actor.server.db.DbExtension
import im.actor.server.model.AuthPhoneTransaction
import im.actor.server.persist.auth.AuthTransactionRepo
import im.actor.server.sms._
import im.actor.util.misc.PhoneNumberUtils.isTestPhone

import scala.concurrent.Future
import scala.concurrent.duration._

private[activation] final class MagfaProvider(implicit system: ActorSystem) extends ActivationProvider with CommonAuthCodes {

protected val activationConfig = ActivationConfig.load.getOrElse(throw new RuntimeException("Failed to load activation config"))
protected val db = DbExtension(system).db
protected implicit val ec = system.dispatcher

private val magfaClient = new MagfaClient(ActorConfig.load().getConfig("services.magfa"))
private val smsEngine = new MagfaSmsEngine(magfaClient)

private implicit val timeout = Timeout(20.seconds)

private val smsStateActor = system.actorOf(ActivationStateActor.props[Long, SmsCode](
repeatLimit = activationConfig.repeatLimit,
sendAction = (code: SmsCode) ⇒ smsEngine.sendCode(code.phone, code.code),
id = (code: SmsCode) ⇒ code.phone
), "magfa-sms-state")

override def send(txHash: String, code: Code): Future[CodeFailure Xor Unit] = code match {
case s: SmsCode ⇒
for {
resp ← if (isTestPhone(s.phone))
Future.successful(Xor.right(()))
else
(smsStateActor ? Send(code)).mapTo[SendAck].map(_.result)
_ ← createAuthCodeIfNeeded(resp, txHash, code.code)
} yield resp
case other ⇒ throw new RuntimeException(s"This provider can't handle code of type: ${other.getClass}")
}

override def cleanup(txHash: String): Future[Unit] = {
for {
ac ← db.run(AuthTransactionRepo.findChildren(txHash))
_ = ac match {
case Some(x: AuthPhoneTransaction) ⇒
smsStateActor ! ForgetSentCode.phone(x.phoneNumber)
case _ ⇒
}
_ ← deleteAuthCode(txHash)
} yield ()
}

}
4 changes: 4 additions & 0 deletions actor-server/actor-sms/src/main/resources/reference.conf
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,8 @@ sms {
clickatell {

}

magfa {

}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package im.actor.server.sms

import java.net.URLEncoder

import akka.actor.ActorSystem
import com.ning.http.client.Response
import com.typesafe.config.Config
import dispatch.{ Http, url }

import scala.concurrent.{ ExecutionContext, Future }
import scala.util.Failure

final class MagfaClient(config: Config)(implicit system: ActorSystem) {

private lazy val http = new Http()
private val Utf8Encoding = "UTF-8"
system registerOnTermination http.shutdown()

private implicit val ec: ExecutionContext = system.dispatcher

private val BaseUrl = config.getString("url")
private val ResourcePath = "/magfaHttpService?"

def sendSmsCode(phoneNumber: Long, code: String): Future[Unit] = {
postRequest(ResourcePath, Map(
"service" -> config.getString("service"),
"domain" -> config.getString("domain"),
"username" -> config.getString("username"),
"password" -> config.getString("password"),
"from" → config.getString("from"),
"to" → phoneNumber.toString,
"message" → code
)) map { _ ⇒
system.log.debug("Message sent via magfa")
}
}

private def postRequest(resourcePath: String, params: Map[String, String]): Future[Response] = {
val body = params.map(p ⇒ s"${p._1}=${URLEncoder.encode(p._2, Utf8Encoding)}").mkString("&")
val request = url(BaseUrl + resourcePath + body)

http(request).map { resp ⇒
if (resp.getStatusCode < 199 || resp.getStatusCode > 299) {
throw new RuntimeException(s"Response has code ${resp.getStatusCode}. [${resp.getResponseBody}]")
} else {
resp
}
} andThen {
case Failure(e) ⇒
system.log.error(e, "Failed to make request to telesign")
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package im.actor.server.sms

import scala.concurrent.Future

final class MagfaSmsEngine(magfaSmsClient: MagfaClient) extends AuthSmsEngine {
override def sendCode(phoneNumber: Long, message: String): Future[Unit] = magfaSmsClient.sendSmsCode(phoneNumber, message)
}