mirror of
https://github.com/oxen-io/session-android.git
synced 2025-06-08 23:18:34 +00:00
Migrate profile key into database.
This commit is contained in:
parent
b92c389a5b
commit
f10d1eac61
@ -1,38 +1,25 @@
|
||||
package org.thoughtcrime.securesms.crypto;
|
||||
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import org.thoughtcrime.securesms.util.Base64;
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||
import org.thoughtcrime.securesms.util.Util;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
|
||||
import java.io.IOException;
|
||||
public final class ProfileKeyUtil {
|
||||
|
||||
public class ProfileKeyUtil {
|
||||
|
||||
public static synchronized boolean hasProfileKey(@NonNull Context context) {
|
||||
return TextSecurePreferences.getProfileKey(context) != null;
|
||||
private ProfileKeyUtil() {
|
||||
}
|
||||
|
||||
public static synchronized @NonNull byte[] getProfileKey(@NonNull Context context) {
|
||||
try {
|
||||
String encodedProfileKey = TextSecurePreferences.getProfileKey(context);
|
||||
|
||||
if (encodedProfileKey == null) {
|
||||
encodedProfileKey = Util.getSecret(32);
|
||||
TextSecurePreferences.setProfileKey(context, encodedProfileKey);
|
||||
}
|
||||
|
||||
return Base64.decode(encodedProfileKey);
|
||||
} catch (IOException e) {
|
||||
throw new AssertionError(e);
|
||||
/**
|
||||
* @deprecated Will inline later as part of Versioned profiles.
|
||||
*/
|
||||
@Deprecated
|
||||
public static @NonNull byte[] getProfileKey(@NonNull Context context) {
|
||||
byte[] profileKey = Recipient.self().getProfileKey();
|
||||
if (profileKey == null) {
|
||||
throw new AssertionError();
|
||||
}
|
||||
}
|
||||
|
||||
public static synchronized @NonNull byte[] rotateProfileKey(@NonNull Context context) {
|
||||
TextSecurePreferences.setProfileKey(context, null);
|
||||
return getProfileKey(context);
|
||||
return profileKey;
|
||||
}
|
||||
}
|
||||
|
@ -42,7 +42,7 @@ public class UnidentifiedAccessUtil {
|
||||
{
|
||||
try {
|
||||
byte[] theirUnidentifiedAccessKey = getTargetUnidentifiedAccessKey(recipient);
|
||||
byte[] ourUnidentifiedAccessKey = getSelfUnidentifiedAccessKey(context);
|
||||
byte[] ourUnidentifiedAccessKey = getSelfUnidentifiedAccessKey(ProfileKeyUtil.getProfileKey(context));
|
||||
byte[] ourUnidentifiedAccessCertificate = recipient.resolve().isUuidSupported() && Recipient.self().isUuidSupported()
|
||||
? TextSecurePreferences.getUnidentifiedAccessCertificate(context)
|
||||
: TextSecurePreferences.getUnidentifiedAccessCertificateLegacy(context);
|
||||
@ -75,7 +75,7 @@ public class UnidentifiedAccessUtil {
|
||||
|
||||
public static Optional<UnidentifiedAccessPair> getAccessForSync(@NonNull Context context) {
|
||||
try {
|
||||
byte[] ourUnidentifiedAccessKey = getSelfUnidentifiedAccessKey(context);
|
||||
byte[] ourUnidentifiedAccessKey = getSelfUnidentifiedAccessKey(ProfileKeyUtil.getProfileKey(context));
|
||||
byte[] ourUnidentifiedAccessCertificate = Recipient.self().isUuidSupported() ? TextSecurePreferences.getUnidentifiedAccessCertificate(context)
|
||||
: TextSecurePreferences.getUnidentifiedAccessCertificateLegacy(context);
|
||||
|
||||
@ -97,8 +97,8 @@ public class UnidentifiedAccessUtil {
|
||||
}
|
||||
}
|
||||
|
||||
public static @NonNull byte[] getSelfUnidentifiedAccessKey(@NonNull Context context) {
|
||||
return UnidentifiedAccess.deriveAccessKeyFrom(ProfileKeyUtil.getProfileKey(context));
|
||||
public static @NonNull byte[] getSelfUnidentifiedAccessKey(@NonNull byte[] selfProfileKey) {
|
||||
return UnidentifiedAccess.deriveAccessKeyFrom(selfProfileKey);
|
||||
}
|
||||
|
||||
private static @Nullable byte[] getTargetUnidentifiedAccessKey(@NonNull Recipient recipient) {
|
||||
|
@ -34,8 +34,8 @@ import org.whispersystems.libsignal.InvalidKeyException;
|
||||
import org.whispersystems.libsignal.util.Pair;
|
||||
import org.whispersystems.libsignal.util.guava.Optional;
|
||||
import org.whispersystems.signalservice.api.push.SignalServiceAddress;
|
||||
import org.whispersystems.signalservice.api.util.UuidUtil;
|
||||
import org.whispersystems.signalservice.api.storage.SignalContactRecord;
|
||||
import org.whispersystems.signalservice.api.util.UuidUtil;
|
||||
|
||||
import java.io.Closeable;
|
||||
import java.io.IOException;
|
||||
|
@ -9,6 +9,7 @@ import android.database.Cursor;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.os.SystemClock;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
@ -47,10 +48,12 @@ import org.thoughtcrime.securesms.logging.Log;
|
||||
import org.thoughtcrime.securesms.notifications.NotificationChannels;
|
||||
import org.thoughtcrime.securesms.phonenumbers.PhoneNumberFormatter;
|
||||
import org.thoughtcrime.securesms.service.KeyCachingService;
|
||||
import org.thoughtcrime.securesms.util.Base64;
|
||||
import org.thoughtcrime.securesms.util.GroupUtil;
|
||||
import org.thoughtcrime.securesms.util.ServiceUtil;
|
||||
import org.thoughtcrime.securesms.util.SqlUtil;
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||
import org.thoughtcrime.securesms.util.Util;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.List;
|
||||
@ -105,8 +108,9 @@ public class SQLCipherOpenHelper extends SQLiteOpenHelper {
|
||||
private static final int STICKER_PACK_ORDER = 44;
|
||||
private static final int MEGAPHONES = 45;
|
||||
private static final int MEGAPHONE_FIRST_APPEARANCE = 46;
|
||||
private static final int PROFILE_KEY_TO_DB = 47;
|
||||
|
||||
private static final int DATABASE_VERSION = 46;
|
||||
private static final int DATABASE_VERSION = 47;
|
||||
private static final String DATABASE_NAME = "signal.db";
|
||||
|
||||
private final Context context;
|
||||
@ -724,6 +728,21 @@ public class SQLCipherOpenHelper extends SQLiteOpenHelper {
|
||||
db.execSQL("ALTER TABLE megaphone ADD COLUMN first_visible INTEGER DEFAULT 0");
|
||||
}
|
||||
|
||||
if (oldVersion < PROFILE_KEY_TO_DB) {
|
||||
String localNumber = TextSecurePreferences.getLocalNumber(context);
|
||||
if (!TextUtils.isEmpty(localNumber)) {
|
||||
String encodedProfileKey = PreferenceManager.getDefaultSharedPreferences(context).getString("pref_profile_key", null);
|
||||
byte[] profileKey = encodedProfileKey != null ? Base64.decodeOrThrow(encodedProfileKey) : Util.getSecretBytes(32);
|
||||
ContentValues values = new ContentValues(1);
|
||||
|
||||
values.put("profile_key", Base64.encodeBytes(profileKey));
|
||||
|
||||
if (db.update("recipient", values, "phone = ?", new String[]{localNumber}) == 0) {
|
||||
throw new AssertionError("No rows updated!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
db.setTransactionSuccessful();
|
||||
} finally {
|
||||
db.endTransaction();
|
||||
|
@ -4,15 +4,14 @@ import android.content.res.AssetFileDescriptor;
|
||||
import android.database.Cursor;
|
||||
import android.net.Uri;
|
||||
import android.provider.ContactsContract;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import org.thoughtcrime.securesms.ApplicationContext;
|
||||
import org.thoughtcrime.securesms.crypto.ProfileKeyUtil;
|
||||
import org.thoughtcrime.securesms.crypto.UnidentifiedAccessUtil;
|
||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||
import org.thoughtcrime.securesms.database.IdentityDatabase;
|
||||
import org.thoughtcrime.securesms.database.ThreadDatabase;
|
||||
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
|
||||
import org.thoughtcrime.securesms.jobmanager.Data;
|
||||
import org.thoughtcrime.securesms.jobmanager.Job;
|
||||
@ -42,8 +41,6 @@ import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
@ -201,14 +198,17 @@ public class MultiDeviceContactUpdateJob extends BaseJob {
|
||||
archived.contains(recipient.getId())));
|
||||
}
|
||||
|
||||
if (ProfileKeyUtil.hasProfileKey(context)) {
|
||||
Recipient self = Recipient.self();
|
||||
|
||||
Recipient self = Recipient.self();
|
||||
byte[] profileKey = self.getProfileKey();
|
||||
|
||||
if (profileKey != null) {
|
||||
out.write(new DeviceContact(RecipientUtil.toSignalServiceAddress(context, self),
|
||||
Optional.absent(),
|
||||
Optional.absent(),
|
||||
Optional.of(self.getColor().serialize()),
|
||||
Optional.absent(),
|
||||
Optional.of(ProfileKeyUtil.getProfileKey(context)),
|
||||
Optional.of(profileKey),
|
||||
false,
|
||||
self.getExpireMessages() > 0 ? Optional.of(self.getExpireMessages()) : Optional.absent(),
|
||||
Optional.fromNullable(inboxPositions.get(self.getId())),
|
||||
|
@ -2,6 +2,7 @@ package org.thoughtcrime.securesms.jobs;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import org.thoughtcrime.securesms.crypto.ProfileKeyUtil;
|
||||
import org.thoughtcrime.securesms.crypto.UnidentifiedAccessUtil;
|
||||
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
|
||||
import org.thoughtcrime.securesms.jobmanager.Data;
|
||||
@ -47,7 +48,7 @@ public class RefreshAttributesJob extends BaseJob {
|
||||
public void onRun() throws IOException {
|
||||
int registrationId = TextSecurePreferences.getLocalRegistrationId(context);
|
||||
boolean fetchesMessages = TextSecurePreferences.isFcmDisabled(context);
|
||||
byte[] unidentifiedAccessKey = UnidentifiedAccessUtil.getSelfUnidentifiedAccessKey(context);
|
||||
byte[] unidentifiedAccessKey = UnidentifiedAccessUtil.getSelfUnidentifiedAccessKey(ProfileKeyUtil.getProfileKey(context));
|
||||
boolean universalUnidentifiedAccess = TextSecurePreferences.isUniversalUnidentifiedAccess(context);
|
||||
String pin = null;
|
||||
String registrationLockToken = null;
|
||||
|
@ -3,7 +3,8 @@ package org.thoughtcrime.securesms.jobs;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import org.thoughtcrime.securesms.crypto.ProfileKeyUtil;
|
||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||
import org.thoughtcrime.securesms.database.RecipientDatabase;
|
||||
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
|
||||
import org.thoughtcrime.securesms.jobmanager.Data;
|
||||
import org.thoughtcrime.securesms.jobmanager.Job;
|
||||
@ -14,6 +15,7 @@ import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||
import org.whispersystems.signalservice.api.SignalServiceAccountManager;
|
||||
import org.whispersystems.signalservice.api.push.exceptions.PushNetworkException;
|
||||
import org.whispersystems.signalservice.api.util.StreamDetails;
|
||||
import org.whispersystems.signalservice.internal.util.Util;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
@ -48,9 +50,12 @@ public class RotateProfileKeyJob extends BaseJob {
|
||||
|
||||
@Override
|
||||
public void onRun() throws Exception {
|
||||
SignalServiceAccountManager accountManager = ApplicationDependencies.getSignalServiceAccountManager();
|
||||
byte[] profileKey = ProfileKeyUtil.rotateProfileKey(context);
|
||||
SignalServiceAccountManager accountManager = ApplicationDependencies.getSignalServiceAccountManager();
|
||||
RecipientDatabase recipientDatabase = DatabaseFactory.getRecipientDatabase(context);
|
||||
byte[] profileKey = Util.getSecretBytes(32);
|
||||
Recipient self = Recipient.self();
|
||||
|
||||
recipientDatabase.setProfileKey(self.getId(), profileKey);
|
||||
accountManager.setProfileName(profileKey, TextSecurePreferences.getProfileName(context).serialize());
|
||||
accountManager.setProfileAvatar(profileKey, getProfileAvatar());
|
||||
|
||||
|
@ -7,9 +7,8 @@ import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import org.thoughtcrime.securesms.color.MaterialColor;
|
||||
import org.thoughtcrime.securesms.database.RecipientDatabase.InsightsBannerTier;
|
||||
import org.thoughtcrime.securesms.crypto.ProfileKeyUtil;
|
||||
import org.thoughtcrime.securesms.database.IdentityDatabase.VerifiedStatus;
|
||||
import org.thoughtcrime.securesms.database.RecipientDatabase.InsightsBannerTier;
|
||||
import org.thoughtcrime.securesms.database.RecipientDatabase.RecipientSettings;
|
||||
import org.thoughtcrime.securesms.database.RecipientDatabase.RegisteredState;
|
||||
import org.thoughtcrime.securesms.database.RecipientDatabase.UnidentifiedAccessMode;
|
||||
@ -90,7 +89,7 @@ public class RecipientDetails {
|
||||
this.profileName = isLocalNumber ? TextSecurePreferences.getProfileName(context) : settings.getProfileName();
|
||||
this.defaultSubscriptionId = settings.getDefaultSubscriptionId();
|
||||
this.registered = settings.getRegistered();
|
||||
this.profileKey = isLocalNumber ? ProfileKeyUtil.getProfileKey(context) : settings.getProfileKey();
|
||||
this.profileKey = settings.getProfileKey();
|
||||
this.profileAvatar = settings.getProfileAvatar();
|
||||
this.profileSharing = settings.isProfileSharing();
|
||||
this.systemContact = systemContact;
|
||||
|
@ -22,12 +22,13 @@ import org.thoughtcrime.securesms.keyvalue.SignalStore;
|
||||
import org.thoughtcrime.securesms.lock.PinHashing;
|
||||
import org.thoughtcrime.securesms.lock.RegistrationLockReminders;
|
||||
import org.thoughtcrime.securesms.logging.Log;
|
||||
import org.thoughtcrime.securesms.migrations.RegistrationPinV2MigrationJob;
|
||||
import org.thoughtcrime.securesms.push.AccountManagerFactory;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.recipients.RecipientId;
|
||||
import org.thoughtcrime.securesms.service.DirectoryRefreshListener;
|
||||
import org.thoughtcrime.securesms.service.RotateSignedPreKeyListener;
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||
import org.thoughtcrime.securesms.util.Util;
|
||||
import org.whispersystems.libsignal.IdentityKeyPair;
|
||||
import org.whispersystems.libsignal.state.PreKeyRecord;
|
||||
import org.whispersystems.libsignal.state.SignedPreKeyRecord;
|
||||
@ -192,8 +193,15 @@ public final class CodeVerificationRequest {
|
||||
{
|
||||
boolean isV2KbsPin = kbsTokenResponse != null;
|
||||
int registrationId = KeyHelper.generateRegistrationId(false);
|
||||
byte[] unidentifiedAccessKey = UnidentifiedAccessUtil.getSelfUnidentifiedAccessKey(context);
|
||||
boolean universalUnidentifiedAccess = TextSecurePreferences.isUniversalUnidentifiedAccess(context);
|
||||
byte[] profileKey = findExistingProfileKey(context, credentials.getE164number());
|
||||
|
||||
if (profileKey == null) {
|
||||
profileKey = Util.getSecretBytes(32);
|
||||
Log.i(TAG, "No profile key found, created a new one");
|
||||
}
|
||||
|
||||
byte[] unidentifiedAccessKey = UnidentifiedAccessUtil.getSelfUnidentifiedAccessKey(profileKey);
|
||||
|
||||
TextSecurePreferences.setLocalRegistrationId(context, registrationId);
|
||||
SessionUtil.archiveAllSessions(context);
|
||||
@ -227,6 +235,7 @@ public final class CodeVerificationRequest {
|
||||
|
||||
TextSecurePreferences.setLocalNumber(context, credentials.getE164number());
|
||||
TextSecurePreferences.setLocalUuid(context, uuid);
|
||||
recipientDatabase.setProfileKey(selfId, profileKey);
|
||||
ApplicationDependencies.getRecipientCache().clearSelf();
|
||||
|
||||
TextSecurePreferences.setFcmToken(context, fcmToken);
|
||||
@ -260,6 +269,17 @@ public final class CodeVerificationRequest {
|
||||
}
|
||||
}
|
||||
|
||||
private static @Nullable byte[] findExistingProfileKey(@NonNull Context context, @NonNull String e164number) {
|
||||
RecipientDatabase recipientDatabase = DatabaseFactory.getRecipientDatabase(context);
|
||||
Optional<RecipientId> recipient = recipientDatabase.getByE164(e164number);
|
||||
|
||||
if (recipient.isPresent()) {
|
||||
return Recipient.resolved(recipient.get()).getProfileKey();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static void repostPinToResetTries(@NonNull Context context, @Nullable String pin, @NonNull RegistrationLockData kbsData) {
|
||||
if (pin == null) return;
|
||||
|
||||
|
@ -16,4 +16,12 @@ public final class Base64 {
|
||||
public static @NonNull String encodeBytes(@NonNull byte[] source) {
|
||||
return org.whispersystems.util.Base64.encodeBytes(source);
|
||||
}
|
||||
|
||||
public static @NonNull byte[] decodeOrThrow(@NonNull String s) {
|
||||
try {
|
||||
return org.whispersystems.util.Base64.decode(s);
|
||||
} catch (IOException e) {
|
||||
throw new AssertionError();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -123,7 +123,6 @@ public class TextSecurePreferences {
|
||||
private static final String MULTI_DEVICE_PROVISIONED_PREF = "pref_multi_device";
|
||||
public static final String DIRECT_CAPTURE_CAMERA_ID = "pref_direct_capture_camera_id";
|
||||
private static final String ALWAYS_RELAY_CALLS_PREF = "pref_turn_only";
|
||||
private static final String PROFILE_KEY_PREF = "pref_profile_key";
|
||||
private static final String PROFILE_NAME_PREF = "pref_profile_name";
|
||||
private static final String PROFILE_AVATAR_ID_PREF = "pref_profile_avatar_id";
|
||||
public static final String READ_RECEIPTS_PREF = "pref_read_receipts";
|
||||
@ -435,14 +434,6 @@ public class TextSecurePreferences {
|
||||
setBooleanPreference(context, GIF_GRID_LAYOUT, isGrid);
|
||||
}
|
||||
|
||||
public static @Nullable String getProfileKey(Context context) {
|
||||
return getStringPreference(context, PROFILE_KEY_PREF, null);
|
||||
}
|
||||
|
||||
public static void setProfileKey(Context context, String key) {
|
||||
setStringPreference(context, PROFILE_KEY_PREF, key);
|
||||
}
|
||||
|
||||
public static void setProfileName(Context context, ProfileName name) {
|
||||
setStringPreference(context, PROFILE_NAME_PREF, name.serialize());
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user