Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Multi Device Support #31

Merged
merged 38 commits into from Oct 8, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
ff65d4e
Added Database.
Mikunj Sep 19, 2019
901d627
Linked storage api and database.
Mikunj Sep 23, 2019
90ee676
Hookup receiving logic.
Mikunj Sep 23, 2019
d51c62e
Moved LokiMultiDeviceDatabase into LokiAPIDatabase.
Mikunj Sep 24, 2019
ed9c3ae
Merge pull request #26 from loki-project/multi-device-database
Mikunj Sep 24, 2019
8acc0bc
Auto accept friend requests if we're friends with the primary device.
Mikunj Sep 24, 2019
203348b
Update device mappings on the file server upon receiving a pairing co…
Mikunj Sep 24, 2019
4af63f7
Merge commit 'ed9c3ae692ae3e436e0fbb1b12cb8d6662fcda5f' into multi-de…
Mikunj Sep 24, 2019
0b49d7a
Fix crashing during start.
Mikunj Sep 25, 2019
7d1883c
Trigger event when authorisation is accepted.
Mikunj Sep 26, 2019
10c1a9c
Added linking in the ui.
Mikunj Sep 26, 2019
dde4ee6
Merge branch 'dev' into multi-device-integration
Mikunj Sep 30, 2019
258ad57
Merge branch 'dev' into multi-device-integration
Mikunj Oct 1, 2019
80e9b82
Hooked up dialog ui
Mikunj Oct 1, 2019
373b9b3
Moved pairing logic into dialog.
Mikunj Oct 1, 2019
7205932
Show toast if message sending failed.
Mikunj Oct 2, 2019
e07d8dd
Fix ui not being dismissed on message send failure.
Mikunj Oct 2, 2019
be55e1b
Fixed multi device database primary key allocation.
Mikunj Oct 2, 2019
be9afa2
Fix auto accept friend request logic.
Mikunj Oct 2, 2019
8e495d0
Fix bugs in multi device pairing.
Mikunj Oct 3, 2019
fb3967d
Multi-device sending text messages.
Mikunj Oct 4, 2019
8a3b4a6
Refactor.
Mikunj Oct 6, 2019
0bfa3c3
Multi-device sending media message
Mikunj Oct 6, 2019
da67bfa
Multi-device sending typing and receipt messages.
Mikunj Oct 6, 2019
a2e9271
Hide link device preference if we're a secondary device.
Mikunj Oct 7, 2019
dbd8133
Merge branch 'dev' into multi-device-integration
Mikunj Oct 7, 2019
4f46c63
Renaming.
Mikunj Oct 7, 2019
19ec4db
Update for core changes
nielsandriesse Oct 7, 2019
742d9bf
Partially implement feedback
nielsandriesse Oct 7, 2019
c8a90ce
Add missing event
nielsandriesse Oct 7, 2019
79ec455
Clean
nielsandriesse Oct 7, 2019
98498a6
Fix receiving multiple of the same authorisations at once causing us …
Mikunj Oct 7, 2019
95695ff
Clean up seed step
nielsandriesse Oct 7, 2019
a644100
Merge branch 'multi-device' of github.com:loki-project/loki-messenger…
nielsandriesse Oct 7, 2019
d0e5ddf
WIP
nielsandriesse Oct 7, 2019
bf958ff
Partially disable settings for slave devices
nielsandriesse Oct 8, 2019
a44c3fc
Clean
nielsandriesse Oct 8, 2019
ac9c9f5
Somewhat simplify device linking UI
nielsandriesse Oct 8, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
8 changes: 4 additions & 4 deletions res/layout/activity_account_details.xml
Expand Up @@ -20,7 +20,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="40dp"
android:text="@string/activity_account_details_title"
android:text="@string/activity_display_name_title"
android:textAlignment="center" />

<TextView
Expand All @@ -29,7 +29,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:text="@string/activity_account_details_subtitle"
android:text="@string/activity_display_name_subtitle"
android:textAlignment="center" />

