mirror of
https://github.com/oxen-io/session-android.git
synced 2024-12-24 16:57:50 +00:00
Partially implement SSK group creation
This commit is contained in:
parent
a5a53adc47
commit
944f85ddb9
@ -37,6 +37,7 @@ import org.thoughtcrime.securesms.loki.database.LokiPreKeyBundleDatabase;
|
|||||||
import org.thoughtcrime.securesms.loki.database.LokiPreKeyRecordDatabase;
|
import org.thoughtcrime.securesms.loki.database.LokiPreKeyRecordDatabase;
|
||||||
import org.thoughtcrime.securesms.loki.database.LokiThreadDatabase;
|
import org.thoughtcrime.securesms.loki.database.LokiThreadDatabase;
|
||||||
import org.thoughtcrime.securesms.loki.database.LokiUserDatabase;
|
import org.thoughtcrime.securesms.loki.database.LokiUserDatabase;
|
||||||
|
import org.thoughtcrime.securesms.loki.database.SharedSenderKeysDatabase;
|
||||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||||
|
|
||||||
public class DatabaseFactory {
|
public class DatabaseFactory {
|
||||||
@ -73,6 +74,7 @@ public class DatabaseFactory {
|
|||||||
private final LokiMessageDatabase lokiMessageDatabase;
|
private final LokiMessageDatabase lokiMessageDatabase;
|
||||||
private final LokiThreadDatabase lokiThreadDatabase;
|
private final LokiThreadDatabase lokiThreadDatabase;
|
||||||
private final LokiUserDatabase lokiUserDatabase;
|
private final LokiUserDatabase lokiUserDatabase;
|
||||||
|
private final SharedSenderKeysDatabase sskDatabase;
|
||||||
|
|
||||||
public static DatabaseFactory getInstance(Context context) {
|
public static DatabaseFactory getInstance(Context context) {
|
||||||
synchronized (lock) {
|
synchronized (lock) {
|
||||||
@ -187,6 +189,10 @@ public class DatabaseFactory {
|
|||||||
public static LokiUserDatabase getLokiUserDatabase(Context context) {
|
public static LokiUserDatabase getLokiUserDatabase(Context context) {
|
||||||
return getInstance(context).lokiUserDatabase;
|
return getInstance(context).lokiUserDatabase;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static SharedSenderKeysDatabase getSSKDatabase(Context context) {
|
||||||
|
return getInstance(context).sskDatabase;
|
||||||
|
}
|
||||||
// endregion
|
// endregion
|
||||||
|
|
||||||
public static void upgradeRestored(Context context, SQLiteDatabase database){
|
public static void upgradeRestored(Context context, SQLiteDatabase database){
|
||||||
@ -200,32 +206,33 @@ public class DatabaseFactory {
|
|||||||
DatabaseSecret databaseSecret = new DatabaseSecretProvider(context).getOrCreateDatabaseSecret();
|
DatabaseSecret databaseSecret = new DatabaseSecretProvider(context).getOrCreateDatabaseSecret();
|
||||||
AttachmentSecret attachmentSecret = AttachmentSecretProvider.getInstance(context).getOrCreateAttachmentSecret();
|
AttachmentSecret attachmentSecret = AttachmentSecretProvider.getInstance(context).getOrCreateAttachmentSecret();
|
||||||
|
|
||||||
this.databaseHelper = new SQLCipherOpenHelper(context, databaseSecret);
|
this.databaseHelper = new SQLCipherOpenHelper(context, databaseSecret);
|
||||||
this.sms = new SmsDatabase(context, databaseHelper);
|
this.sms = new SmsDatabase(context, databaseHelper);
|
||||||
this.mms = new MmsDatabase(context, databaseHelper);
|
this.mms = new MmsDatabase(context, databaseHelper);
|
||||||
this.attachments = new AttachmentDatabase(context, databaseHelper, attachmentSecret);
|
this.attachments = new AttachmentDatabase(context, databaseHelper, attachmentSecret);
|
||||||
this.media = new MediaDatabase(context, databaseHelper);
|
this.media = new MediaDatabase(context, databaseHelper);
|
||||||
this.thread = new ThreadDatabase(context, databaseHelper);
|
this.thread = new ThreadDatabase(context, databaseHelper);
|
||||||
this.mmsSmsDatabase = new MmsSmsDatabase(context, databaseHelper);
|
this.mmsSmsDatabase = new MmsSmsDatabase(context, databaseHelper);
|
||||||
this.identityDatabase = new IdentityDatabase(context, databaseHelper);
|
this.identityDatabase = new IdentityDatabase(context, databaseHelper);
|
||||||
this.draftDatabase = new DraftDatabase(context, databaseHelper);
|
this.draftDatabase = new DraftDatabase(context, databaseHelper);
|
||||||
this.pushDatabase = new PushDatabase(context, databaseHelper);
|
this.pushDatabase = new PushDatabase(context, databaseHelper);
|
||||||
this.groupDatabase = new GroupDatabase(context, databaseHelper);
|
this.groupDatabase = new GroupDatabase(context, databaseHelper);
|
||||||
this.recipientDatabase = new RecipientDatabase(context, databaseHelper);
|
this.recipientDatabase = new RecipientDatabase(context, databaseHelper);
|
||||||
this.groupReceiptDatabase = new GroupReceiptDatabase(context, databaseHelper);
|
this.groupReceiptDatabase = new GroupReceiptDatabase(context, databaseHelper);
|
||||||
this.contactsDatabase = new ContactsDatabase(context);
|
this.contactsDatabase = new ContactsDatabase(context);
|
||||||
this.preKeyDatabase = new OneTimePreKeyDatabase(context, databaseHelper);
|
this.preKeyDatabase = new OneTimePreKeyDatabase(context, databaseHelper);
|
||||||
this.signedPreKeyDatabase = new SignedPreKeyDatabase(context, databaseHelper);
|
this.signedPreKeyDatabase = new SignedPreKeyDatabase(context, databaseHelper);
|
||||||
this.sessionDatabase = new SessionDatabase(context, databaseHelper);
|
this.sessionDatabase = new SessionDatabase(context, databaseHelper);
|
||||||
this.searchDatabase = new SearchDatabase(context, databaseHelper);
|
this.searchDatabase = new SearchDatabase(context, databaseHelper);
|
||||||
this.jobDatabase = new JobDatabase(context, databaseHelper);
|
this.jobDatabase = new JobDatabase(context, databaseHelper);
|
||||||
this.stickerDatabase = new StickerDatabase(context, databaseHelper, attachmentSecret);
|
this.stickerDatabase = new StickerDatabase(context, databaseHelper, attachmentSecret);
|
||||||
this.lokiAPIDatabase = new LokiAPIDatabase(context, databaseHelper);
|
this.lokiAPIDatabase = new LokiAPIDatabase(context, databaseHelper);
|
||||||
this.lokiContactPreKeyDatabase = new LokiPreKeyRecordDatabase(context, databaseHelper);
|
this.lokiContactPreKeyDatabase = new LokiPreKeyRecordDatabase(context, databaseHelper);
|
||||||
this.lokiPreKeyBundleDatabase = new LokiPreKeyBundleDatabase(context, databaseHelper);
|
this.lokiPreKeyBundleDatabase = new LokiPreKeyBundleDatabase(context, databaseHelper);
|
||||||
this.lokiMessageDatabase = new LokiMessageDatabase(context, databaseHelper);
|
this.lokiMessageDatabase = new LokiMessageDatabase(context, databaseHelper);
|
||||||
this.lokiThreadDatabase = new LokiThreadDatabase(context, databaseHelper);
|
this.lokiThreadDatabase = new LokiThreadDatabase(context, databaseHelper);
|
||||||
this.lokiUserDatabase = new LokiUserDatabase(context, databaseHelper);
|
this.lokiUserDatabase = new LokiUserDatabase(context, databaseHelper);
|
||||||
|
this.sskDatabase = new SharedSenderKeysDatabase(context, databaseHelper);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onApplicationLevelUpgrade(@NonNull Context context, @NonNull MasterSecret masterSecret,
|
public void onApplicationLevelUpgrade(@NonNull Context context, @NonNull MasterSecret masterSecret,
|
||||||
|
@ -1,30 +1,56 @@
|
|||||||
package org.thoughtcrime.securesms.loki.protocol
|
package org.thoughtcrime.securesms.loki.protocol
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.util.Log
|
|
||||||
import nl.komponents.kovenant.Promise
|
import nl.komponents.kovenant.Promise
|
||||||
import nl.komponents.kovenant.functional.map
|
|
||||||
import org.thoughtcrime.securesms.ApplicationContext
|
import org.thoughtcrime.securesms.ApplicationContext
|
||||||
import org.thoughtcrime.securesms.crypto.storage.TextSecureSessionStore
|
|
||||||
import org.thoughtcrime.securesms.database.Address
|
import org.thoughtcrime.securesms.database.Address
|
||||||
import org.thoughtcrime.securesms.database.DatabaseFactory
|
import org.thoughtcrime.securesms.database.DatabaseFactory
|
||||||
import org.thoughtcrime.securesms.loki.utilities.recipient
|
import org.thoughtcrime.securesms.loki.utilities.recipient
|
||||||
import org.thoughtcrime.securesms.loki.utilities.timeout
|
|
||||||
import org.thoughtcrime.securesms.recipients.Recipient
|
import org.thoughtcrime.securesms.recipients.Recipient
|
||||||
import org.thoughtcrime.securesms.sms.MessageSender
|
import org.thoughtcrime.securesms.sms.MessageSender
|
||||||
|
import org.thoughtcrime.securesms.sms.OutgoingTextMessage
|
||||||
import org.thoughtcrime.securesms.util.GroupUtil
|
import org.thoughtcrime.securesms.util.GroupUtil
|
||||||
|
import org.thoughtcrime.securesms.util.Hex
|
||||||
import org.thoughtcrime.securesms.util.TextSecurePreferences
|
import org.thoughtcrime.securesms.util.TextSecurePreferences
|
||||||
import org.whispersystems.libsignal.SignalProtocolAddress
|
import org.whispersystems.libsignal.ecc.Curve
|
||||||
import org.whispersystems.signalservice.api.messages.SignalServiceContent
|
import org.whispersystems.signalservice.loki.protocol.closedgroups.ClosedGroupSenderKey
|
||||||
import org.whispersystems.signalservice.api.messages.SignalServiceGroup
|
import org.whispersystems.signalservice.loki.protocol.closedgroups.SharedSenderKeysImplementation
|
||||||
import org.whispersystems.signalservice.api.push.SignalServiceAddress
|
import org.whispersystems.signalservice.loki.utilities.hexEncodedPrivateKey
|
||||||
import org.whispersystems.signalservice.loki.api.SnodeAPI
|
import org.whispersystems.signalservice.loki.utilities.hexEncodedPublicKey
|
||||||
import org.whispersystems.signalservice.loki.api.fileserver.FileServerAPI
|
|
||||||
import org.whispersystems.signalservice.loki.protocol.shelved.multidevice.MultiDeviceProtocol
|
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
object ClosedGroupsProtocol {
|
object ClosedGroupsProtocol {
|
||||||
|
|
||||||
|
public fun createClosedGroup(context: Context, name: String, members: Collection<String>): Promise<Unit, Exception> {
|
||||||
|
// Prepare
|
||||||
|
val userPublicKey = TextSecurePreferences.getLocalNumber(context)
|
||||||
|
// Generate a key pair for the group
|
||||||
|
val groupKeyPair = Curve.generateKeyPair()
|
||||||
|
val groupPublicKey = groupKeyPair.hexEncodedPublicKey // Includes the "05" prefix
|
||||||
|
val membersAsData = members.map { Hex.fromStringCondensed(it) }
|
||||||
|
// Create ratchets for all members
|
||||||
|
val senderKeys: List<ClosedGroupSenderKey> = members.map { publicKey ->
|
||||||
|
val ratchet = SharedSenderKeysImplementation.shared.generateRatchet(groupPublicKey, publicKey)
|
||||||
|
ClosedGroupSenderKey(Hex.fromStringCondensed(ratchet.chainKey), ratchet.keyIndex, Hex.fromStringCondensed(publicKey))
|
||||||
|
}
|
||||||
|
// Create the group
|
||||||
|
val groupID = GroupUtil.getEncodedId(Hex.fromStringCondensed(groupPublicKey), false);
|
||||||
|
val admins = setOf( Address.fromSerialized(userPublicKey) )
|
||||||
|
DatabaseFactory.getGroupDatabase(context).create(groupID, name, LinkedList<Address>(members.map { Address.fromSerialized(it) }),
|
||||||
|
null, null, LinkedList<Address>(admins))
|
||||||
|
DatabaseFactory.getRecipientDatabase(context).setProfileSharing(Recipient.from(context, Address.fromSerialized(groupID), false), true)
|
||||||
|
// Establish sessions if needed
|
||||||
|
establishSessionsWithMembersIfNeeded(context, members)
|
||||||
|
// Send a closed group update message to all members using established channels
|
||||||
|
// TODO
|
||||||
|
// Add the group to the user's set of public keys to poll for
|
||||||
|
DatabaseFactory.getSSKDatabase(context).setClosedGroupPrivateKey(groupPublicKey, groupKeyPair.hexEncodedPrivateKey)
|
||||||
|
// Notify the user
|
||||||
|
// TODO
|
||||||
|
// Return
|
||||||
|
return Promise.of(Unit)
|
||||||
|
}
|
||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
fun shouldIgnoreContentMessage(context: Context, address: Address, groupID: String?, senderPublicKey: String): Boolean {
|
fun shouldIgnoreContentMessage(context: Context, address: Address, groupID: String?, senderPublicKey: String): Boolean {
|
||||||
if (!address.isClosedGroup || groupID == null) { return false }
|
if (!address.isClosedGroup || groupID == null) { return false }
|
||||||
@ -84,7 +110,7 @@ object ClosedGroupsProtocol {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
fun establishSessionsWithMembersIfNeeded(context: Context, members: List<String>) {
|
fun establishSessionsWithMembersIfNeeded(context: Context, members: Collection<String>) {
|
||||||
@Suppress("NAME_SHADOWING") val members = members.toMutableSet()
|
@Suppress("NAME_SHADOWING") val members = members.toMutableSet()
|
||||||
/*
|
/*
|
||||||
val allDevices = members.flatMap { member ->
|
val allDevices = members.flatMap { member ->
|
||||||
|
@ -26,13 +26,13 @@ class PushSessionRequestMessageSendJob private constructor(parameters: Parameter
|
|||||||
}
|
}
|
||||||
|
|
||||||
constructor(publicKey: String, timestamp: Long) : this(Parameters.Builder()
|
constructor(publicKey: String, timestamp: Long) : this(Parameters.Builder()
|
||||||
.addConstraint(NetworkConstraint.KEY)
|
.addConstraint(NetworkConstraint.KEY)
|
||||||
.setQueue(KEY)
|
.setQueue(KEY)
|
||||||
.setLifespan(TimeUnit.DAYS.toMillis(1))
|
.setLifespan(TimeUnit.DAYS.toMillis(1))
|
||||||
.setMaxAttempts(1)
|
.setMaxAttempts(1)
|
||||||
.build(),
|
.build(),
|
||||||
publicKey,
|
publicKey,
|
||||||
timestamp)
|
timestamp)
|
||||||
|
|
||||||
override fun serialize(): Data {
|
override fun serialize(): Data {
|
||||||
return Data.Builder().putString("publicKey", publicKey).putLong("timestamp", timestamp).build()
|
return Data.Builder().putString("publicKey", publicKey).putLong("timestamp", timestamp).build()
|
||||||
|
Loading…
x
Reference in New Issue
Block a user