mirror of
https://github.com/signalapp/Signal-Android.git
synced 2026-04-23 10:20:25 +01:00
Separate PINs from Registration Lock.
You can now have a PIN without having registration lock. Note: We still need to change the registration flow to allow non-reglock users to enter their PIN.
This commit is contained in:
@@ -3,8 +3,10 @@ package org.thoughtcrime.securesms.keyvalue;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import org.thoughtcrime.securesms.logging.Log;
|
||||
import org.thoughtcrime.securesms.util.Base64;
|
||||
import org.thoughtcrime.securesms.util.JsonUtils;
|
||||
import org.whispersystems.signalservice.api.RegistrationLockData;
|
||||
import org.whispersystems.signalservice.api.KbsPinData;
|
||||
import org.whispersystems.signalservice.api.kbs.MasterKey;
|
||||
import org.whispersystems.signalservice.internal.contacts.entities.TokenResponse;
|
||||
|
||||
@@ -13,7 +15,7 @@ import java.security.SecureRandom;
|
||||
|
||||
public final class KbsValues {
|
||||
|
||||
private static final String V2_LOCK_ENABLED = "kbs.v2_lock_enabled";
|
||||
public static final String V2_LOCK_ENABLED = "kbs.v2_lock_enabled";
|
||||
private static final String MASTER_KEY = "kbs.registration_lock_master_key";
|
||||
private static final String TOKEN_RESPONSE = "kbs.token_response";
|
||||
private static final String LOCK_LOCAL_PIN_HASH = "kbs.registration_lock_local_pin_hash";
|
||||
@@ -27,7 +29,7 @@ public final class KbsValues {
|
||||
/**
|
||||
* Deliberately does not clear the {@link #MASTER_KEY}.
|
||||
*/
|
||||
public void clearRegistrationLock() {
|
||||
public void clearRegistrationLockAndPin() {
|
||||
store.beginWrite()
|
||||
.remove(V2_LOCK_ENABLED)
|
||||
.remove(TOKEN_RESPONSE)
|
||||
@@ -35,23 +37,30 @@ public final class KbsValues {
|
||||
.commit();
|
||||
}
|
||||
|
||||
public synchronized void setRegistrationLockMasterKey(@NonNull RegistrationLockData registrationLockData, @NonNull String localPinHash) {
|
||||
MasterKey masterKey = registrationLockData.getMasterKey();
|
||||
public synchronized void setKbsMasterKey(@NonNull KbsPinData pinData, @NonNull String localPinHash) {
|
||||
MasterKey masterKey = pinData.getMasterKey();
|
||||
String tokenResponse;
|
||||
try {
|
||||
tokenResponse = JsonUtils.toJson(registrationLockData.getTokenResponse());
|
||||
tokenResponse = JsonUtils.toJson(pinData.getTokenResponse());
|
||||
} catch (IOException e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
|
||||
store.beginWrite()
|
||||
.putBoolean(V2_LOCK_ENABLED, true)
|
||||
.putString(TOKEN_RESPONSE, tokenResponse)
|
||||
.putBlob(MASTER_KEY, masterKey.serialize())
|
||||
.putString(LOCK_LOCAL_PIN_HASH, localPinHash)
|
||||
.commit();
|
||||
}
|
||||
|
||||
public synchronized void setV2RegistrationLockEnabled(boolean enabled) {
|
||||
store.beginWrite().putBoolean(V2_LOCK_ENABLED, enabled).apply();
|
||||
}
|
||||
|
||||
public synchronized boolean isV2RegistrationLockEnabled() {
|
||||
return store.getBoolean(V2_LOCK_ENABLED, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds or creates the master key. Therefore this will always return a master key whether backed
|
||||
* up or not.
|
||||
@@ -97,8 +106,8 @@ public final class KbsValues {
|
||||
return store.getString(LOCK_LOCAL_PIN_HASH, null);
|
||||
}
|
||||
|
||||
public synchronized boolean isV2RegistrationLockEnabled() {
|
||||
return store.getBoolean(V2_LOCK_ENABLED, false);
|
||||
public synchronized boolean hasPin() {
|
||||
return getLocalPinHash() != null;
|
||||
}
|
||||
|
||||
public synchronized @Nullable TokenResponse getRegistrationLockTokenResponse() {
|
||||
|
||||
@@ -2,6 +2,7 @@ package org.thoughtcrime.securesms.keyvalue;
|
||||
|
||||
import androidx.annotation.CheckResult;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
|
||||
import org.thoughtcrime.securesms.lock.SignalPinReminders;
|
||||
@@ -19,6 +20,7 @@ public final class PinValues {
|
||||
private static final String LAST_SUCCESSFUL_ENTRY = "pin.last_successful_entry";
|
||||
private static final String NEXT_INTERVAL = "pin.interval_index";
|
||||
private static final String KEYBOARD_TYPE = "kbs.keyboard_type";
|
||||
private static final String PIN_STATE = "pin.pin_state";
|
||||
|
||||
private final KeyValueStore store;
|
||||
|
||||
@@ -55,9 +57,9 @@ public final class PinValues {
|
||||
.apply();
|
||||
}
|
||||
|
||||
public void onPinChange() {
|
||||
public void resetPinReminders() {
|
||||
long nextInterval = SignalPinReminders.INITIAL_INTERVAL;
|
||||
Log.i(TAG, "onPinChange() nextInterval: " + nextInterval);
|
||||
Log.i(TAG, "resetPinReminders() nextInterval: " + nextInterval, new Throwable());
|
||||
|
||||
store.beginWrite()
|
||||
.putLong(NEXT_INTERVAL, nextInterval)
|
||||
@@ -82,4 +84,12 @@ public final class PinValues {
|
||||
public @NonNull PinKeyboardType getKeyboardType() {
|
||||
return PinKeyboardType.fromCode(store.getString(KEYBOARD_TYPE, null));
|
||||
}
|
||||
|
||||
public void setPinState(@NonNull String pinState) {
|
||||
store.beginWrite().putString(PIN_STATE, pinState).commit();
|
||||
}
|
||||
|
||||
public @Nullable String getPinState() {
|
||||
return store.getString(PIN_STATE, null);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
package org.thoughtcrime.securesms.keyvalue;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.preference.PreferenceDataStore;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* An implementation of the {@link PreferenceDataStore} interface to let us link preference screens
|
||||
* to the {@link SignalStore}.
|
||||
*/
|
||||
public class SignalPreferenceDataStore extends PreferenceDataStore {
|
||||
|
||||
private final KeyValueStore store;
|
||||
|
||||
SignalPreferenceDataStore(@NonNull KeyValueStore store) {
|
||||
this.store = store;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void putString(String key, @Nullable String value) {
|
||||
store.beginWrite().putString(key, value).apply();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void putInt(String key, int value) {
|
||||
store.beginWrite().putInteger(key, value).apply();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void putLong(String key, long value) {
|
||||
store.beginWrite().putLong(key, value).apply();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void putFloat(String key, float value) {
|
||||
store.beginWrite().putFloat(key, value).apply();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void putBoolean(String key, boolean value) {
|
||||
store.beginWrite().putBoolean(key, value).apply();
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable String getString(String key, @Nullable String defValue) {
|
||||
return store.getString(key, defValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getInt(String key, int defValue) {
|
||||
return store.getInteger(key, defValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getLong(String key, long defValue) {
|
||||
return store.getLong(key, defValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getFloat(String key, float defValue) {
|
||||
return store.getFloat(key, defValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getBoolean(String key, boolean defValue) {
|
||||
return store.getBoolean(key, defValue);
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,10 @@
|
||||
package org.thoughtcrime.securesms.keyvalue;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.preference.PreferenceDataStore;
|
||||
|
||||
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
|
||||
import org.thoughtcrime.securesms.logging.SignalUncaughtExceptionHandler;
|
||||
import org.thoughtcrime.securesms.util.FeatureFlags;
|
||||
|
||||
/**
|
||||
* Simple, encrypted key-value store.
|
||||
@@ -56,6 +56,10 @@ public final class SignalStore {
|
||||
putLong(MESSAGE_REQUEST_ENABLE_TIME, time);
|
||||
}
|
||||
|
||||
public static @NonNull PreferenceDataStore getPreferenceDataStore() {
|
||||
return new SignalPreferenceDataStore(getStore());
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures any pending writes are finished. Only intended to be called by
|
||||
* {@link SignalUncaughtExceptionHandler}.
|
||||
|
||||
@@ -4,13 +4,13 @@ import androidx.annotation.NonNull;
|
||||
|
||||
import org.thoughtcrime.securesms.util.FeatureFlags;
|
||||
import org.whispersystems.signalservice.api.kbs.MasterKey;
|
||||
import org.whispersystems.signalservice.api.storage.StorageKey;
|
||||
|
||||
import java.security.SecureRandom;
|
||||
|
||||
public class StorageServiceValues {
|
||||
|
||||
private static final String STORAGE_MASTER_KEY = "storage.storage_master_key";
|
||||
private static final String LAST_SYNC_TIME = "storage.last_sync_time";
|
||||
private static final String LAST_SYNC_TIME = "storage.last_sync_time";
|
||||
|
||||
private final KeyValueStore store;
|
||||
|
||||
@@ -18,23 +18,8 @@ public class StorageServiceValues {
|
||||
this.store = store;
|
||||
}
|
||||
|
||||
public synchronized MasterKey getOrCreateStorageMasterKey() {
|
||||
byte[] blob = store.getBlob(STORAGE_MASTER_KEY, null);
|
||||
|
||||
if (blob == null) {
|
||||
store.beginWrite()
|
||||
.putBlob(STORAGE_MASTER_KEY, MasterKey.createNew(new SecureRandom()).serialize())
|
||||
.commit();
|
||||
blob = store.getBlob(STORAGE_MASTER_KEY, null);
|
||||
}
|
||||
|
||||
return new MasterKey(blob);
|
||||
}
|
||||
|
||||
public synchronized void rotateStorageMasterKey() {
|
||||
store.beginWrite()
|
||||
.putBlob(STORAGE_MASTER_KEY, MasterKey.createNew(new SecureRandom()).serialize())
|
||||
.commit();
|
||||
public synchronized StorageKey getOrCreateStorageKey() {
|
||||
return SignalStore.kbsValues().getOrCreateMasterKey().deriveStorageServiceKey();
|
||||
}
|
||||
|
||||
public long getLastSyncTime() {
|
||||
|
||||
Reference in New Issue
Block a user