<org.thoughtcrime.securesms.components.LabeledEditText
Expand All @@ -38,7 +38,7 @@
android:layout_height="wrap_content"
android:layout_marginTop="32dp"
app:labeledEditText_background="@color/loki_darkest_gray"
app:labeledEditText_label="@string/activity_account_details_name_edit_text_label"/>
app:labeledEditText_label="@string/activity_display_name_name_edit_text_label"/>

<com.dd.CircularProgressButton
android:id="@+id/nextButton"
Expand All @@ -53,7 +53,7 @@
app:cpb_colorProgress="@color/textsecure_primary"
app:cpb_cornerRadius="4dp"
app:cpb_selectorIdle="@drawable/progress_button_state"
app:cpb_textIdle="@string/activity_account_details_button_title" />
app:cpb_textIdle="@string/activity_display_name_button_title" />

</LinearLayout>

Expand Down
47 changes: 44 additions & 3 deletions res/layout/activity_seed.xml
Expand Up @@ -76,8 +76,28 @@
app:labeledEditText_background="@color/loki_darkest_gray"
app:labeledEditText_label="@string/activity_key_pair_mnemonic_edit_text_label"/>

<TextView
android:id="@+id/linkExplanationTextView"
style="@style/Signal.Text.Body"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="24dp"
android:visibility="gone"
android:text="@string/activity_key_pair_seed_explanation_3"
android:textAlignment="center" />

<org.thoughtcrime.securesms.components.LabeledEditText
android:id="@+id/publicKeyEditText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:layout_marginBottom="20dp"
android:visibility="gone"
app:labeledEditText_background="@color/loki_darkest_gray"
app:labeledEditText_label="@string/activity_key_pair_public_key_edit_text_label"/>

<Button
android:id="@+id/toggleModeButton"
android:id="@+id/toggleRestoreModeButton"
android:layout_width="match_parent"
android:layout_height="50dp"
android:background="@color/transparent"
Expand All @@ -86,8 +106,29 @@
android:elevation="0dp"
android:stateListAnimator="@null" />

<Button
android:id="@+id/toggleRegisterModeButton"
android:layout_width="match_parent"
android:layout_height="50dp"
android:background="@color/transparent"
android:textColor="@color/signal_primary"
android:text="@string/activity_key_pair_toggle_mode_button_title_2"
android:visibility="gone"
android:elevation="0dp"
android:stateListAnimator="@null" />

<Button
android:id="@+id/toggleLinkModeButton"
android:layout_width="match_parent"
android:layout_height="50dp"
android:background="@color/transparent"
android:textColor="@color/signal_primary"
android:text="@string/activity_key_pair_toggle_mode_button_title_3"
android:elevation="0dp"
android:stateListAnimator="@null" />

<com.dd.CircularProgressButton
android:id="@+id/registerOrRestoreButton"
android:id="@+id/mainButton"
android:layout_width="match_parent"
android:layout_height="50dp"
android:layout_marginTop="20dp"
Expand All @@ -99,7 +140,7 @@
app:cpb_colorProgress="@color/textsecure_primary"
app:cpb_cornerRadius="4dp"
app:cpb_selectorIdle="@drawable/progress_button_state"
app:cpb_textIdle="@string/activity_key_pair_register_or_restore_button_title_1" />
app:cpb_textIdle="@string/activity_key_pair_main_button_title_1" />

</LinearLayout>

