norn-talk/app/src/main/java/xyz/johnny/norntalk/messages/NornMessageReceiver.kt

124 lines
5.3 KiB
Kotlin

package xyz.johnny.norntalk.messages
import android.annotation.SuppressLint
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.os.AsyncTask
import android.os.AsyncTask.THREAD_POOL_EXECUTOR
import android.provider.Telephony.Sms.Intents.getMessagesFromIntent
import android.util.Log
import android.widget.Toast
import xyz.johnny.norntalk.R
import xyz.johnny.norntalk.security.CheckNumber
import xyz.johnny.norntalk.security.QRCode
import java.util.*
/**
* Classe recevant les SMS
*/
class NornMessageReceiver : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
// Récupérer les messages
val msgs = getMessagesFromIntent(intent)
// Concaténer les messages reçus, pour les messages en plusieurs parties
val body = msgs.map { it.displayMessageBody }.joinToString("")
Log.d(this::class.java.simpleName, "message received: " + body)
// trouver l'expéditeur du message
val msg = msgs[0]
val contact = NornContact.getContact(msg.displayOriginatingAddress, context)
// créer le message
val message = NornMessage(body,
msg.displayOriginatingAddress,
NornConversation.getConversation(arrayOf(contact), context),
Date(msg.timestampMillis),
context)
Log.d(this::class.java.simpleName, message.toString())
// permettre de vérifier le numéro de téléphone de l'utilisateur
if (CheckNumber.messageReceived(message))
return
// vérifier si le message est en rapport avec un QR code
if (QRCode.message_hook(context, message))
return
/*
* Si le message commence par "ke:" le message sera utilisé pour démarrer une conversation
* sécurisée. Cela peut paraître un peu simple, sachant que n'importe qui serait capable
* d'envoyer un tel message, mais il est impossible de procéder autrement.
* Il semble bien exister une notion de port dans le protocole des SMS, qui seraient utile
* dans un tel cas et pourrait également être utilisé pour différencier plus facilement
* les messages chiffrés.
* Cependant il semble que cette fonctionnalité n'est pas supportée par beaucoup de
* téléphones, dont un des téléphones sur lequel nous avions testé ces échanges de clés.
*/
if (message.rawtext.startsWith(context.getString(R.string.key_exchange_prefix))) {
// assigner la clé publique au contact
message.setPublicKey(context)
/*
*
* Si la conversation n'est pas déjà notée comme sécurisée on envoi un message à
* l'expéditeur du message afin d'être sûr qu'il aient reçu notre clé publique.
* Les échanges s'effectuent donc ainsi:
*
* - L'application envoie la clé publique à un autre utilisateur de l'application
* - L'application de l'autre utilisateur répond en envoyant également sa clé publique
* et considère alors la conversation comme sécurisée
* - L'application reçoit la clé publique de l'autre utilisateur et considère elle
* aussi la conversation comme sécurisée, elle envoi de nouveau sa clé publique
* - L'application de l'autre utilisateur reçoit de nouveau la clé et arrête la boucle
*
* Cela permet d'échanger les clés de manière simple et sûre.
*/
if (!message.conversation.secured) {
message.conversation.createSecuredConversation(context)
message.conversation.setSecured(true, context)
Toast.makeText(context, context.getText(R.string.secured_conv), Toast.LENGTH_SHORT).show()
}
return
}
/*
* Si le message "EOSC" est reçu la conversation sécurisée est interrompue.
* EOSC est un acronyme pour "End Of Secured Conversation".
* Même remarque que pour le choix de "ke:" pour l'échange de clé, il serait facile
* d'envoyer manuellement un tel message mais il ne semble pas exister une méthode plus sûre.
*/
if (message.rawtext == context.getString(R.string.end_secret_conversation)) {
message.conversation.setSecured(false, context)
Toast.makeText(context, context.getText(R.string.unsecured_conv), Toast.LENGTH_SHORT).show()
return
}
// Transmettre le message au reste de l'application en parallèle
val task = @SuppressLint("StaticFieldLeak")
object : AsyncTask<Context, Void, NornMessage>() {
override fun doInBackground(vararg params: Context?): NornMessage {
message.insertMessage(context).get()
return message
}
override fun onPostExecute(message: NornMessage) {
super.onPostExecute(message)
// envoyer une notification
message.sendNotification()
// Afficher le message dans les activités
NornMessageDispatcher.send(message)
}
}
task.executeOnExecutor(THREAD_POOL_EXECUTOR, context)
}
}