session-android/libsession/src/main/java/org/session/libsession/messaging/jobs/InviteContactJob.kt

86 lines
3.9 KiB
Kotlin

package org.session.libsession.messaging.jobs
import com.google.protobuf.ByteString
import org.session.libsession.messaging.MessagingModuleConfiguration
import org.session.libsession.messaging.messages.Destination
import org.session.libsession.messaging.messages.control.GroupUpdated
import org.session.libsession.messaging.sending_receiving.MessageSender
import org.session.libsession.messaging.utilities.Data
import org.session.libsession.messaging.utilities.SodiumUtilities
import org.session.libsession.snode.SnodeAPI
import org.session.libsignal.protos.SignalServiceProtos.DataMessage.GroupUpdateInviteMessage
import org.session.libsignal.protos.SignalServiceProtos.DataMessage.GroupUpdateMessage
import org.session.libsignal.protos.SignalServiceProtos.DataMessage.LokiProfile
import org.session.libsignal.utilities.Log
import org.session.libsignal.utilities.SessionId
class InviteContactJob(val groupSessionId: String, val memberSessionId: String): Job {
sealed class InviteError(message: String): Exception(message) {
object NO_GROUP_KEYS: InviteError("No group keys config for this group")
}
companion object {
const val KEY = "InviteContactJob"
private const val GROUP = "group"
private const val MEMBER = "member"
}
override var delegate: JobDelegate? = null
override var id: String? = null
override var failureCount: Int = 0
override val maxFailureCount: Int = 1
override suspend fun execute(dispatcherName: String) {
val delegate = delegate ?: return
val configs = MessagingModuleConfiguration.shared.configFactory
val storage = MessagingModuleConfiguration.shared.storage
val adminKey = configs.userGroups?.getClosedGroup(groupSessionId)?.adminKey
?: return delegate.handleJobFailedPermanently(this, dispatcherName, NullPointerException("No admin key"))
val subAccount = configs.getGroupKeysConfig(SessionId.from(groupSessionId))?.use { keys ->
keys.makeSubAccount(SessionId.from(memberSessionId))
} ?: return delegate.handleJobFailedPermanently(this, dispatcherName, InviteError.NO_GROUP_KEYS)
val timestamp = SnodeAPI.nowWithOffset
val messageToSign = "INVITE$memberSessionId$timestamp"
val signature = SodiumUtilities.sign(messageToSign.toByteArray(), adminKey)
val userProfile = storage.getUserProfile()
val lokiProfile = LokiProfile.newBuilder()
.setDisplayName(userProfile.displayName)
if (userProfile.profilePictureURL?.isNotEmpty() == true) {
lokiProfile.profilePicture = userProfile.profilePictureURL
}
val groupInvite = GroupUpdateInviteMessage.newBuilder()
.setGroupSessionId(groupSessionId)
.setMemberAuthData(ByteString.copyFrom(subAccount))
.setAdminSignature(ByteString.copyFrom(signature))
.setName(userProfile.displayName)
.setProfile(lokiProfile.build())
if (userProfile.profileKey?.isNotEmpty() == true) {
groupInvite.profileKey = ByteString.copyFrom(userProfile.profileKey)
}
val message = GroupUpdateMessage.newBuilder()
.setInviteMessage(groupInvite)
.build()
val update = GroupUpdated(message).apply {
sentTimestamp = timestamp
}
try {
MessageSender.send(update, Destination.Contact(memberSessionId), false).get()
Log.d("InviteContactJob", "Sent invite message successfully")
delegate.handleJobSucceeded(this, dispatcherName)
} catch (e: Exception) {
Log.e("InviteContactJob", e)
delegate.handleJobFailed(this, dispatcherName, e)
}
}
override fun serialize(): Data =
Data.Builder()
.putString(GROUP, groupSessionId)
.putString(MEMBER, memberSessionId)
.build()
override fun getFactoryKey(): String = KEY
}