parent
							
								
									299671480f
								
							
						
					
					
						commit
						2e01a05e71
					
				@ -42,6 +42,7 @@ import org.asamk.signal.manager.helper.IncomingMessageHandler;
 | 
				
			|||||||
import org.asamk.signal.manager.helper.PinHelper;
 | 
					import org.asamk.signal.manager.helper.PinHelper;
 | 
				
			||||||
import org.asamk.signal.manager.helper.ProfileHelper;
 | 
					import org.asamk.signal.manager.helper.ProfileHelper;
 | 
				
			||||||
import org.asamk.signal.manager.helper.SendHelper;
 | 
					import org.asamk.signal.manager.helper.SendHelper;
 | 
				
			||||||
 | 
					import org.asamk.signal.manager.helper.StorageHelper;
 | 
				
			||||||
import org.asamk.signal.manager.helper.SyncHelper;
 | 
					import org.asamk.signal.manager.helper.SyncHelper;
 | 
				
			||||||
import org.asamk.signal.manager.helper.UnidentifiedAccessHelper;
 | 
					import org.asamk.signal.manager.helper.UnidentifiedAccessHelper;
 | 
				
			||||||
import org.asamk.signal.manager.jobs.Context;
 | 
					import org.asamk.signal.manager.jobs.Context;
 | 
				
			||||||