Expand Down
18 changes: 11 additions & 7 deletions res/values/strings.xml
Expand Up @@ -1549,22 +1549,26 @@
<string name="activity_landing_permission_dialog_message">Some features of Loki Messenger (such as automatic message backup) require storage access to work.</string>
<string name="activity_landing_beta_terms">"Loki Messenger is currently in beta. For development purposes the beta version collects basic usage statistics and crash logs. In addition, the beta version doesn't provide full privacy and shouldn\'t be used to transmit sensitive information."</string>
<string name="activity_landing_privacy_policy_button_title">Privacy Policy</string>
<!-- Account details activity -->
<string name="activity_account_details_title">Create Your Loki Messenger Account</string>
<string name="activity_account_details_subtitle">Enter a name to be shown to your contacts</string>
<string name="activity_account_details_name_edit_text_label">Display Name (Optional)</string>
<string name="activity_account_details_button_title">Next</string>
<!-- Display name activity -->
<string name="activity_display_name_title">Create Your Loki Messenger Account</string>
<string name="activity_display_name_subtitle">Enter a name to be shown to your contacts</string>
<string name="activity_display_name_name_edit_text_label">Display Name (Optional)</string>
<string name="activity_display_name_button_title">Next</string>
<!-- Key pair activity -->
<string name="activity_key_pair_title">Create Your Loki Messenger Account</string>
<string name="activity_key_pair_seed_explanation_1">Please save the seed below in a safe location. It can be used to restore your account if you lose access, or to migrate to a new device.</string>
<string name="activity_key_pair_seed_explanation_2">Restore your account by entering your seed below</string>
<string name="activity_key_pair_seed_explanation_3">Link to an existing device by going into its in-app settings and clicking "Link Device".</string>
<string name="activity_key_pair_copy_button_title">Copy</string>
<string name="activity_key_pair_mnemonic_edit_text_label">Your Seed</string>
<string name="activity_key_pair_toggle_mode_button_title_1">Restore Using Seed</string>
<string name="activity_key_pair_toggle_mode_button_title_2">Register a New Account</string>
<string name="activity_key_pair_toggle_mode_button_title_3">Link Device</string>
<string name="activity_key_pair_mnemonic_copied_message">Copied to clipboard</string>
<string name="activity_key_pair_register_or_restore_button_title_1">Register</string>
<string name="activity_key_pair_register_or_restore_button_title_2">Restore</string>
<string name="activity_key_pair_main_button_title_1">Register</string>
<string name="activity_key_pair_main_button_title_2">Restore</string>
<string name="activity_key_pair_main_button_title_3">Link</string>
<string name="activity_key_pair_public_key_edit_text_label">Your Public Key</string>
<!-- Conversation list activity -->
<string name="activity_conversation_list_empty_state_message">Looks like you don\'t have any conversations yet. Get started by messaging a friend.</string>
<!-- Settings activity -->
Expand Down
14 changes: 14 additions & 0 deletions src/org/thoughtcrime/securesms/ApplicationContext.java
Expand Up @@ -36,6 +36,7 @@
import org.signal.aesgcmprovider.AesGcmProvider;
import org.thoughtcrime.securesms.components.TypingStatusRepository;
import org.thoughtcrime.securesms.components.TypingStatusSender;
import org.thoughtcrime.securesms.crypto.IdentityKeyUtil;
import org.thoughtcrime.securesms.database.DatabaseContentProviders;
import org.thoughtcrime.securesms.database.DatabaseFactory;
import org.thoughtcrime.securesms.dependencies.AxolotlStorageModule;
Expand Down Expand Up @@ -83,12 +84,14 @@
import org.whispersystems.libsignal.logging.SignalProtocolLoggerProvider;
import org.whispersystems.signalservice.api.messages.SignalServiceEnvelope;
import org.whispersystems.signalservice.internal.push.SignalServiceProtos;
import org.whispersystems.signalservice.loki.api.LokiAPIDatabaseProtocol;
import org.whispersystems.signalservice.loki.api.LokiGroupChat;
import org.whispersystems.signalservice.loki.api.LokiGroupChatAPI;
import org.whispersystems.signalservice.loki.api.LokiLongPoller;
import org.whispersystems.signalservice.loki.api.LokiP2PAPI;
import org.whispersystems.signalservice.loki.api.LokiP2PAPIDelegate;
import org.whispersystems.signalservice.loki.api.LokiRSSFeed;
import org.whispersystems.signalservice.loki.api.LokiStorageAPI;
import org.whispersystems.signalservice.loki.utilities.Analytics;

