From: AsamK Date: Sun, 2 May 2021 20:03:41 +0000 (+0200) Subject: Handle saving inside SignalAccount X-Git-Tag: v0.8.2~33 X-Git-Url: https://git.nmode.ca/signal-cli/commitdiff_plain/530ef51ba7cd98814c14cfb1c12bb4e1c35596c0 Handle saving inside SignalAccount --- diff --git a/lib/src/main/java/org/asamk/signal/manager/Manager.java b/lib/src/main/java/org/asamk/signal/manager/Manager.java index 3c2d130d..e3939480 100644 --- a/lib/src/main/java/org/asamk/signal/manager/Manager.java +++ b/lib/src/main/java/org/asamk/signal/manager/Manager.java @@ -316,11 +316,9 @@ public class Manager implements Closeable { public void checkAccountState() throws IOException { if (accountManager.getPreKeysCount() < ServiceConfig.PREKEY_MINIMUM_COUNT) { refreshPreKeys(); - account.save(); } if (account.getUuid() == null) { account.setUuid(accountManager.getOwnUuid()); - account.save(); } updateAccountAttributes(); } @@ -411,13 +409,11 @@ public class Manager implements Closeable { accountManager.deleteAccount(); account.setRegistered(false); - account.save(); } public List getLinkedDevices() throws IOException { var devices = accountManager.getDevices(); account.setMultiDevice(devices.size() > 1); - account.save(); return devices; } @@ -425,7 +421,6 @@ public class Manager implements Closeable { accountManager.removeDevice(deviceId); var devices = accountManager.getDevices(); account.setMultiDevice(devices.size() > 1); - account.save(); } public void addDeviceLink(URI linkUri) throws IOException, InvalidKeyException { @@ -444,7 +439,6 @@ public class Manager implements Closeable { Optional.of(account.getProfileKey().serialize()), verificationCode); account.setMultiDevice(true); - account.save(); } public void setRegistrationLockPin(Optional pin) throws IOException, UnauthenticatedResponseException { @@ -458,8 +452,7 @@ public class Manager implements Closeable { pinHelper.setRegistrationLockPin(pin.get(), masterKey); - account.setRegistrationLockPin(pin.get()); - account.setPinMasterKey(masterKey); + account.setRegistrationLockPin(pin.get(), masterKey); } else { // Remove legacy registration lock accountManager.removeRegistrationLockV1(); @@ -467,10 +460,8 @@ public class Manager implements Closeable { // Remove KBS Pin pinHelper.removeRegistrationLockPin(); - account.setRegistrationLockPin(null); - account.setPinMasterKey(null); + account.setRegistrationLockPin(null, null); } - account.save(); } void refreshPreKeys() throws IOException { @@ -1082,7 +1073,6 @@ public class Manager implements Closeable { for (var address : signalServiceAddresses) { handleEndSession(address); } - account.save(); throw e; } } @@ -1097,7 +1087,6 @@ public class Manager implements Closeable { var contact = account.getContactStore().getContact(recipientId); final var builder = contact == null ? Contact.newBuilder() : Contact.newBuilder(contact); account.getContactStore().storeContact(recipientId, builder.withName(name).build()); - account.save(); } public void setContactBlocked(String number, boolean blocked) throws InvalidNumberException { @@ -1108,7 +1097,6 @@ public class Manager implements Closeable { var contact = account.getContactStore().getContact(recipientId); final var builder = contact == null ? Contact.newBuilder() : Contact.newBuilder(contact); account.getContactStore().storeContact(recipientId, builder.withBlocked(blocked).build()); - account.save(); } public void setGroupBlocked(final GroupId groupId, final boolean blocked) throws GroupNotFoundException { @@ -1119,7 +1107,6 @@ public class Manager implements Closeable { group.setBlocked(blocked); account.getGroupStore().updateGroup(group); - account.save(); } private void setExpirationTimer(RecipientId recipientId, int messageExpirationTimer) { @@ -1146,7 +1133,6 @@ public class Manager implements Closeable { var recipientId = canonicalizeAndResolveRecipient(number); setExpirationTimer(recipientId, messageExpirationTimer); sendExpirationTimerUpdate(recipientId); - account.save(); } /** @@ -1179,7 +1165,6 @@ public class Manager implements Closeable { var sticker = new Sticker(StickerPackId.deserialize(Hex.fromStringCondensed(packId)), packKey); account.getStickerStore().updateSticker(sticker); - account.save(); try { return new URI("https", @@ -1376,7 +1361,6 @@ public class Manager implements Closeable { handleEndSession(recipient); } } - account.save(); } } @@ -1387,19 +1371,15 @@ public class Manager implements Closeable { messageBuilder.withTimestamp(timestamp); getOrCreateMessagePipe(); getOrCreateUnidentifiedMessagePipe(); - try { - final var recipientId = account.getSelfRecipientId(); + final var recipientId = account.getSelfRecipientId(); - final var contact = account.getContactStore().getContact(recipientId); - final var expirationTime = contact != null ? contact.getMessageExpirationTime() : 0; - messageBuilder.withExpiration(expirationTime); + final var contact = account.getContactStore().getContact(recipientId); + final var expirationTime = contact != null ? contact.getMessageExpirationTime() : 0; + messageBuilder.withExpiration(expirationTime); - var message = messageBuilder.build(); - final var result = sendSelfMessage(message); - return new Pair<>(timestamp, result); - } finally { - account.save(); - } + var message = messageBuilder.build(); + final var result = sendSelfMessage(message); + return new Pair<>(timestamp, result); } private SendMessageResult sendSelfMessage(SignalServiceDataMessage message) throws IOException { @@ -1715,7 +1695,6 @@ public class Manager implements Closeable { } actions = handleMessage(envelope, content, ignoreAttachments); } - account.save(); handler.handleMessage(envelope, content, null); cachedMessage.delete(); return actions; @@ -1763,7 +1742,6 @@ public class Manager implements Closeable { logger.warn("Message action failed.", e); } } - account.save(); queuedActions.clear(); queuedActions = null; } @@ -1803,7 +1781,6 @@ public class Manager implements Closeable { queuedActions.addAll(actions); } } - account.save(); if (isMessageBlocked(envelope, content)) { logger.info("Ignoring a message from blocked user/group: {}", envelope.getTimestamp()); } else if (notAGroupMember) { diff --git a/lib/src/main/java/org/asamk/signal/manager/ProvisioningManager.java b/lib/src/main/java/org/asamk/signal/manager/ProvisioningManager.java index c8869212..37ac4cdb 100644 --- a/lib/src/main/java/org/asamk/signal/manager/ProvisioningManager.java +++ b/lib/src/main/java/org/asamk/signal/manager/ProvisioningManager.java @@ -125,7 +125,6 @@ public class ProvisioningManager { ret.getIdentity(), registrationId, profileKey); - account.save(); Manager m = null; try { @@ -149,8 +148,6 @@ public class ProvisioningManager { throw e; } - account.save(); - final var result = m; account = null; m = null; diff --git a/lib/src/main/java/org/asamk/signal/manager/RegistrationManager.java b/lib/src/main/java/org/asamk/signal/manager/RegistrationManager.java index b3c524c6..72c99729 100644 --- a/lib/src/main/java/org/asamk/signal/manager/RegistrationManager.java +++ b/lib/src/main/java/org/asamk/signal/manager/RegistrationManager.java @@ -29,6 +29,7 @@ import org.whispersystems.signalservice.api.KeyBackupSystemNoDataException; import org.whispersystems.signalservice.api.SignalServiceAccountManager; import org.whispersystems.signalservice.api.groupsv2.ClientZkOperations; import org.whispersystems.signalservice.api.groupsv2.GroupsV2Operations; +import org.whispersystems.signalservice.api.kbs.MasterKey; import org.whispersystems.signalservice.api.push.SignalServiceAddress; import org.whispersystems.signalservice.api.util.SleepTimer; import org.whispersystems.signalservice.api.util.UptimeSleepTimer; @@ -40,7 +41,6 @@ import org.whispersystems.signalservice.internal.util.DynamicCredentialsProvider import java.io.Closeable; import java.io.File; import java.io.IOException; -import java.util.Date; import java.util.Locale; public class RegistrationManager implements Closeable { @@ -103,7 +103,6 @@ public class RegistrationManager implements Closeable { identityKey, registrationId, profileKey); - account.save(); return new RegistrationManager(account, pathConfig, serviceConfiguration, userAgent); } @@ -114,10 +113,6 @@ public class RegistrationManager implements Closeable { } public void register(boolean voiceVerification, String captcha) throws IOException { - if (account.getPassword() == null) { - account.setPassword(KeyUtils.createPassword()); - } - if (voiceVerification) { accountManager.requestVoiceVerificationCode(Locale.getDefault(), Optional.fromNullable(captcha), @@ -125,8 +120,6 @@ public class RegistrationManager implements Closeable { } else { accountManager.requestSmsVerificationCode(false, Optional.fromNullable(captcha), Optional.absent()); } - - account.save(); } public Manager verifyAccount( @@ -134,9 +127,11 @@ public class RegistrationManager implements Closeable { ) throws IOException, KeyBackupSystemNoDataException, KeyBackupServicePinException { verificationCode = verificationCode.replace("-", ""); VerifyAccountResponse response; + MasterKey masterKey; try { response = verifyAccountWithCode(verificationCode, pin, null); - account.setPinMasterKey(null); + + masterKey = null; } catch (LockedException e) { if (pin == null) { throw e; @@ -153,33 +148,21 @@ public class RegistrationManager implements Closeable { } catch (LockedException _e) { throw new AssertionError("KBS Pin appeared to matched but reg lock still failed!"); } - account.setPinMasterKey(registrationLockData.getMasterKey()); + masterKey = registrationLockData.getMasterKey(); } // TODO response.isStorageCapable() //accountManager.setGcmId(Optional.of(GoogleCloudMessaging.getInstance(this).register(REGISTRATION_ID))); - - account.setDeviceId(SignalServiceAddress.DEFAULT_DEVICE_ID); - account.setMultiDevice(false); - account.setRegistered(true); - account.setUuid(UuidUtil.parseOrNull(response.getUuid())); - account.setRegistrationLockPin(pin); - account.getSessionStore().archiveAllSessions(); - final var recipientId = account.getRecipientStore().resolveRecipientTrusted(account.getSelfAddress()); - final var publicKey = account.getIdentityKeyPair().getPublicKey(); - account.getIdentityKeyStore().saveIdentity(recipientId, publicKey, new Date()); - account.getIdentityKeyStore().setIdentityTrustLevel(recipientId, publicKey, TrustLevel.TRUSTED_VERIFIED); + account.finishRegistration(UuidUtil.parseOrNull(response.getUuid()), masterKey, pin); Manager m = null; try { m = new Manager(account, pathConfig, serviceEnvironmentConfig, userAgent); + account = null; m.refreshPreKeys(); - account.save(); - final var result = m; - account = null; m = null; return result; diff --git a/lib/src/main/java/org/asamk/signal/manager/storage/SignalAccount.java b/lib/src/main/java/org/asamk/signal/manager/storage/SignalAccount.java index f2d2d91d..6b05faa6 100644 --- a/lib/src/main/java/org/asamk/signal/manager/storage/SignalAccount.java +++ b/lib/src/main/java/org/asamk/signal/manager/storage/SignalAccount.java @@ -3,6 +3,7 @@ package org.asamk.signal.manager.storage; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; +import org.asamk.signal.manager.TrustLevel; import org.asamk.signal.manager.groups.GroupId; import org.asamk.signal.manager.storage.contacts.ContactsStore; import org.asamk.signal.manager.storage.contacts.LegacyJsonContactsStore; @@ -54,6 +55,7 @@ import java.nio.channels.ClosedChannelException; import java.nio.channels.FileChannel; import java.nio.channels.FileLock; import java.util.Base64; +import java.util.Date; import java.util.HashSet; import java.util.List; import java.util.UUID; @@ -139,6 +141,7 @@ public class SignalAccount implements Closeable { account.registered = false; account.migrateLegacyConfigs(); + account.save(); return account; } @@ -196,15 +199,19 @@ public class SignalAccount implements Closeable { account.recipientStore.resolveRecipientTrusted(account.getSelfAddress()); account.migrateLegacyConfigs(); + account.save(); return account; } - public void migrateLegacyConfigs() { + private void migrateLegacyConfigs() { + if (getPassword() == null) { + setPassword(KeyUtils.createPassword()); + } + if (getProfileKey() == null && isRegistered()) { // Old config file, creating new profile key setProfileKey(KeyUtils.createProfileKey()); - save(); } // Ensure our profile key is stored in profile store getProfileStore().storeProfileKey(getSelfRecipientId(), getProfileKey()); @@ -225,7 +232,7 @@ public class SignalAccount implements Closeable { return new File(dataPath, username + ".d"); } - public static File getMessageCachePath(File dataPath, String username) { + private static File getMessageCachePath(File dataPath, String username) { return new File(getUserPath(dataPath, username), "msg-cache"); } @@ -324,6 +331,7 @@ public class SignalAccount implements Closeable { } } + var migratedLegacyConfig = false; final var legacySignalProtocolStore = rootNode.hasNonNull("axolotlStore") ? jsonProcessor.convertValue(Utils.getNotNullNode(rootNode, "axolotlStore"), LegacyJsonSignalProtocolStore.class) @@ -331,11 +339,12 @@ public class SignalAccount implements Closeable { if (legacySignalProtocolStore != null && legacySignalProtocolStore.getLegacyIdentityKeyStore() != null) { identityKeyPair = legacySignalProtocolStore.getLegacyIdentityKeyStore().getIdentityKeyPair(); registrationId = legacySignalProtocolStore.getLegacyIdentityKeyStore().getLocalRegistrationId(); + migratedLegacyConfig = true; } initStores(dataPath, identityKeyPair, registrationId); - loadLegacyStores(rootNode, legacySignalProtocolStore); + migratedLegacyConfig = loadLegacyStores(rootNode, legacySignalProtocolStore) || migratedLegacyConfig; if (rootNode.hasNonNull("groupStore")) { groupStoreStorage = jsonProcessor.convertValue(rootNode.get("groupStore"), GroupStore.Storage.class); @@ -356,12 +365,17 @@ public class SignalAccount implements Closeable { stickerStore = new StickerStore(this::saveStickerStore); } - loadLegacyThreadStore(rootNode); + migratedLegacyConfig = loadLegacyThreadStore(rootNode) || migratedLegacyConfig; + + if (migratedLegacyConfig) { + save(); + } } - private void loadLegacyStores( + private boolean loadLegacyStores( final JsonNode rootNode, final LegacyJsonSignalProtocolStore legacySignalProtocolStore ) { + var migrated = false; var legacyRecipientStoreNode = rootNode.get("recipientStore"); if (legacyRecipientStoreNode != null) { logger.debug("Migrating legacy recipient store."); @@ -370,6 +384,7 @@ public class SignalAccount implements Closeable { recipientStore.resolveRecipientsTrusted(legacyRecipientStore.getAddresses()); } recipientStore.resolveRecipientTrusted(getSelfAddress()); + migrated = true; } if (legacySignalProtocolStore != null && legacySignalProtocolStore.getLegacyPreKeyStore() != null) { @@ -381,6 +396,7 @@ public class SignalAccount implements Closeable { logger.warn("Failed to migrate pre key, ignoring", e); } } + migrated = true; } if (legacySignalProtocolStore != null && legacySignalProtocolStore.getLegacySignedPreKeyStore() != null) { @@ -392,6 +408,7 @@ public class SignalAccount implements Closeable { logger.warn("Failed to migrate signed pre key, ignoring", e); } } + migrated = true; } if (legacySignalProtocolStore != null && legacySignalProtocolStore.getLegacySessionStore() != null) { @@ -404,6 +421,7 @@ public class SignalAccount implements Closeable { logger.warn("Failed to migrate session, ignoring", e); } } + migrated = true; } if (legacySignalProtocolStore != null && legacySignalProtocolStore.getLegacyIdentityKeyStore() != null) { @@ -415,6 +433,7 @@ public class SignalAccount implements Closeable { identity.getIdentityKey(), identity.getTrustLevel()); } + migrated = true; } if (rootNode.hasNonNull("contactStore")) { @@ -442,6 +461,7 @@ public class SignalAccount implements Closeable { } } } + migrated = true; } if (rootNode.hasNonNull("profileStore")) { @@ -479,9 +499,11 @@ public class SignalAccount implements Closeable { } } } + + return migrated; } - private void loadLegacyThreadStore(final JsonNode rootNode) { + private boolean loadLegacyThreadStore(final JsonNode rootNode) { var threadStoreNode = rootNode.get("threadStore"); if (threadStoreNode != null && !threadStoreNode.isNull()) { var threadStore = jsonProcessor.convertValue(threadStoreNode, LegacyJsonThreadStore.class); @@ -511,7 +533,10 @@ public class SignalAccount implements Closeable { logger.warn("Failed to read legacy thread info: {}", e.getMessage()); } } + return true; } + + return false; } private void saveStickerStore(StickerStore.Storage storage) { @@ -524,7 +549,7 @@ public class SignalAccount implements Closeable { save(); } - public void save() { + private void save() { synchronized (fileChannel) { var rootNode = jsonProcessor.createObjectNode(); rootNode.put("username", username) @@ -645,6 +670,7 @@ public class SignalAccount implements Closeable { public void setUuid(final UUID uuid) { this.uuid = uuid; + save(); } public SignalServiceAddress getSelfAddress() { @@ -659,10 +685,6 @@ public class SignalAccount implements Closeable { return deviceId; } - public void setDeviceId(final int deviceId) { - this.deviceId = deviceId; - } - public boolean isMasterDevice() { return deviceId == SignalServiceAddress.DEFAULT_DEVICE_ID; } @@ -679,26 +701,25 @@ public class SignalAccount implements Closeable { return password; } - public void setPassword(final String password) { + private void setPassword(final String password) { this.password = password; + save(); } public String getRegistrationLockPin() { return registrationLockPin; } - public void setRegistrationLockPin(final String registrationLockPin) { + public void setRegistrationLockPin(final String registrationLockPin, final MasterKey pinMasterKey) { this.registrationLockPin = registrationLockPin; + this.pinMasterKey = pinMasterKey; + save(); } public MasterKey getPinMasterKey() { return pinMasterKey; } - public void setPinMasterKey(final MasterKey pinMasterKey) { - this.pinMasterKey = pinMasterKey; - } - public StorageKey getStorageKey() { if (pinMasterKey != null) { return pinMasterKey.deriveStorageServiceKey(); @@ -707,7 +728,11 @@ public class SignalAccount implements Closeable { } public void setStorageKey(final StorageKey storageKey) { + if (storageKey.equals(this.storageKey)) { + return; + } this.storageKey = storageKey; + save(); } public ProfileKey getProfileKey() { @@ -715,7 +740,11 @@ public class SignalAccount implements Closeable { } public void setProfileKey(final ProfileKey profileKey) { + if (profileKey.equals(this.profileKey)) { + return; + } this.profileKey = profileKey; + save(); } public byte[] getSelfUnidentifiedAccessKey() { @@ -736,6 +765,7 @@ public class SignalAccount implements Closeable { public void setRegistered(final boolean registered) { this.registered = registered; + save(); } public boolean isMultiDevice() { @@ -743,7 +773,11 @@ public class SignalAccount implements Closeable { } public void setMultiDevice(final boolean multiDevice) { + if (isMultiDevice == multiDevice) { + return; + } isMultiDevice = multiDevice; + save(); } public boolean isUnrestrictedUnidentifiedAccess() { @@ -756,11 +790,24 @@ public class SignalAccount implements Closeable { return true; } + public void finishRegistration(final UUID uuid, final MasterKey masterKey, final String pin) { + this.pinMasterKey = masterKey; + this.deviceId = SignalServiceAddress.DEFAULT_DEVICE_ID; + this.isMultiDevice = false; + this.registered = true; + this.uuid = uuid; + this.registrationLockPin = pin; + save(); + + getSessionStore().archiveAllSessions(); + final var recipientId = getRecipientStore().resolveRecipientTrusted(getSelfAddress()); + final var publicKey = getIdentityKeyPair().getPublicKey(); + getIdentityKeyStore().saveIdentity(recipientId, publicKey, new Date()); + getIdentityKeyStore().setIdentityTrustLevel(recipientId, publicKey, TrustLevel.TRUSTED_VERIFIED); + } + @Override public void close() throws IOException { - if (fileChannel.isOpen()) { - save(); - } synchronized (fileChannel) { try { lock.close();