@ -133,6 +134,7 @@ public class Manager implements Closeable {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    private final ProfileHelper profileHelper;
 | 
					    private final ProfileHelper profileHelper;
 | 
				
			||||||
    private final PinHelper pinHelper;
 | 
					    private final PinHelper pinHelper;
 | 
				
			||||||
 | 
					    private final StorageHelper storageHelper;
 | 
				
			||||||
    private final SendHelper sendHelper;
 | 
					    private final SendHelper sendHelper;
 | 
				
			||||||
    private final SyncHelper syncHelper;
 | 
					    private final SyncHelper syncHelper;
 | 
				
			||||||
    private final AttachmentHelper attachmentHelper;
 | 
					    private final AttachmentHelper attachmentHelper;
 | 
				
			||||||
@ -209,6 +211,7 @@ public class Manager implements Closeable {
 | 
				
			|||||||
                avatarStore,
 | 
					                avatarStore,
 | 
				
			||||||
                this::resolveSignalServiceAddress,
 | 
					                this::resolveSignalServiceAddress,
 | 
				
			||||||
                account.getRecipientStore());
 | 
					                account.getRecipientStore());
 | 
				
			||||||
 | 
					        this.storageHelper = new StorageHelper(account, dependencies, groupHelper);
 | 
				
			||||||
        this.contactHelper = new ContactHelper(account);
 | 
					        this.contactHelper = new ContactHelper(account);
 | 
				
			||||||
        this.syncHelper = new SyncHelper(account,
 | 
					        this.syncHelper = new SyncHelper(account,
 | 
				
			||||||
                attachmentHelper,
 | 
					                attachmentHelper,
 | 
				
			||||||
@ -223,7 +226,8 @@ public class Manager implements Closeable {
 | 
				
			|||||||
                sendHelper,
 | 
					                sendHelper,
 | 
				
			||||||
                groupHelper,
 | 
					                groupHelper,
 | 
				
			||||||
                syncHelper,
 | 
					                syncHelper,
 | 
				
			||||||
                profileHelper);
 | 
					                profileHelper,
 | 
				
			||||||
 | 
					                storageHelper);
 | 
				
			||||||
        var jobExecutor = new JobExecutor(context);
 | 
					        var jobExecutor = new JobExecutor(context);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        this.incomingMessageHandler = new IncomingMessageHandler(account,
 | 
					        this.incomingMessageHandler = new IncomingMessageHandler(account,
 | 
				
			||||||
@ -747,6 +751,13 @@ public class Manager implements Closeable {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    public void requestAllSyncData() throws IOException {
 | 
					    public void requestAllSyncData() throws IOException {
 | 
				
			||||||
        syncHelper.requestAllSyncData();
 | 
					        syncHelper.requestAllSyncData();
 | 
				
			||||||
 | 
					        retrieveRemoteStorage();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    void retrieveRemoteStorage() throws IOException {
 | 
				
			||||||
 | 
					        if (account.getStorageKey() != null) {
 | 
				
			||||||
 | 
					            storageHelper.readDataFromStorage();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private byte[] getSenderCertificate() {
 | 
					    private byte[] getSenderCertificate() {
 | 
				
			||||||
 | 
				
			|||||||
@ -103,6 +103,7 @@ public class ProvisioningManager {
 | 
				
			|||||||
                ? null
 | 
					                ? null
 | 
				
			||||||
                : DeviceNameUtil.encryptDeviceName(deviceName, ret.getIdentity().getPrivateKey());
 | 
					                : DeviceNameUtil.encryptDeviceName(deviceName, ret.getIdentity().getPrivateKey());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        logger.debug("Finishing new device registration");
 | 
				
			||||||
        var deviceId = accountManager.finishNewDeviceRegistration(ret.getProvisioningCode(),
 | 
					        var deviceId = accountManager.finishNewDeviceRegistration(ret.getProvisioningCode(),
 | 
				
			||||||
                false,
 | 
					                false,
 | 
				
			||||||
                true,
 | 
					                true,
 | 
				
			||||||
@ -129,6 +130,7 @@ public class ProvisioningManager {
 | 
				
			|||||||
            try {
 | 
					            try {
 | 
				
			||||||
                m = new Manager(account, pathConfig, serviceEnvironmentConfig, userAgent);
 | 
					                m = new Manager(account, pathConfig, serviceEnvironmentConfig, userAgent);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                logger.debug("Refreshing pre keys");
 | 
				
			||||||
                try {
 | 
					                try {
 | 
				
			||||||
                    m.refreshPreKeys();
 | 
					                    m.refreshPreKeys();
 | 
				
			||||||
                } catch (Exception e) {
 | 
					                } catch (Exception e) {
 | 
				
			||||||
@ -136,6 +138,7 @@ public class ProvisioningManager {
 | 
				
			|||||||
                    throw e;
 | 
					                    throw e;
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                logger.debug("Requesting sync data");
 | 
				
			||||||
                try {
 | 
					                try {
 | 
				
			||||||
                    m.requestAllSyncData();
 | 
					                    m.requestAllSyncData();
 | 
				
			||||||
                } catch (Exception e) {
 | 
					                } catch (Exception e) {
 | 
				
			||||||
 | 
				
			|||||||
@ -174,7 +174,6 @@ public class RegistrationManager implements Closeable {
 | 
				
			|||||||
            masterKey = registrationLockData.getMasterKey();
 | 
					            masterKey = registrationLockData.getMasterKey();
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // TODO response.isStorageCapable()
 | 
					 | 
				
			||||||
        //accountManager.setGcmId(Optional.of(GoogleCloudMessaging.getInstance(this).register(REGISTRATION_ID)));
 | 
					        //accountManager.setGcmId(Optional.of(GoogleCloudMessaging.getInstance(this).register(REGISTRATION_ID)));
 | 
				
			||||||
        account.finishRegistration(UuidUtil.parseOrNull(response.getUuid()), masterKey, pin);
 | 
					        account.finishRegistration(UuidUtil.parseOrNull(response.getUuid()), masterKey, pin);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -186,6 +185,9 @@ public class RegistrationManager implements Closeable {
 | 
				
			|||||||
            m.refreshPreKeys();
 | 
					            m.refreshPreKeys();
 | 
				
			||||||
            // Set an initial empty profile so user can be added to groups
 | 
					            // Set an initial empty profile so user can be added to groups
 | 
				
			||||||
            m.setProfile(null, null, null, null, null);
 | 
					            m.setProfile(null, null, null, null, null);
 | 
				
			||||||
 | 
					            if (response.isStorageCapable()) {
 | 
				
			||||||
 | 
					                m.retrieveRemoteStorage();
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            final var result = m;
 | 
					            final var result = m;
 | 
				
			||||||
            m = null;
 | 
					            m = null;
 | 
				
			||||||
 | 
				
			|||||||
@ -1,6 +1,7 @@
 | 
				
			|||||||
package org.asamk.signal.manager;
 | 
					package org.asamk.signal.manager;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import org.whispersystems.signalservice.api.messages.multidevice.VerifiedMessage;
 | 
					import org.whispersystems.signalservice.api.messages.multidevice.VerifiedMessage;
 | 
				
			||||||
 | 
					import org.whispersystems.signalservice.internal.storage.protos.ContactRecord;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
public enum TrustLevel {
 | 
					public enum TrustLevel {
 | 
				
			||||||
    UNTRUSTED,
 | 
					    UNTRUSTED,
 | 
				
			||||||
@ -16,6 +17,20 @@ public enum TrustLevel {
 | 
				
			|||||||
        return TrustLevel.cachedValues[i];
 | 
					        return TrustLevel.cachedValues[i];
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public static TrustLevel fromIdentityState(ContactRecord.IdentityState identityState) {
 | 
				
			||||||
 | 
					        switch (identityState) {
 | 
				
			||||||
 | 
					            case DEFAULT:
 | 
				
			||||||
 | 
					                return TRUSTED_UNVERIFIED;
 | 
				
			||||||
 | 
					            case UNVERIFIED:
 | 
				
			||||||
 | 
					                return UNTRUSTED;
 | 
				
			||||||
 | 
					            case VERIFIED:
 | 
				
			||||||
 | 
					                return TRUSTED_VERIFIED;
 | 
				
			||||||
 | 
					            case UNRECOGNIZED:
 | 
				
			||||||
 | 
					                return null;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        throw new RuntimeException("Unknown identity state: " + identityState);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public static TrustLevel fromVerifiedState(VerifiedMessage.VerifiedState verifiedState) {
 | 
					    public static TrustLevel fromVerifiedState(VerifiedMessage.VerifiedState verifiedState) {
 | 
				
			||||||
        switch (verifiedState) {
 | 
					        switch (verifiedState) {
 | 
				
			||||||
            case DEFAULT:
 | 
					            case DEFAULT:
 | 
				
			||||||
 | 
				
			|||||||
@ -0,0 +1,26 @@
 | 
				
			|||||||
 | 
					package org.asamk.signal.manager.actions;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import org.asamk.signal.manager.jobs.Context;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public class RetrieveStorageDataAction implements HandleAction {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private static final RetrieveStorageDataAction INSTANCE = new RetrieveStorageDataAction();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private RetrieveStorageDataAction() {
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public static RetrieveStorageDataAction create() {
 | 
				
			||||||
 | 
					        return INSTANCE;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
 | 
					    public void execute(Context context) throws Throwable {
 | 
				
			||||||
 | 
					        if (context.getAccount().getStorageKey() != null) {
 | 
				
			||||||
 | 
					            context.getStorageHelper().readDataFromStorage();
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            if (!context.getAccount().isMasterDevice()) {
 | 
				
			||||||
 | 
					                context.getSyncHelper().requestAllSyncData();
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -0,0 +1,20 @@
 | 
				
			|||||||
 | 
					package org.asamk.signal.manager.actions;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import org.asamk.signal.manager.jobs.Context;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public class SendSyncKeysAction implements HandleAction {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private static final SendSyncKeysAction INSTANCE = new SendSyncKeysAction();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private SendSyncKeysAction() {
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public static SendSyncKeysAction create() {
 | 
				
			||||||
 | 
					        return INSTANCE;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
 | 
					    public void execute(Context context) throws Throwable {
 | 
				
			||||||
 | 
					        context.getSyncHelper().sendKeysMessage();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -8,12 +8,14 @@ import org.asamk.signal.manager.UntrustedIdentityException;
 | 
				
			|||||||
import org.asamk.signal.manager.actions.HandleAction;
 | 
					import org.asamk.signal.manager.actions.HandleAction;
 | 
				
			||||||
import org.asamk.signal.manager.actions.RenewSessionAction;
 | 
					import org.asamk.signal.manager.actions.RenewSessionAction;
 | 
				
			||||||
import org.asamk.signal.manager.actions.RetrieveProfileAction;
 | 
					import org.asamk.signal.manager.actions.RetrieveProfileAction;
 | 
				
			||||||
 | 
					import org.asamk.signal.manager.actions.RetrieveStorageDataAction;
 | 
				
			||||||
import org.asamk.signal.manager.actions.SendGroupInfoAction;
 | 
					import org.asamk.signal.manager.actions.SendGroupInfoAction;
 | 
				
			||||||
import org.asamk.signal.manager.actions.SendGroupInfoRequestAction;
 | 
					import org.asamk.signal.manager.actions.SendGroupInfoRequestAction;
 | 
				
			||||||
import org.asamk.signal.manager.actions.SendReceiptAction;
 | 
					import org.asamk.signal.manager.actions.SendReceiptAction;
 | 
				
			||||||
import org.asamk.signal.manager.actions.SendSyncBlockedListAction;
 | 
					import org.asamk.signal.manager.actions.SendSyncBlockedListAction;
 | 
				
			||||||
import org.asamk.signal.manager.actions.SendSyncContactsAction;
 | 
					import org.asamk.signal.manager.actions.SendSyncContactsAction;
 | 
				
			||||||
import org.asamk.signal.manager.actions.SendSyncGroupsAction;
 | 
					import org.asamk.signal.manager.actions.SendSyncGroupsAction;
 | 
				
			||||||
 | 
					import org.asamk.signal.manager.actions.SendSyncKeysAction;
 | 
				
			||||||
import org.asamk.signal.manager.groups.GroupId;
 | 
					import org.asamk.signal.manager.groups.GroupId;
 | 
				
			||||||
import org.asamk.signal.manager.groups.GroupNotFoundException;
 | 
					import org.asamk.signal.manager.groups.GroupNotFoundException;
 | 
				
			||||||
import org.asamk.signal.manager.groups.GroupUtils;
 | 
					import org.asamk.signal.manager.groups.GroupUtils;
 | 
				
			||||||
@ -237,7 +239,10 @@ public final class IncomingMessageHandler {
 | 
				
			|||||||
            if (rm.isBlockedListRequest()) {
 | 
					            if (rm.isBlockedListRequest()) {
 | 
				
			||||||
                actions.add(SendSyncBlockedListAction.create());
 | 
					                actions.add(SendSyncBlockedListAction.create());
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            // TODO Handle rm.isConfigurationRequest(); rm.isKeysRequest();
 | 
					            if (rm.isKeysRequest()) {
 | 
				
			||||||
 | 
					                actions.add(SendSyncKeysAction.create());
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            // TODO Handle rm.isConfigurationRequest();
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        if (syncMessage.getGroups().isPresent()) {
 | 
					        if (syncMessage.getGroups().isPresent()) {
 | 
				
			||||||
            logger.warn("Received a group v1 sync message, that can't be handled anymore, ignoring.");
 | 
					            logger.warn("Received a group v1 sync message, that can't be handled anymore, ignoring.");
 | 
				
			||||||
@ -307,7 +312,7 @@ public final class IncomingMessageHandler {
 | 
				
			|||||||
                case LOCAL_PROFILE:
 | 
					                case LOCAL_PROFILE:
 | 
				
			||||||
                    actions.add(new RetrieveProfileAction(account.getSelfRecipientId()));
 | 
					                    actions.add(new RetrieveProfileAction(account.getSelfRecipientId()));
 | 
				
			||||||
                case STORAGE_MANIFEST:
 | 
					                case STORAGE_MANIFEST:
 | 
				
			||||||
                    // TODO
 | 
					                    actions.add(RetrieveStorageDataAction.create());
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        if (syncMessage.getKeys().isPresent()) {
 | 
					        if (syncMessage.getKeys().isPresent()) {
 | 
				
			||||||
@ -315,6 +320,7 @@ public final class IncomingMessageHandler {
 | 
				
			|||||||
            if (keysMessage.getStorageService().isPresent()) {
 | 
					            if (keysMessage.getStorageService().isPresent()) {
 | 
				
			||||||
                final var storageKey = keysMessage.getStorageService().get();
 | 
					                final var storageKey = keysMessage.getStorageService().get();
 | 
				
			||||||
                account.setStorageKey(storageKey);
 | 
					                account.setStorageKey(storageKey);
 | 
				
			||||||
 | 
					                actions.add(RetrieveStorageDataAction.create());
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        if (syncMessage.getConfiguration().isPresent()) {
 | 
					        if (syncMessage.getConfiguration().isPresent()) {
 | 
				
			||||||
 | 
				
			|||||||
@ -0,0 +1,222 @@
 | 
				
			|||||||
 | 
					package org.asamk.signal.manager.helper;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import org.asamk.signal.manager.SignalDependencies;
 | 
				
			||||||
 | 
					import org.asamk.signal.manager.TrustLevel;
 | 
				
			||||||
 | 
					import org.asamk.signal.manager.groups.GroupId;
 | 
				
			||||||
 | 
					import org.asamk.signal.manager.storage.SignalAccount;
 | 
				
			||||||
 | 
					import org.asamk.signal.manager.storage.recipients.Contact;
 | 
				
			||||||
 | 
					import org.signal.zkgroup.InvalidInputException;
 | 
				
			||||||
 | 
					import org.signal.zkgroup.groups.GroupMasterKey;
 | 
				
			||||||
 | 
					import org.signal.zkgroup.profiles.ProfileKey;
 | 
				
			||||||
 | 
					import org.slf4j.Logger;
 | 
				
			||||||
 | 
					import org.slf4j.LoggerFactory;
 | 
				
			||||||
 | 
					import org.whispersystems.libsignal.IdentityKey;
 | 
				
			||||||
 | 
					import org.whispersystems.libsignal.InvalidKeyException;
 | 
				
			||||||
 | 
					import org.whispersystems.libsignal.util.guava.Optional;
 | 
				
			||||||
 | 
					import org.whispersystems.signalservice.api.storage.SignalAccountRecord;
 | 
				
			||||||
 | 
					import org.whispersystems.signalservice.api.storage.SignalStorageManifest;
 | 
				
			||||||
 | 
					import org.whispersystems.signalservice.api.storage.SignalStorageRecord;
 | 
				
			||||||
 | 
					import org.whispersystems.signalservice.api.storage.StorageId;
 | 
				
			||||||
 | 
					import org.whispersystems.signalservice.internal.storage.protos.ManifestRecord;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import java.io.IOException;
 | 
				
			||||||
 | 
					import java.util.Collections;
 | 
				
			||||||
 | 
					import java.util.Date;
 | 
				
			||||||
 | 
					import java.util.List;
 | 
				
			||||||
 | 
					import java.util.stream.Collectors;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public class StorageHelper {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private final static Logger logger = LoggerFactory.getLogger(StorageHelper.class);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private final SignalAccount account;
 | 
				
			||||||
 | 
					    private final SignalDependencies dependencies;
 | 
				
			||||||
 | 
					    private final GroupHelper groupHelper;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public StorageHelper(
 | 
				
			||||||
 | 
					            final SignalAccount account, final SignalDependencies dependencies, final GroupHelper groupHelper
 | 
				
			||||||
 | 
					    ) {
 | 
				
			||||||
 | 
					        this.account = account;
 | 
				
			||||||
 | 
					        this.dependencies = dependencies;
 | 
				
			||||||
 | 
					        this.groupHelper = groupHelper;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public void readDataFromStorage() throws IOException {
 | 
				
			||||||
 | 
					        logger.debug("Reading data from remote storage");
 | 
				
			||||||
 | 
					        Optional<SignalStorageManifest> manifest;
 | 
				
			||||||
 | 
					        try {
 | 
				
			||||||
 | 
					            manifest = dependencies.getAccountManager()
 | 
				
			||||||
 | 
					                    .getStorageManifestIfDifferentVersion(account.getStorageKey(), account.getStorageManifestVersion());
 | 
				
			||||||
 | 
					        } catch (InvalidKeyException e) {
 | 
				
			||||||
 | 
					            logger.warn("Manifest couldn't be decrypted, ignoring.");
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (!manifest.isPresent()) {
 | 
				
			||||||
 | 
					            logger.debug("Manifest is up to date, does not exist or couldn't be decrypted, ignoring.");
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        account.setStorageManifestVersion(manifest.get().getVersion());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        readAccountRecord(manifest.get());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        final var storageIds = manifest.get()
 | 
				
			||||||
 | 
					                .getStorageIds()
 | 
				
			||||||
 | 
					                .stream()
 | 
				
			||||||
 | 
					                .filter(id -> !id.isUnknown() && id.getType() != ManifestRecord.Identifier.Type.ACCOUNT_VALUE)
 | 
				
			||||||
 | 
					                .collect(Collectors.toList());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        for (final var record : getSignalStorageRecords(storageIds)) {
 | 
				
			||||||
 | 
					            if (record.getType() == ManifestRecord.Identifier.Type.GROUPV2_VALUE) {
 | 
				
			||||||
 | 
					                readGroupV2Record(record);
 | 
				
			||||||
 | 
					            } else if (record.getType() == ManifestRecord.Identifier.Type.GROUPV1_VALUE) {
 | 
				
			||||||
 | 
					                readGroupV1Record(record);
 | 
				
			||||||
 | 
					            } else if (record.getType() == ManifestRecord.Identifier.Type.CONTACT_VALUE) {
 | 
				
			||||||
 | 
					                readContactRecord(record);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private void readContactRecord(final SignalStorageRecord record) {
 | 
				
			||||||
 | 
					        if (record == null || !record.getContact().isPresent()) {
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        final var contactRecord = record.getContact().get();
 | 
				
			||||||
 | 
					        final var address = contactRecord.getAddress();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        final var recipientId = account.getRecipientStore().resolveRecipient(address);
 | 
				
			||||||
 | 
					        final var contact = account.getContactStore().getContact(recipientId);
 | 
				
			||||||
 | 
					        if (contactRecord.getGivenName().isPresent() || contactRecord.getFamilyName().isPresent() || (
 | 
				
			||||||
 | 
					                (contact == null || !contact.isBlocked()) && contactRecord.isBlocked()
 | 
				
			||||||
 | 
					        )) {
 | 
				
			||||||
 | 
					            final var newContact = (contact == null ? Contact.newBuilder() : Contact.newBuilder(contact)).withBlocked(
 | 
				
			||||||
 | 
					                    contactRecord.isBlocked())
 | 
				
			||||||
 | 
					                    .withName((contactRecord.getGivenName().or("") + " " + contactRecord.getFamilyName().or("")).trim())
 | 
				
			||||||
 | 
					                    .build();
 | 
				
			||||||
 | 
					            account.getContactStore().storeContact(recipientId, newContact);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (contactRecord.getProfileKey().isPresent()) {
 | 
				
			||||||
 | 
					            try {
 | 
				
			||||||
 | 
					                final var profileKey = new ProfileKey(contactRecord.getProfileKey().get());
 | 
				
			||||||
 | 
					                account.getProfileStore().storeProfileKey(recipientId, profileKey);
 | 
				
			||||||
 | 
					            } catch (InvalidInputException e) {
 | 
				
			||||||
 | 
					                logger.warn("Received invalid contact profile key from storage");
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if (contactRecord.getIdentityKey().isPresent()) {
 | 
				
			||||||
 | 
					            try {
 | 
				
			||||||
 | 
					                final var identityKey = new IdentityKey(contactRecord.getIdentityKey().get());
 | 
				
			||||||
 | 
					                account.getIdentityKeyStore().saveIdentity(recipientId, identityKey, new Date());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                final var trustLevel = TrustLevel.fromIdentityState(contactRecord.getIdentityState());
 | 
				
			||||||
 | 
					                if (trustLevel != null) {
 | 
				
			||||||
 | 
					                    account.getIdentityKeyStore().setIdentityTrustLevel(recipientId, identityKey, trustLevel);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            } catch (InvalidKeyException e) {
 | 
				
			||||||
 | 
					                logger.warn("Received invalid contact identity key from storage");
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private void readGroupV1Record(final SignalStorageRecord record) {
 | 
				
			||||||
 | 
					        if (record == null || !record.getGroupV1().isPresent()) {
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        final var groupV1Record = record.getGroupV1().get();
 | 
				
			||||||
 | 
					        final var groupIdV1 = GroupId.v1(groupV1Record.getGroupId());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        final var group = account.getGroupStore().getGroup(groupIdV1);
 | 
				
			||||||
 | 
					        if (group == null) {
 | 
				
			||||||
 | 
					            try {
 | 
				
			||||||
 | 
					                groupHelper.sendGroupInfoRequest(groupIdV1, account.getSelfRecipientId());
 | 
				
			||||||
 | 
					            } catch (Throwable e) {
 | 
				
			||||||
 | 
					                logger.warn("Failed to send group request", e);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        final var groupV1 = account.getGroupStore().getOrCreateGroupV1(groupIdV1);
 | 
				
			||||||
 | 
					        if (groupV1.isBlocked() != groupV1Record.isBlocked()) {
 | 
				
			||||||
 | 
					            groupV1.setBlocked(groupV1Record.isBlocked());
 | 
				
			||||||
 | 
					            account.getGroupStore().updateGroup(groupV1);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private void readGroupV2Record(final SignalStorageRecord record) {
 | 
				
			||||||
 | 
					        if (record == null || !record.getGroupV2().isPresent()) {
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        final var groupV2Record = record.getGroupV2().get();
 | 
				
			||||||
 | 
					        if (groupV2Record.isArchived()) {
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        final GroupMasterKey groupMasterKey;
 | 
				
			||||||
 | 
					        try {
 | 
				
			||||||
 | 
					            groupMasterKey = new GroupMasterKey(groupV2Record.getMasterKeyBytes());
 | 
				
			||||||
 | 
					        } catch (InvalidInputException e) {
 | 
				
			||||||
 | 
					            logger.warn("Received invalid group master key from storage");
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        final var group = groupHelper.getOrMigrateGroup(groupMasterKey, 0, null);
 | 
				
			||||||
 | 
					        if (group.isBlocked() != groupV2Record.isBlocked()) {
 | 
				
			||||||
 | 
					            group.setBlocked(groupV2Record.isBlocked());
 | 
				
			||||||
 | 
					            account.getGroupStore().updateGroup(group);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private void readAccountRecord(final SignalStorageManifest manifest) throws IOException {
 | 
				
			||||||
 | 
					        Optional<StorageId> accountId = manifest.getAccountStorageId();
 | 
				
			||||||
 | 
					        if (!accountId.isPresent()) {
 | 
				
			||||||
 | 
					            logger.warn("Manifest has no account record, ignoring.");
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        SignalStorageRecord record = getSignalStorageRecord(accountId.get());
 | 
				
			||||||
 | 
					        if (record == null) {
 | 
				
			||||||
 | 
					            logger.warn("Could not find account record, even though we had an ID, ignoring.");
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        SignalAccountRecord accountRecord = record.getAccount().orNull();
 | 
				
			||||||
 | 
					        if (accountRecord == null) {
 | 
				
			||||||
 | 
					            logger.warn("The storage record didn't actually have an account, ignoring.");
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (accountRecord.getProfileKey().isPresent()) {
 | 
				
			||||||
 | 
					            try {
 | 
				
			||||||
 | 
					                account.setProfileKey(new ProfileKey(accountRecord.getProfileKey().get()));
 | 
				
			||||||
 | 
					            } catch (InvalidInputException e) {
 | 
				
			||||||
 | 
					                logger.warn("Received invalid profile key from storage");
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private SignalStorageRecord getSignalStorageRecord(final StorageId accountId) throws IOException {
 | 
				
			||||||
 | 
					        List<SignalStorageRecord> records;
 | 
				
			||||||
 | 
					        try {
 | 
				
			||||||
 | 
					            records = dependencies.getAccountManager()
 | 
				
			||||||
 | 
					                    .readStorageRecords(account.getStorageKey(), Collections.singletonList(accountId));
 | 
				
			||||||
 | 
					        } catch (InvalidKeyException e) {
 | 
				
			||||||
 | 
					            logger.warn("Failed to read storage records, ignoring.");
 | 
				
			||||||
 | 
					            return null;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return records.size() > 0 ? records.get(0) : null;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private List<SignalStorageRecord> getSignalStorageRecords(final List<StorageId> storageIds) throws IOException {
 | 
				
			||||||
 | 
					        List<SignalStorageRecord> records;
 | 
				
			||||||
 | 
					        try {
 | 
				
			||||||
 | 
					            records = dependencies.getAccountManager().readStorageRecords(account.getStorageKey(), storageIds);
 | 
				
			||||||
 | 
					        } catch (InvalidKeyException e) {
 | 
				
			||||||
 | 
					            logger.warn("Failed to read storage records, ignoring.");
 | 
				
			||||||
 | 
					            return List.of();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return records;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -20,6 +20,7 @@ import org.whispersystems.signalservice.api.messages.multidevice.DeviceContactsI
 | 
				
			|||||||
import org.whispersystems.signalservice.api.messages.multidevice.DeviceContactsOutputStream;
 | 
					import org.whispersystems.signalservice.api.messages.multidevice.DeviceContactsOutputStream;
 | 
				
			||||||
import org.whispersystems.signalservice.api.messages.multidevice.DeviceGroup;
 | 
					import org.whispersystems.signalservice.api.messages.multidevice.DeviceGroup;
 | 
				
			||||||
import org.whispersystems.signalservice.api.messages.multidevice.DeviceGroupsOutputStream;
 | 
					import org.whispersystems.signalservice.api.messages.multidevice.DeviceGroupsOutputStream;
 | 
				
			||||||
 | 
					import org.whispersystems.signalservice.api.messages.multidevice.KeysMessage;
 | 
				
			||||||
import org.whispersystems.signalservice.api.messages.multidevice.RequestMessage;
 | 
					import org.whispersystems.signalservice.api.messages.multidevice.RequestMessage;
 | 
				
			||||||
import org.whispersystems.signalservice.api.messages.multidevice.SignalServiceSyncMessage;
 | 
					import org.whispersystems.signalservice.api.messages.multidevice.SignalServiceSyncMessage;
 | 
				
			||||||
import org.whispersystems.signalservice.api.messages.multidevice.VerifiedMessage;
 | 
					import org.whispersystems.signalservice.api.messages.multidevice.VerifiedMessage;
 | 
				
			||||||
@ -215,6 +216,11 @@ public class SyncHelper {
 | 
				
			|||||||
        sendHelper.sendSyncMessage(SignalServiceSyncMessage.forVerified(verifiedMessage));
 | 
					        sendHelper.sendSyncMessage(SignalServiceSyncMessage.forVerified(verifiedMessage));
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public void sendKeysMessage() throws IOException {
 | 
				
			||||||
 | 
					        var keysMessage = new KeysMessage(Optional.fromNullable(account.getStorageKey()));
 | 
				
			||||||
 | 
					        sendHelper.sendSyncMessage(SignalServiceSyncMessage.forKeys(keysMessage));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public void handleSyncDeviceContacts(final InputStream input) throws IOException {
 | 
					    public void handleSyncDeviceContacts(final InputStream input) throws IOException {
 | 
				
			||||||
        final var s = new DeviceContactsInputStream(input);
 | 
					        final var s = new DeviceContactsInputStream(input);
 | 
				
			||||||
        DeviceContact c;
 | 
					        DeviceContact c;
 | 
				
			||||||
 | 
				
			|||||||
@ -5,6 +5,7 @@ import org.asamk.signal.manager.StickerPackStore;
 | 
				
			|||||||
import org.asamk.signal.manager.helper.GroupHelper;
 | 
					import org.asamk.signal.manager.helper.GroupHelper;
 | 
				
			||||||
import org.asamk.signal.manager.helper.ProfileHelper;
 | 
					import org.asamk.signal.manager.helper.ProfileHelper;
 | 
				
			||||||
import org.asamk.signal.manager.helper.SendHelper;
 | 
					import org.asamk.signal.manager.helper.SendHelper;
 | 
				
			||||||
 | 
					import org.asamk.signal.manager.helper.StorageHelper;
 | 
				
			||||||
import org.asamk.signal.manager.helper.SyncHelper;
 | 
					import org.asamk.signal.manager.helper.SyncHelper;
 | 
				
			||||||
import org.asamk.signal.manager.storage.SignalAccount;
 | 
					import org.asamk.signal.manager.storage.SignalAccount;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -17,6 +18,7 @@ public class Context {
 | 
				
			|||||||
    private final GroupHelper groupHelper;
 | 
					    private final GroupHelper groupHelper;
 | 
				
			||||||
    private final SyncHelper syncHelper;
 | 
					    private final SyncHelper syncHelper;
 | 
				
			||||||
    private final ProfileHelper profileHelper;
 | 
					    private final ProfileHelper profileHelper;
 | 
				
			||||||
 | 
					    private final StorageHelper storageHelper;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public Context(
 | 
					    public Context(
 | 
				
			||||||
            final SignalAccount account,
 | 
					            final SignalAccount account,
 | 
				
			||||||
@ -25,7 +27,8 @@ public class Context {
 | 
				
			|||||||
            final SendHelper sendHelper,
 | 
					            final SendHelper sendHelper,
 | 
				
			||||||
            final GroupHelper groupHelper,
 | 
					            final GroupHelper groupHelper,
 | 
				
			||||||
            final SyncHelper syncHelper,
 | 
					            final SyncHelper syncHelper,
 | 
				
			||||||
            final ProfileHelper profileHelper
 | 
					            final ProfileHelper profileHelper,
 | 
				
			||||||
 | 
					            final StorageHelper storageHelper
 | 
				
			||||||
    ) {
 | 
					    ) {
 | 
				
			||||||
        this.account = account;
 | 
					        this.account = account;
 | 
				
			||||||
        this.dependencies = dependencies;
 | 
					        this.dependencies = dependencies;
 | 
				
			||||||
@ -34,6 +37,7 @@ public class Context {
 | 
				
			|||||||
        this.groupHelper = groupHelper;
 | 
					        this.groupHelper = groupHelper;
 | 
				
			||||||
        this.syncHelper = syncHelper;
 | 
					        this.syncHelper = syncHelper;
 | 
				
			||||||
        this.profileHelper = profileHelper;
 | 
					        this.profileHelper = profileHelper;
 | 
				
			||||||
 | 
					        this.storageHelper = storageHelper;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public SignalAccount getAccount() {
 | 
					    public SignalAccount getAccount() {
 | 
				
			||||||
@ -63,4 +67,8 @@ public class Context {
 | 
				
			|||||||
    public ProfileHelper getProfileHelper() {
 | 
					    public ProfileHelper getProfileHelper() {
 | 
				
			||||||
        return profileHelper;
 | 
					        return profileHelper;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public StorageHelper getStorageHelper() {
 | 
				
			||||||
 | 
					        return storageHelper;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -84,6 +84,7 @@ public class SignalAccount implements Closeable {
 | 
				
			|||||||
    private String registrationLockPin;
 | 
					    private String registrationLockPin;
 | 
				
			||||||
    private MasterKey pinMasterKey;
 | 
					    private MasterKey pinMasterKey;
 | 
				
			||||||
    private StorageKey storageKey;
 | 
					    private StorageKey storageKey;
 | 
				
			||||||
 | 
					    private long storageManifestVersion = -1;
 | 
				
			||||||
    private ProfileKey profileKey;
 | 
					    private ProfileKey profileKey;
 | 
				
			||||||
    private int preKeyIdOffset;
 | 
					    private int preKeyIdOffset;
 | 
				
			||||||
    private int nextSignedPreKeyId;
 | 
					    private int nextSignedPreKeyId;
 | 
				
			||||||
@ -291,6 +292,9 @@ public class SignalAccount implements Closeable {
 | 
				
			|||||||
        this.registered = true;
 | 
					        this.registered = true;
 | 
				
			||||||
        this.isMultiDevice = true;
 | 
					        this.isMultiDevice = true;
 | 
				
			||||||
        this.lastReceiveTimestamp = 0;
 | 
					        this.lastReceiveTimestamp = 0;
 | 
				
			||||||
 | 
					        this.pinMasterKey = null;
 | 
				
			||||||
 | 
					        this.storageManifestVersion = -1;
 | 
				
			||||||
 | 
					        this.storageKey = null;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private void migrateLegacyConfigs() {
 | 
					    private void migrateLegacyConfigs() {
 | 
				
			||||||
@ -432,6 +436,9 @@ public class SignalAccount implements Closeable {
 | 
				
			|||||||
        if (rootNode.hasNonNull("storageKey")) {
 | 
					        if (rootNode.hasNonNull("storageKey")) {
 | 
				
			||||||
            storageKey = new StorageKey(Base64.getDecoder().decode(rootNode.get("storageKey").asText()));
 | 
					            storageKey = new StorageKey(Base64.getDecoder().decode(rootNode.get("storageKey").asText()));
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					        if (rootNode.hasNonNull("storageManifestVersion")) {
 | 
				
			||||||
 | 
					            storageManifestVersion = rootNode.get("storageManifestVersion").asLong();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
        if (rootNode.hasNonNull("preKeyIdOffset")) {
 | 
					        if (rootNode.hasNonNull("preKeyIdOffset")) {
 | 
				
			||||||
            preKeyIdOffset = rootNode.get("preKeyIdOffset").asInt(0);
 | 
					            preKeyIdOffset = rootNode.get("preKeyIdOffset").asInt(0);
 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
@ -693,6 +700,7 @@ public class SignalAccount implements Closeable {
 | 
				
			|||||||
                            pinMasterKey == null ? null : Base64.getEncoder().encodeToString(pinMasterKey.serialize()))
 | 
					                            pinMasterKey == null ? null : Base64.getEncoder().encodeToString(pinMasterKey.serialize()))
 | 
				
			||||||
                    .put("storageKey",
 | 
					                    .put("storageKey",
 | 
				
			||||||
                            storageKey == null ? null : Base64.getEncoder().encodeToString(storageKey.serialize()))
 | 
					                            storageKey == null ? null : Base64.getEncoder().encodeToString(storageKey.serialize()))
 | 
				
			||||||
 | 
					                    .put("storageManifestVersion", storageManifestVersion == -1 ? null : storageManifestVersion)
 | 
				
			||||||
                    .put("preKeyIdOffset", preKeyIdOffset)
 | 
					                    .put("preKeyIdOffset", preKeyIdOffset)
 | 
				
			||||||
                    .put("nextSignedPreKeyId", nextSignedPreKeyId)
 | 
					                    .put("nextSignedPreKeyId", nextSignedPreKeyId)
 | 
				
			||||||
                    .put("profileKey",
 | 
					                    .put("profileKey",
 | 
				
			||||||
@ -877,6 +885,18 @@ public class SignalAccount implements Closeable {
 | 
				
			|||||||
        save();
 | 
					        save();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public long getStorageManifestVersion() {
 | 
				
			||||||
 | 
					        return this.storageManifestVersion;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public void setStorageManifestVersion(final long storageManifestVersion) {
 | 
				
			||||||
 | 
					        if (storageManifestVersion == this.storageManifestVersion) {
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        this.storageManifestVersion = storageManifestVersion;
 | 
				
			||||||
 | 
					        save();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public ProfileKey getProfileKey() {
 | 
					    public ProfileKey getProfileKey() {
 | 
				
			||||||
        return profileKey;
 | 
					        return profileKey;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@ -948,6 +968,8 @@ public class SignalAccount implements Closeable {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    public void finishRegistration(final UUID uuid, final MasterKey masterKey, final String pin) {
 | 
					    public void finishRegistration(final UUID uuid, final MasterKey masterKey, final String pin) {
 | 
				
			||||||
        this.pinMasterKey = masterKey;
 | 
					        this.pinMasterKey = masterKey;
 | 
				
			||||||
 | 
					        this.storageManifestVersion = -1;
 | 
				
			||||||
 | 
					        this.storageKey = null;
 | 
				
			||||||
        this.encryptedDeviceName = null;
 | 
					        this.encryptedDeviceName = null;
 | 
				
			||||||
        this.deviceId = SignalServiceAddress.DEFAULT_DEVICE_ID;
 | 
					        this.deviceId = SignalServiceAddress.DEFAULT_DEVICE_ID;
 | 
				
			||||||
        this.isMultiDevice = false;
 | 
					        this.isMultiDevice = false;
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user