mirror of
https://github.com/oxen-io/session-android.git
synced 2025-06-09 14:38:33 +00:00
KBS remote feature flag.
This commit is contained in:
parent
ba6e1ab15a
commit
fea2b6253f
@ -35,6 +35,7 @@ import org.thoughtcrime.securesms.keyvalue.KbsValues;
|
|||||||
import org.thoughtcrime.securesms.keyvalue.SignalStore;
|
import org.thoughtcrime.securesms.keyvalue.SignalStore;
|
||||||
import org.thoughtcrime.securesms.logging.Log;
|
import org.thoughtcrime.securesms.logging.Log;
|
||||||
import org.thoughtcrime.securesms.migrations.RegistrationPinV2MigrationJob;
|
import org.thoughtcrime.securesms.migrations.RegistrationPinV2MigrationJob;
|
||||||
|
import org.thoughtcrime.securesms.util.FeatureFlags;
|
||||||
import org.thoughtcrime.securesms.util.ServiceUtil;
|
import org.thoughtcrime.securesms.util.ServiceUtil;
|
||||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||||
import org.thoughtcrime.securesms.util.ThemeUtil;
|
import org.thoughtcrime.securesms.util.ThemeUtil;
|
||||||
@ -125,8 +126,10 @@ public final class RegistrationLockDialog {
|
|||||||
dialog.dismiss();
|
dialog.dismiss();
|
||||||
RegistrationLockReminders.scheduleReminder(context, true);
|
RegistrationLockReminders.scheduleReminder(context, true);
|
||||||
|
|
||||||
Log.i(TAG, "Pin V1 successfully remembered, scheduling a migration to V2");
|
if (FeatureFlags.kbs()) {
|
||||||
ApplicationDependencies.getJobManager().add(new RegistrationPinV2MigrationJob());
|
Log.i(TAG, "Pin V1 successfully remembered, scheduling a migration to V2");
|
||||||
|
ApplicationDependencies.getJobManager().add(new RegistrationPinV2MigrationJob());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -198,25 +201,32 @@ public final class RegistrationLockDialog {
|
|||||||
@Override
|
@Override
|
||||||
protected Boolean doInBackground(Void... voids) {
|
protected Boolean doInBackground(Void... voids) {
|
||||||
try {
|
try {
|
||||||
Log.i(TAG, "Setting pin on KBS");
|
if (FeatureFlags.kbs()) {
|
||||||
|
Log.i(TAG, "Setting pin on KBS");
|
||||||
|
|
||||||
KbsValues kbsValues = SignalStore.kbsValues();
|
KbsValues kbsValues = SignalStore.kbsValues();
|
||||||
MasterKey masterKey = kbsValues.getOrCreateMasterKey();
|
MasterKey masterKey = kbsValues.getOrCreateMasterKey();
|
||||||
KeyBackupService keyBackupService = ApplicationDependencies.getKeyBackupService();
|
KeyBackupService keyBackupService = ApplicationDependencies.getKeyBackupService();
|
||||||
KeyBackupService.PinChangeSession pinChangeSession = keyBackupService.newPinChangeSession();
|
KeyBackupService.PinChangeSession pinChangeSession = keyBackupService.newPinChangeSession();
|
||||||
HashedPin hashedPin = PinHashing.hashPin(pinValue, pinChangeSession);
|
HashedPin hashedPin = PinHashing.hashPin(pinValue, pinChangeSession);
|
||||||
RegistrationLockData kbsData = pinChangeSession.setPin(hashedPin, masterKey);
|
RegistrationLockData kbsData = pinChangeSession.setPin(hashedPin, masterKey);
|
||||||
RegistrationLockData restoredData = keyBackupService.newRestoreSession(kbsData.getTokenResponse())
|
RegistrationLockData restoredData = keyBackupService.newRestoreSession(kbsData.getTokenResponse())
|
||||||
.restorePin(hashedPin);
|
.restorePin(hashedPin);
|
||||||
|
|
||||||
if (!restoredData.getMasterKey().equals(masterKey)) {
|
if (!restoredData.getMasterKey().equals(masterKey)) {
|
||||||
throw new AssertionError("Failed to set the pin correctly");
|
throw new AssertionError("Failed to set the pin correctly");
|
||||||
|
} else {
|
||||||
|
Log.i(TAG, "Set and retrieved pin on KBS successfully");
|
||||||
|
}
|
||||||
|
|
||||||
|
kbsValues.setRegistrationLockMasterKey(restoredData, PinHashing.localPinHash(pinValue));
|
||||||
|
TextSecurePreferences.clearOldRegistrationLockPin(context);
|
||||||
} else {
|
} else {
|
||||||
Log.i(TAG, "Set and retrieved pin on KBS successfully");
|
Log.i(TAG, "Setting V1 pin");
|
||||||
|
SignalServiceAccountManager accountManager = ApplicationDependencies.getSignalServiceAccountManager();
|
||||||
|
accountManager.setPin(pinValue);
|
||||||
|
TextSecurePreferences.setDeprecatedRegistrationLockPin(context, pinValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
kbsValues.setRegistrationLockMasterKey(restoredData, PinHashing.localPinHash(pinValue));
|
|
||||||
TextSecurePreferences.clearOldRegistrationLockPin(context);
|
|
||||||
TextSecurePreferences.setRegistrationLockLastReminderTime(context, System.currentTimeMillis());
|
TextSecurePreferences.setRegistrationLockLastReminderTime(context, System.currentTimeMillis());
|
||||||
TextSecurePreferences.setRegistrationLockNextReminderInterval(context, RegistrationLockReminders.INITIAL_INTERVAL);
|
TextSecurePreferences.setRegistrationLockNextReminderInterval(context, RegistrationLockReminders.INITIAL_INTERVAL);
|
||||||
return true;
|
return true;
|
||||||
@ -272,13 +282,16 @@ public final class RegistrationLockDialog {
|
|||||||
@Override
|
@Override
|
||||||
protected Boolean doInBackground(Void... voids) {
|
protected Boolean doInBackground(Void... voids) {
|
||||||
try {
|
try {
|
||||||
Log.i(TAG, "Removing v2 registration lock pin from server");
|
KbsValues kbsValues = SignalStore.kbsValues();
|
||||||
KbsValues kbsValues = SignalStore.kbsValues();
|
|
||||||
TokenResponse currentToken = kbsValues.getRegistrationLockTokenResponse();
|
|
||||||
|
|
||||||
KeyBackupService keyBackupService = ApplicationDependencies.getKeyBackupService();
|
if (kbsValues.isV2RegistrationLockEnabled()) {
|
||||||
keyBackupService.newPinChangeSession(currentToken).removePin();
|
Log.i(TAG, "Removing v2 registration lock pin from server");
|
||||||
kbsValues.clearRegistrationLock();
|
TokenResponse currentToken = kbsValues.getRegistrationLockTokenResponse();
|
||||||
|
|
||||||
|
KeyBackupService keyBackupService = ApplicationDependencies.getKeyBackupService();
|
||||||
|
keyBackupService.newPinChangeSession(currentToken).removePin();
|
||||||
|
kbsValues.clearRegistrationLock();
|
||||||
|
}
|
||||||
|
|
||||||
// It is possible a migration has not occurred, in this case, we need to remove the old V1 Pin
|
// It is possible a migration has not occurred, in this case, we need to remove the old V1 Pin
|
||||||
if (TextSecurePreferences.isV1RegistrationLockEnabled(context)) {
|
if (TextSecurePreferences.isV1RegistrationLockEnabled(context)) {
|
||||||
|
@ -13,6 +13,7 @@ import org.thoughtcrime.securesms.keyvalue.KbsValues;
|
|||||||
import org.thoughtcrime.securesms.keyvalue.SignalStore;
|
import org.thoughtcrime.securesms.keyvalue.SignalStore;
|
||||||
import org.thoughtcrime.securesms.lock.PinHashing;
|
import org.thoughtcrime.securesms.lock.PinHashing;
|
||||||
import org.thoughtcrime.securesms.logging.Log;
|
import org.thoughtcrime.securesms.logging.Log;
|
||||||
|
import org.thoughtcrime.securesms.util.FeatureFlags;
|
||||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||||
import org.whispersystems.signalservice.api.KeyBackupService;
|
import org.whispersystems.signalservice.api.KeyBackupService;
|
||||||
import org.whispersystems.signalservice.api.KeyBackupServicePinException;
|
import org.whispersystems.signalservice.api.KeyBackupServicePinException;
|
||||||
@ -56,6 +57,11 @@ public final class RegistrationPinV2MigrationJob extends BaseJob {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onRun() throws IOException, UnauthenticatedResponseException, KeyBackupServicePinException {
|
protected void onRun() throws IOException, UnauthenticatedResponseException, KeyBackupServicePinException {
|
||||||
|
if (!FeatureFlags.kbs()) {
|
||||||
|
Log.i(TAG, "Not migrating pin to KBS");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (!TextSecurePreferences.isV1RegistrationLockEnabled(context)) {
|
if (!TextSecurePreferences.isV1RegistrationLockEnabled(context)) {
|
||||||
Log.i(TAG, "Registration lock disabled");
|
Log.i(TAG, "Registration lock disabled");
|
||||||
return;
|
return;
|
||||||
|
@ -27,6 +27,7 @@ import org.thoughtcrime.securesms.push.AccountManagerFactory;
|
|||||||
import org.thoughtcrime.securesms.recipients.RecipientId;
|
import org.thoughtcrime.securesms.recipients.RecipientId;
|
||||||
import org.thoughtcrime.securesms.service.DirectoryRefreshListener;
|
import org.thoughtcrime.securesms.service.DirectoryRefreshListener;
|
||||||
import org.thoughtcrime.securesms.service.RotateSignedPreKeyListener;
|
import org.thoughtcrime.securesms.service.RotateSignedPreKeyListener;
|
||||||
|
import org.thoughtcrime.securesms.util.FeatureFlags;
|
||||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||||
import org.whispersystems.libsignal.IdentityKeyPair;
|
import org.whispersystems.libsignal.IdentityKeyPair;
|
||||||
import org.whispersystems.libsignal.state.PreKeyRecord;
|
import org.whispersystems.libsignal.state.PreKeyRecord;
|
||||||
@ -212,8 +213,10 @@ public final class CodeVerificationRequest {
|
|||||||
//noinspection deprecation Only acceptable place to write the old pin enabled state.
|
//noinspection deprecation Only acceptable place to write the old pin enabled state.
|
||||||
TextSecurePreferences.setV1RegistrationLockEnabled(context, pin != null);
|
TextSecurePreferences.setV1RegistrationLockEnabled(context, pin != null);
|
||||||
if (pin != null) {
|
if (pin != null) {
|
||||||
Log.i(TAG, "Pin V1 successfully entered during registration, scheduling a migration to Pin V2");
|
if (FeatureFlags.kbs()) {
|
||||||
ApplicationDependencies.getJobManager().add(new RegistrationPinV2MigrationJob());
|
Log.i(TAG, "Pin V1 successfully entered during registration, scheduling a migration to Pin V2");
|
||||||
|
ApplicationDependencies.getJobManager().add(new RegistrationPinV2MigrationJob());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
SignalStore.kbsValues().setRegistrationLockMasterKey(kbsData, PinHashing.localPinHash(pin));
|
SignalStore.kbsValues().setRegistrationLockMasterKey(kbsData, PinHashing.localPinHash(pin));
|
||||||
|
@ -6,6 +6,7 @@ import androidx.annotation.NonNull;
|
|||||||
import androidx.annotation.VisibleForTesting;
|
import androidx.annotation.VisibleForTesting;
|
||||||
|
|
||||||
import com.annimon.stream.Stream;
|
import com.annimon.stream.Stream;
|
||||||
|
import com.google.android.collect.Sets;
|
||||||
|
|
||||||
import org.json.JSONException;
|
import org.json.JSONException;
|
||||||
import org.json.JSONObject;
|
import org.json.JSONObject;
|
||||||
@ -20,7 +21,6 @@ import java.util.Iterator;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.TreeMap;
|
import java.util.TreeMap;
|
||||||
import java.util.TreeSet;
|
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -50,6 +50,7 @@ public final class FeatureFlags {
|
|||||||
private static final String PROFILE_DISPLAY = generateKey("profileDisplay");
|
private static final String PROFILE_DISPLAY = generateKey("profileDisplay");
|
||||||
private static final String MESSAGE_REQUESTS = generateKey("messageRequests");
|
private static final String MESSAGE_REQUESTS = generateKey("messageRequests");
|
||||||
private static final String USERNAMES = generateKey("usernames");
|
private static final String USERNAMES = generateKey("usernames");
|
||||||
|
private static final String KBS = generateKey("kbs");
|
||||||
private static final String STORAGE_SERVICE = generateKey("storageService");
|
private static final String STORAGE_SERVICE = generateKey("storageService");
|
||||||
private static final String REACTION_SENDING = generateKey("reactionSending");
|
private static final String REACTION_SENDING = generateKey("reactionSending");
|
||||||
|
|
||||||
@ -73,14 +74,15 @@ public final class FeatureFlags {
|
|||||||
* will be updated arbitrarily at runtime. This will make values more responsive, but also places
|
* will be updated arbitrarily at runtime. This will make values more responsive, but also places
|
||||||
* more burden on the reader to ensure that the app experience remains consistent.
|
* more burden on the reader to ensure that the app experience remains consistent.
|
||||||
*/
|
*/
|
||||||
private static final Set<String> HOT_SWAPPABLE = new TreeSet<String>() {{
|
private static final Set<String> HOT_SWAPPABLE = Sets.newHashSet(
|
||||||
}};
|
KBS
|
||||||
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Flags in this set will stay true forever once they receive a true value from a remote config.
|
* Flags in this set will stay true forever once they receive a true value from a remote config.
|
||||||
*/
|
*/
|
||||||
private static final Set<String> STICKY = new HashSet<String>() {{
|
private static final Set<String> STICKY = Sets.newHashSet(
|
||||||
}};
|
);
|
||||||
|
|
||||||
private static final Map<String, Boolean> REMOTE_VALUES = new TreeMap<>();
|
private static final Map<String, Boolean> REMOTE_VALUES = new TreeMap<>();
|
||||||
|
|
||||||
@ -139,9 +141,16 @@ public final class FeatureFlags {
|
|||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Storage service. */
|
/** Set or migrate PIN to KBS */
|
||||||
public static synchronized boolean storageService() {
|
public static boolean kbs() {
|
||||||
return getValue(STORAGE_SERVICE, false);
|
return getValue(KBS, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Storage service. Requires {@link #kbs()}. */
|
||||||
|
public static boolean storageService() {
|
||||||
|
boolean value = getValue(STORAGE_SERVICE, false);
|
||||||
|
if (value && !kbs()) throw new MissingFlagRequirementError();
|
||||||
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Send support for reactions. */
|
/** Send support for reactions. */
|
||||||
|
@ -16,15 +16,12 @@ import androidx.core.app.NotificationCompat;
|
|||||||
import org.greenrobot.eventbus.EventBus;
|
import org.greenrobot.eventbus.EventBus;
|
||||||
import org.thoughtcrime.securesms.R;
|
import org.thoughtcrime.securesms.R;
|
||||||
import org.thoughtcrime.securesms.jobmanager.impl.SqlCipherMigrationConstraintObserver;
|
import org.thoughtcrime.securesms.jobmanager.impl.SqlCipherMigrationConstraintObserver;
|
||||||
import org.thoughtcrime.securesms.keyvalue.SignalStore;
|
|
||||||
import org.thoughtcrime.securesms.lock.RegistrationLockReminders;
|
import org.thoughtcrime.securesms.lock.RegistrationLockReminders;
|
||||||
import org.thoughtcrime.securesms.logging.Log;
|
import org.thoughtcrime.securesms.logging.Log;
|
||||||
import org.thoughtcrime.securesms.preferences.widgets.NotificationPrivacyPreference;
|
import org.thoughtcrime.securesms.preferences.widgets.NotificationPrivacyPreference;
|
||||||
import org.thoughtcrime.securesms.profiles.ProfileName;
|
import org.thoughtcrime.securesms.profiles.ProfileName;
|
||||||
import org.whispersystems.libsignal.util.Medium;
|
import org.whispersystems.libsignal.util.Medium;
|
||||||
import org.whispersystems.signalservice.api.RegistrationLockData;
|
|
||||||
import org.whispersystems.signalservice.api.util.UuidUtil;
|
import org.whispersystems.signalservice.api.util.UuidUtil;
|
||||||
import org.whispersystems.signalservice.internal.contacts.entities.TokenResponse;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.security.SecureRandom;
|
import java.security.SecureRandom;
|
||||||
@ -162,8 +159,9 @@ public class TextSecurePreferences {
|
|||||||
@Deprecated
|
@Deprecated
|
||||||
private static final String REGISTRATION_LOCK_PIN_PREF_V1 = "pref_registration_lock_pin";
|
private static final String REGISTRATION_LOCK_PIN_PREF_V1 = "pref_registration_lock_pin";
|
||||||
|
|
||||||
private static final String REGISTRATION_LOCK_LAST_REMINDER_TIME = "pref_registration_lock_last_reminder_time_2";
|
private static final String REGISTRATION_LOCK_LAST_REMINDER_TIME = "pref_registration_lock_last_reminder_time";
|
||||||
private static final String REGISTRATION_LOCK_NEXT_REMINDER_INTERVAL = "pref_registration_lock_next_reminder_interval";
|
private static final String REGISTRATION_LOCK_LAST_REMINDER_TIME_POST_KBS = "pref_registration_lock_last_reminder_time_post_kbs";
|
||||||
|
private static final String REGISTRATION_LOCK_NEXT_REMINDER_INTERVAL = "pref_registration_lock_next_reminder_interval";
|
||||||
|
|
||||||
private static final String SERVICE_OUTAGE = "pref_service_outage";
|
private static final String SERVICE_OUTAGE = "pref_service_outage";
|
||||||
private static final String LAST_OUTAGE_CHECK_TIME = "pref_last_outage_check_time";
|
private static final String LAST_OUTAGE_CHECK_TIME = "pref_last_outage_check_time";
|
||||||
@ -271,11 +269,16 @@ public class TextSecurePreferences {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static long getRegistrationLockLastReminderTime(@NonNull Context context) {
|
public static long getRegistrationLockLastReminderTime(@NonNull Context context) {
|
||||||
return getLongPreference(context, REGISTRATION_LOCK_LAST_REMINDER_TIME, 0);
|
return getLongPreference(context, getAppropriateReminderKey(), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void setRegistrationLockLastReminderTime(@NonNull Context context, long time) {
|
public static void setRegistrationLockLastReminderTime(@NonNull Context context, long time) {
|
||||||
setLongPreference(context, REGISTRATION_LOCK_LAST_REMINDER_TIME, time);
|
setLongPreference(context, getAppropriateReminderKey(), time);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String getAppropriateReminderKey() {
|
||||||
|
return FeatureFlags.kbs() ? REGISTRATION_LOCK_LAST_REMINDER_TIME_POST_KBS
|
||||||
|
: REGISTRATION_LOCK_LAST_REMINDER_TIME;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static long getRegistrationLockNextReminderInterval(@NonNull Context context) {
|
public static long getRegistrationLockNextReminderInterval(@NonNull Context context) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user