import java.security.Security;
Expand Down Expand Up @@ -190,6 +193,7 @@ public void onStart(@NonNull LifecycleOwner owner) {
KeyCachingService.onAppForegrounded(this);
// Loki - Start long polling if needed
startLongPollingIfNeeded();
setUpStorageAPIIfNeeded();
}

@Override
Expand Down Expand Up @@ -424,6 +428,16 @@ private static class ProviderInitializationException extends RuntimeException {
}

// region Loki
public void setUpStorageAPIIfNeeded() {
String userHexEncodedPublicKey = TextSecurePreferences.getLocalNumber(this);
if (userHexEncodedPublicKey != null && IdentityKeyUtil.hasIdentityKey(this)) {
boolean isDebugMode = BuildConfig.DEBUG;
byte[] userPrivateKey = IdentityKeyUtil.getIdentityKeyPair(this).getPrivateKey().serialize();
LokiAPIDatabaseProtocol database = DatabaseFactory.getLokiAPIDatabase(this);
LokiStorageAPI.Companion.configure(isDebugMode, userHexEncodedPublicKey, userPrivateKey, database);
}
}

public void setUpP2PAPI() {
String hexEncodedPublicKey = TextSecurePreferences.getLocalNumber(this);
if (hexEncodedPublicKey == null) { return; }
Expand Down
28 changes: 20 additions & 8 deletions src/org/thoughtcrime/securesms/ApplicationPreferencesActivity.java
Expand Up @@ -156,8 +156,13 @@ public static class ApplicationPreferenceFragment extends CorrectedPreferenceFra
public void onCreate(Bundle icicle) {
super.onCreate(icicle);

this.findPreference(PREFERENCE_CATEGORY_PROFILE)
.setOnPreferenceClickListener(new ProfileClickListener());
String masterHexEncodedPublicKey = TextSecurePreferences.getMasterHexEncodedPublicKey(getContext());
boolean isMasterDevice = (masterHexEncodedPublicKey != null);

Preference profilePreference = this.findPreference(PREFERENCE_CATEGORY_PROFILE);
// Hide if this is a slave device
profilePreference.setVisible(isMasterDevice);
profilePreference.setOnPreferenceClickListener(new ProfileClickListener());
/*
this.findPreference(PREFERENCE_CATEGORY_SMS_MMS)
.setOnPreferenceClickListener(new CategoryClickListener(PREFERENCE_CATEGORY_SMS_MMS));
Expand All @@ -182,10 +187,14 @@ public void onCreate(Bundle icicle) {
.setOnPreferenceClickListener(new CategoryClickListener(PREFERENCE_CATEGORY_PUBLIC_KEY));
this.findPreference(PREFERENCE_CATEGORY_QR_CODE)
.setOnPreferenceClickListener(new CategoryClickListener(PREFERENCE_CATEGORY_QR_CODE));
this.findPreference(PREFERENCE_CATEGORY_LINK_DEVICE)
.setOnPreferenceClickListener(new CategoryClickListener(PREFERENCE_CATEGORY_LINK_DEVICE));
this.findPreference(PREFERENCE_CATEGORY_SEED)
.setOnPreferenceClickListener(new CategoryClickListener((PREFERENCE_CATEGORY_SEED)));
Preference linkDevicePreference = this.findPreference(PREFERENCE_CATEGORY_LINK_DEVICE);
// Hide if this is a slave device
linkDevicePreference.setVisible(isMasterDevice);
linkDevicePreference.setOnPreferenceClickListener(new CategoryClickListener(PREFERENCE_CATEGORY_LINK_DEVICE));
Preference seedPreference = this.findPreference(PREFERENCE_CATEGORY_SEED);
// Hide if this is a slave device
seedPreference.setVisible(isMasterDevice);
seedPreference.setOnPreferenceClickListener(new CategoryClickListener((PREFERENCE_CATEGORY_SEED)));

if (VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
tintIcons(getActivity());
Expand Down Expand Up @@ -320,7 +329,10 @@ public boolean onPreferenceClick(Preference preference) {
*/
case PREFERENCE_CATEGORY_PUBLIC_KEY:
Analytics.Companion.getShared().track("Public Key Shared");
String hexEncodedPublicKey = TextSecurePreferences.getLocalNumber(getContext());
String hexEncodedPublicKey = TextSecurePreferences.getMasterHexEncodedPublicKey(getContext());
if (hexEncodedPublicKey == null) {
hexEncodedPublicKey = TextSecurePreferences.getLocalNumber(getContext());
}
Intent shareIntent = new Intent();
shareIntent.setAction(Intent.ACTION_SEND);
shareIntent.putExtra(Intent.EXTRA_TEXT, hexEncodedPublicKey);
Expand All @@ -331,7 +343,7 @@ public boolean onPreferenceClick(Preference preference) {
QRCodeDialog.INSTANCE.show(getContext());
break;
case PREFERENCE_CATEGORY_LINK_DEVICE:
DeviceLinkingDialog.INSTANCE.show(getContext(), DeviceLinkingView.Mode.Master);
DeviceLinkingDialog.Companion.show(getContext(), DeviceLinkingView.Mode.Master, null);
break;
case PREFERENCE_CATEGORY_SEED:
Analytics.Companion.getShared().track("Seed Modal Shown");
Expand Down
Expand Up @@ -5,13 +5,21 @@
import android.support.annotation.NonNull;

import org.thoughtcrime.securesms.ApplicationContext;
import org.thoughtcrime.securesms.database.Address;
import org.thoughtcrime.securesms.database.DatabaseFactory;
import org.thoughtcrime.securesms.database.ThreadDatabase;
import org.thoughtcrime.securesms.jobs.TypingSendJob;
import org.thoughtcrime.securesms.loki.MultiDeviceUtilitiesKt;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.util.Util;
import org.whispersystems.signalservice.loki.api.LokiStorageAPI;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

import kotlin.Unit;

@SuppressLint("UseSparseArrays")
public class TypingStatusSender {

Expand Down Expand Up @@ -74,7 +82,23 @@ private synchronized void onTypingStopped(long threadId, boolean notify) {
}

private void sendTyping(long threadId, boolean typingStarted) {
ApplicationContext.getInstance(context).getJobManager().add(new TypingSendJob(threadId, typingStarted));
LokiStorageAPI storageAPI = LokiStorageAPI.Companion.getShared();
ThreadDatabase threadDatabase = DatabaseFactory.getThreadDatabase(context);
Recipient recipient = threadDatabase.getRecipientForThreadId(threadId);

if (recipient == null) {
ApplicationContext.getInstance(context).getJobManager().add(new TypingSendJob(threadId, typingStarted));
return;
}

MultiDeviceUtilitiesKt.getAllDevicePublicKeys(context, recipient.getAddress().serialize(), storageAPI, (devicePublicKey, isFriend, friendCount) -> {
Recipient device = Recipient.from(context, Address.fromSerialized(devicePublicKey), false);
long deviceThreadID = threadDatabase.getThreadIdIfExistsFor(device);
if (deviceThreadID > -1) {
ApplicationContext.getInstance(context).getJobManager().add(new TypingSendJob(deviceThreadID, typingStarted));
}
return Unit.INSTANCE;
});
}

private class StartRunnable implements Runnable {
Expand Down
3 changes: 1 addition & 2 deletions src/org/thoughtcrime/securesms/crypto/IdentityKeyUtil.java
Expand Up @@ -172,8 +172,7 @@ public static void save(Context context, String key, String value) {
if (!preferencesEditor.commit()) throw new AssertionError("failed to save identity key/value to shared preferences");
}

private static void delete(Context context, String key) {
public static void delete(Context context, String key) {
context.getSharedPreferences(MasterSecretUtil.PREFERENCES_NAME, 0).edit().remove(key).commit();
}

}
7 changes: 1 addition & 6 deletions src/org/thoughtcrime/securesms/database/DatabaseFactory.java
Expand Up @@ -31,12 +31,7 @@
import org.thoughtcrime.securesms.database.helpers.ClassicOpenHelper;
import org.thoughtcrime.securesms.database.helpers.SQLCipherMigrationHelper;
import org.thoughtcrime.securesms.database.helpers.SQLCipherOpenHelper;
import org.thoughtcrime.securesms.loki.LokiAPIDatabase;
import org.thoughtcrime.securesms.loki.LokiPreKeyRecordDatabase;
import org.thoughtcrime.securesms.loki.LokiPreKeyBundleDatabase;
import org.thoughtcrime.securesms.loki.LokiMessageDatabase;
import org.thoughtcrime.securesms.loki.LokiThreadDatabase;
import org.thoughtcrime.securesms.loki.LokiUserDatabase;
import org.thoughtcrime.securesms.loki.*;
import org.thoughtcrime.securesms.util.TextSecurePreferences;

public class DatabaseFactory {
Expand Down
Expand Up @@ -35,12 +35,7 @@
import org.thoughtcrime.securesms.database.ThreadDatabase;
import org.thoughtcrime.securesms.jobs.RefreshPreKeysJob;
import org.thoughtcrime.securesms.logging.Log;
import org.thoughtcrime.securesms.loki.LokiAPIDatabase;
import org.thoughtcrime.securesms.loki.LokiPreKeyRecordDatabase;
import org.thoughtcrime.securesms.loki.LokiMessageDatabase;
import org.thoughtcrime.securesms.loki.LokiPreKeyBundleDatabase;
import org.thoughtcrime.securesms.loki.LokiThreadDatabase;
import org.thoughtcrime.securesms.loki.LokiUserDatabase;
import org.thoughtcrime.securesms.loki.*;
import org.thoughtcrime.securesms.notifications.NotificationChannels;
import org.thoughtcrime.securesms.service.KeyCachingService;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
Expand Down Expand Up @@ -74,6 +69,7 @@ public class SQLCipherOpenHelper extends SQLiteOpenHelper {
private static final int STICKERS = 21;
private static final int lokiV1 = 22;
private static final int lokiV2 = 23;
private static final int lokiV3 = 24;

private static final int DATABASE_VERSION = lokiV2; // Loki - onUpgrade(...) must be updated to use Loki version numbers if Signal makes any database changes
private static final String DATABASE_NAME = "signal.db";
Expand Down Expand Up @@ -129,6 +125,7 @@ public void onCreate(SQLiteDatabase db) {
db.execSQL(LokiAPIDatabase.getCreateGroupChatAuthTokenTableCommand());
db.execSQL(LokiAPIDatabase.getCreateLastMessageServerIDTableCommand());
db.execSQL(LokiAPIDatabase.getCreateLastDeletionServerIDTableCommand());
db.execSQL(LokiAPIDatabase.getCreatePairingAuthorisationTableCommand());
db.execSQL(LokiPreKeyBundleDatabase.getCreateTableCommand());
db.execSQL(LokiPreKeyRecordDatabase.getCreateTableCommand());
db.execSQL(LokiMessageDatabase.getCreateTableCommand());
Expand Down Expand Up @@ -498,6 +495,10 @@ public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
db.execSQL(LokiUserDatabase.getCreateServerDisplayNameTableCommand());
}

if (oldVersion < lokiV3) {
db.execSQL(LokiAPIDatabase.getCreatePairingAuthorisationTableCommand());
}

db.setTransactionSuccessful();
} finally {
db.endTransaction();
Expand Down