124 lines
5.3 KiB
Kotlin
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)
|
|
|
|
}
|
|
|
|
} |