X-Git-Url: https://git.nmode.ca/signal-cli/blobdiff_plain/5c754b6f5d5bd3273b3c0722cf3eabbcd02c20b9..1c5de83370e1108271bf72836c887fdea9cb46db:/src/main/java/org/asamk/signal/manager/Manager.java diff --git a/src/main/java/org/asamk/signal/manager/Manager.java b/src/main/java/org/asamk/signal/manager/Manager.java index c679449d..e964d218 100644 --- a/src/main/java/org/asamk/signal/manager/Manager.java +++ b/src/main/java/org/asamk/signal/manager/Manager.java @@ -18,20 +18,31 @@ package org.asamk.signal.manager; import com.fasterxml.jackson.databind.ObjectMapper; +import org.asamk.signal.manager.groups.GroupId; +import org.asamk.signal.manager.groups.GroupIdV1; +import org.asamk.signal.manager.groups.GroupIdV2; +import org.asamk.signal.manager.groups.GroupInviteLinkUrl; +import org.asamk.signal.manager.groups.GroupNotFoundException; +import org.asamk.signal.manager.groups.GroupUtils; +import org.asamk.signal.manager.groups.NotAGroupMemberException; import org.asamk.signal.manager.helper.GroupHelper; +import org.asamk.signal.manager.helper.PinHelper; import org.asamk.signal.manager.helper.ProfileHelper; import org.asamk.signal.manager.helper.UnidentifiedAccessHelper; -import org.asamk.signal.storage.SignalAccount; -import org.asamk.signal.storage.contacts.ContactInfo; -import org.asamk.signal.storage.groups.GroupInfo; -import org.asamk.signal.storage.groups.GroupInfoV1; -import org.asamk.signal.storage.groups.GroupInfoV2; -import org.asamk.signal.storage.profiles.SignalProfile; -import org.asamk.signal.storage.profiles.SignalProfileEntry; -import org.asamk.signal.storage.protocol.JsonIdentityKeyStore; -import org.asamk.signal.storage.stickers.Sticker; -import org.asamk.signal.util.IOUtils; -import org.asamk.signal.util.Util; +import org.asamk.signal.manager.storage.SignalAccount; +import org.asamk.signal.manager.storage.contacts.ContactInfo; +import org.asamk.signal.manager.storage.groups.GroupInfo; +import org.asamk.signal.manager.storage.groups.GroupInfoV1; +import org.asamk.signal.manager.storage.groups.GroupInfoV2; +import org.asamk.signal.manager.storage.profiles.SignalProfile; +import org.asamk.signal.manager.storage.profiles.SignalProfileEntry; +import org.asamk.signal.manager.storage.protocol.IdentityInfo; +import org.asamk.signal.manager.storage.stickers.Sticker; +import org.asamk.signal.manager.util.AttachmentUtils; +import org.asamk.signal.manager.util.IOUtils; +import org.asamk.signal.manager.util.KeyUtils; +import org.asamk.signal.manager.util.MessageCacheUtils; +import org.asamk.signal.manager.util.Utils; import org.signal.libsignal.metadata.InvalidMetadataMessageException; import org.signal.libsignal.metadata.InvalidMetadataVersionException; import org.signal.libsignal.metadata.ProtocolDuplicateMessageException; @@ -43,6 +54,7 @@ import org.signal.libsignal.metadata.ProtocolLegacyMessageException; import org.signal.libsignal.metadata.ProtocolNoSessionException; import org.signal.libsignal.metadata.ProtocolUntrustedIdentityException; import org.signal.libsignal.metadata.SelfSendException; +import org.signal.libsignal.metadata.certificate.CertificateValidator; import org.signal.storageservice.protos.groups.GroupChange; import org.signal.storageservice.protos.groups.local.DecryptedGroup; import org.signal.storageservice.protos.groups.local.DecryptedGroupJoinInfo; @@ -71,6 +83,10 @@ import org.whispersystems.libsignal.util.KeyHelper; import org.whispersystems.libsignal.util.Medium; import org.whispersystems.libsignal.util.Pair; import org.whispersystems.libsignal.util.guava.Optional; +import org.whispersystems.signalservice.api.KbsPinData; +import org.whispersystems.signalservice.api.KeyBackupService; +import org.whispersystems.signalservice.api.KeyBackupServicePinException; +import org.whispersystems.signalservice.api.KeyBackupSystemNoDataException; import org.whispersystems.signalservice.api.SignalServiceAccountManager; import org.whispersystems.signalservice.api.SignalServiceMessagePipe; import org.whispersystems.signalservice.api.SignalServiceMessageReceiver; @@ -85,6 +101,7 @@ import org.whispersystems.signalservice.api.groupsv2.GroupLinkNotActiveException import org.whispersystems.signalservice.api.groupsv2.GroupsV2Api; import org.whispersystems.signalservice.api.groupsv2.GroupsV2AuthorizationString; import org.whispersystems.signalservice.api.groupsv2.GroupsV2Operations; +import org.whispersystems.signalservice.api.kbs.MasterKey; import org.whispersystems.signalservice.api.messages.SendMessageResult; import org.whispersystems.signalservice.api.messages.SignalServiceAttachment; import org.whispersystems.signalservice.api.messages.SignalServiceAttachmentPointer; @@ -118,6 +135,7 @@ import org.whispersystems.signalservice.api.push.ContactTokenDetails; import org.whispersystems.signalservice.api.push.SignalServiceAddress; import org.whispersystems.signalservice.api.push.exceptions.MissingConfigurationException; import org.whispersystems.signalservice.api.util.InvalidNumberException; +import org.whispersystems.signalservice.api.util.PhoneNumberFormatter; import org.whispersystems.signalservice.api.util.SleepTimer; import org.whispersystems.signalservice.api.util.StreamDetails; import org.whispersystems.signalservice.api.util.UptimeSleepTimer; @@ -126,6 +144,7 @@ import org.whispersystems.signalservice.internal.configuration.SignalServiceConf import org.whispersystems.signalservice.internal.contacts.crypto.Quote; import org.whispersystems.signalservice.internal.contacts.crypto.UnauthenticatedQuoteException; import org.whispersystems.signalservice.internal.contacts.crypto.UnauthenticatedResponseException; +import org.whispersystems.signalservice.internal.push.LockedException; import org.whispersystems.signalservice.internal.push.SignalServiceProtos; import org.whispersystems.signalservice.internal.push.UnsupportedDataMessageException; import org.whispersystems.signalservice.internal.push.VerifyAccountResponse; @@ -148,11 +167,11 @@ import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Paths; import java.nio.file.StandardCopyOption; +import java.security.KeyStore; import java.security.SignatureException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; -import java.util.Collections; import java.util.Date; import java.util.HashMap; import java.util.HashSet; @@ -178,9 +197,12 @@ public class Manager implements Closeable { final static Logger logger = LoggerFactory.getLogger(Manager.class); private final SleepTimer timer = new UptimeSleepTimer(); + private final CertificateValidator certificateValidator = new CertificateValidator(ServiceConfig.getUnidentifiedSenderTrustRoot()); private final SignalServiceConfiguration serviceConfiguration; private final String userAgent; + + // TODO make configurable private final boolean discoverableByPhoneNumber = true; private final boolean unrestrictedUnidentifiedAccess = false; @@ -197,8 +219,9 @@ public class Manager implements Closeable { private final UnidentifiedAccessHelper unidentifiedAccessHelper; private final ProfileHelper profileHelper; private final GroupHelper groupHelper; + private PinHelper pinHelper; - public Manager( + Manager( SignalAccount account, PathConfig pathConfig, SignalServiceConfiguration serviceConfiguration, @@ -210,8 +233,7 @@ public class Manager implements Closeable { this.userAgent = userAgent; this.groupsV2Operations = capabilities.isGv2() ? new GroupsV2Operations(ClientZkOperations.create( serviceConfiguration)) : null; - this.accountManager = createSignalServiceAccountManager(); - this.groupsV2Api = accountManager.getGroupsV2Api(); + createSignalServiceAccountManager(); this.account.setResolver(this::resolveSignalServiceAddress); @@ -239,8 +261,8 @@ public class Manager implements Closeable { return account.getSelfAddress(); } - private SignalServiceAccountManager createSignalServiceAccountManager() { - return new SignalServiceAccountManager(serviceConfiguration, + private void createSignalServiceAccountManager() { + this.accountManager = new SignalServiceAccountManager(serviceConfiguration, new DynamicCredentialsProvider(account.getUuid(), account.getUsername(), account.getPassword(), @@ -249,6 +271,18 @@ public class Manager implements Closeable { userAgent, groupsV2Operations, timer); + this.groupsV2Api = accountManager.getGroupsV2Api(); + this.pinHelper = new PinHelper(createKeyBackupService()); + } + + private KeyBackupService createKeyBackupService() { + KeyStore keyStore = ServiceConfig.getIasKeyStore(); + + return accountManager.getKeyBackupService(keyStore, + ServiceConfig.KEY_BACKUP_ENCLAVE_NAME, + ServiceConfig.KEY_BACKUP_SERVICE_ID, + ServiceConfig.KEY_BACKUP_MRENCLAVE, + 10); } private IdentityKeyPair getIdentityKeyPair() { @@ -259,22 +293,22 @@ public class Manager implements Closeable { return account.getDeviceId(); } - private String getMessageCachePath() { - return pathConfig.getDataPath() + "/" + account.getUsername() + ".d/msg-cache"; + private File getMessageCachePath() { + return SignalAccount.getMessageCachePath(pathConfig.getDataPath(), account.getUsername()); } - private String getMessageCachePath(String sender) { + private File getMessageCachePath(String sender) { if (sender == null || sender.isEmpty()) { return getMessageCachePath(); } - return getMessageCachePath() + "/" + sender.replace("/", "_"); + return new File(getMessageCachePath(), sender.replace("/", "_")); } private File getMessageCacheFile(String sender, long now, long timestamp) throws IOException { - String cachePath = getMessageCachePath(sender); + File cachePath = getMessageCachePath(sender); IOUtils.createPrivateDirectories(cachePath); - return new File(cachePath + "/" + now + "_" + timestamp); + return new File(cachePath, now + "_" + timestamp); } public static Manager init( @@ -349,13 +383,34 @@ public class Manager implements Closeable { return account.isRegistered(); } + /** + * This is used for checking a set of phone numbers for registration on Signal + * + * @param numbers The set of phone number in question + * @return A map of numbers to booleans. True if registered, false otherwise. Should never be null + * @throws IOException if its unable to check if the users are registered + */ + public Map areUsersRegistered(Set numbers) throws IOException { + // Note "contactDetails" has no optionals. It only gives us info on users who are registered + List contactDetails = this.accountManager.getContacts(numbers); + + // Make the initial map with all numbers set to false for now + Map usersRegistered = numbers.stream().collect(Collectors.toMap(x -> x, x -> false)); + + // Override the contacts we did obtain + for (ContactTokenDetails contactDetail : contactDetails) { + usersRegistered.put(contactDetail.getNumber(), true); + } + + return usersRegistered; + } + public void register(boolean voiceVerification, String captcha) throws IOException { account.setPassword(KeyUtils.createPassword()); // Resetting UUID, because registering doesn't work otherwise account.setUuid(null); - accountManager = createSignalServiceAccountManager(); - this.groupsV2Api = accountManager.getGroupsV2Api(); + createSignalServiceAccountManager(); if (voiceVerification) { accountManager.requestVoiceVerificationCode(Locale.getDefault(), @@ -373,8 +428,9 @@ public class Manager implements Closeable { accountManager.setAccountAttributes(account.getSignalingKey(), account.getSignalProtocolStore().getLocalRegistrationId(), true, - account.getRegistrationLockPin(), - account.getRegistrationLock(), + // set legacy pin only if no KBS master key is set + account.getPinMasterKey() == null ? account.getRegistrationLockPin() : null, + account.getPinMasterKey() == null ? null : account.getPinMasterKey().deriveRegistrationLock(), unidentifiedAccessHelper.getSelfUnidentifiedAccessKey(), unrestrictedUnidentifiedAccess, capabilities, @@ -412,7 +468,7 @@ public class Manager implements Closeable { } public void addDeviceLink(URI linkUri) throws IOException, InvalidKeyException { - Utils.DeviceLinkInfo info = Utils.parseDeviceLinkUri(linkUri); + DeviceLinkInfo info = DeviceLinkInfo.parseDeviceLinkUri(linkUri); addDevice(info.deviceIdentifier, info.deviceKey); } @@ -467,26 +523,39 @@ public class Manager implements Closeable { } } - public void verifyAccount(String verificationCode, String pin) throws IOException { + public void verifyAccount( + String verificationCode, + String pin + ) throws IOException, KeyBackupSystemNoDataException, KeyBackupServicePinException { verificationCode = verificationCode.replace("-", ""); account.setSignalingKey(KeyUtils.createSignalingKey()); - // TODO make unrestricted unidentified access configurable - VerifyAccountResponse response = accountManager.verifyAccountWithCode(verificationCode, - account.getSignalingKey(), - account.getSignalProtocolStore().getLocalRegistrationId(), - true, - pin, - null, - unidentifiedAccessHelper.getSelfUnidentifiedAccessKey(), - unrestrictedUnidentifiedAccess, - capabilities, - discoverableByPhoneNumber); + VerifyAccountResponse response; + try { + response = verifyAccountWithCode(verificationCode, pin, null); + } catch (LockedException e) { + if (pin == null) { + throw e; + } + + KbsPinData registrationLockData = pinHelper.getRegistrationLockData(pin, e); + if (registrationLockData == null) { + throw e; + } + + String registrationLock = registrationLockData.getMasterKey().deriveRegistrationLock(); + try { + response = verifyAccountWithCode(verificationCode, null, registrationLock); + } catch (LockedException _e) { + throw new AssertionError("KBS Pin appeared to matched but reg lock still failed!"); + } + account.setPinMasterKey(registrationLockData.getMasterKey()); + } - UUID uuid = UuidUtil.parseOrNull(response.getUuid()); // TODO response.isStorageCapable() //accountManager.setGcmId(Optional.of(GoogleCloudMessaging.getInstance(this).register(REGISTRATION_ID))); + account.setRegistered(true); - account.setUuid(uuid); + account.setUuid(UuidUtil.parseOrNull(response.getUuid())); account.setRegistrationLockPin(pin); account.getSignalProtocolStore() .saveIdentity(account.getSelfAddress(), @@ -497,13 +566,40 @@ public class Manager implements Closeable { account.save(); } - public void setRegistrationLockPin(Optional pin) throws IOException { + private VerifyAccountResponse verifyAccountWithCode( + final String verificationCode, final String legacyPin, final String registrationLock + ) throws IOException { + return accountManager.verifyAccountWithCode(verificationCode, + account.getSignalingKey(), + account.getSignalProtocolStore().getLocalRegistrationId(), + true, + legacyPin, + registrationLock, + unidentifiedAccessHelper.getSelfUnidentifiedAccessKey(), + unrestrictedUnidentifiedAccess, + capabilities, + discoverableByPhoneNumber); + } + + public void setRegistrationLockPin(Optional pin) throws IOException, UnauthenticatedResponseException { if (pin.isPresent()) { + final MasterKey masterKey = account.getPinMasterKey() != null + ? account.getPinMasterKey() + : KeyUtils.createMasterKey(); + + pinHelper.setRegistrationLockPin(pin.get(), masterKey); + account.setRegistrationLockPin(pin.get()); - throw new RuntimeException("Not implemented anymore, will be replaced with KBS"); + account.setPinMasterKey(masterKey); } else { - account.setRegistrationLockPin(null); + // Remove legacy registration lock accountManager.removeRegistrationLockV1(); + + // Remove KBS Pin + pinHelper.removeRegistrationLockPin(); + + account.setRegistrationLockPin(null); + account.setPinMasterKey(null); } account.save(); } @@ -689,7 +785,7 @@ public class Manager implements Closeable { return Optional.absent(); } - return Optional.of(Utils.createAttachment(file)); + return Optional.of(AttachmentUtils.createAttachment(file)); } private Optional createContactAvatarAttachment(String number) throws IOException { @@ -698,7 +794,7 @@ public class Manager implements Closeable { return Optional.absent(); } - return Optional.of(Utils.createAttachment(file)); + return Optional.of(AttachmentUtils.createAttachment(file)); } private GroupInfo getGroupForSending(GroupId groupId) throws GroupNotFoundException, NotAGroupMemberException { @@ -744,7 +840,7 @@ public class Manager implements Closeable { final SignalServiceDataMessage.Builder messageBuilder = SignalServiceDataMessage.newBuilder() .withBody(messageText); if (attachments != null) { - messageBuilder.withAttachments(Utils.getSignalServiceAttachments(attachments)); + messageBuilder.withAttachments(AttachmentUtils.getSignalServiceAttachments(attachments)); } return sendGroupMessage(messageBuilder, groupId); @@ -797,7 +893,7 @@ public class Manager implements Closeable { GroupInfoV2 gv2 = groupHelper.createGroupV2(name, members, avatarFile); if (gv2 == null) { GroupInfoV1 gv1 = new GroupInfoV1(GroupIdV1.createRandom()); - gv1.addMembers(Collections.singleton(account.getSelfAddress())); + gv1.addMembers(List.of(account.getSelfAddress())); updateGroupV1(gv1, name, members, avatarFile); messageBuilder = getGroupUpdateMessageBuilder(gv1); g = gv1; @@ -921,7 +1017,7 @@ public class Manager implements Closeable { newE164Members.remove(contact.getNumber()); } throw new IOException("Failed to add members " - + Util.join(", ", newE164Members) + + String.join(", ", newE164Members) + " to group: Not registered on Signal"); } @@ -952,7 +1048,7 @@ public class Manager implements Closeable { SignalServiceDataMessage.Builder messageBuilder = getGroupUpdateMessageBuilder(g); // Send group message only to the recipient who requested it - return sendMessage(messageBuilder, Collections.singleton(recipient)); + return sendMessage(messageBuilder, List.of(recipient)); } private SignalServiceDataMessage.Builder getGroupUpdateMessageBuilder(GroupInfoV1 g) throws AttachmentInvalidException { @@ -964,7 +1060,7 @@ public class Manager implements Closeable { File aFile = getGroupAvatarFile(g.getGroupId()); if (aFile.exists()) { try { - group.withAvatar(Utils.createAttachment(aFile)); + group.withAvatar(AttachmentUtils.createAttachment(aFile)); } catch (IOException e) { throw new AttachmentInvalidException(aFile.toString(), e); } @@ -994,14 +1090,14 @@ public class Manager implements Closeable { .asGroupMessage(group.build()); // Send group info request message to the recipient who sent us a message with this groupId - return sendMessage(messageBuilder, Collections.singleton(recipient)); + return sendMessage(messageBuilder, List.of(recipient)); } void sendReceipt( SignalServiceAddress remoteAddress, long messageId ) throws IOException, UntrustedIdentityException { SignalServiceReceiptMessage receiptMessage = new SignalServiceReceiptMessage(SignalServiceReceiptMessage.Type.DELIVERY, - Collections.singletonList(messageId), + List.of(messageId), System.currentTimeMillis()); createMessageSender().sendReceipt(remoteAddress, @@ -1015,7 +1111,7 @@ public class Manager implements Closeable { final SignalServiceDataMessage.Builder messageBuilder = SignalServiceDataMessage.newBuilder() .withBody(messageText); if (attachments != null) { - List attachmentStreams = Utils.getSignalServiceAttachments(attachments); + List attachmentStreams = AttachmentUtils.getSignalServiceAttachments(attachments); // Upload attachments here, so we only upload once even for multiple recipients SignalServiceMessageSender messageSender = createMessageSender(); @@ -1128,7 +1224,7 @@ public class Manager implements Closeable { private void sendExpirationTimerUpdate(SignalServiceAddress address) throws IOException { final SignalServiceDataMessage.Builder messageBuilder = SignalServiceDataMessage.newBuilder() .asExpirationUpdate(); - sendMessage(messageBuilder, Collections.singleton(address)); + sendMessage(messageBuilder, List.of(address)); } /** @@ -1161,7 +1257,7 @@ public class Manager implements Closeable { * @param path Path can be a path to a manifest.json file or to a zip file that contains a manifest.json file * @return if successful, returns the URL to install the sticker pack in the signal app */ - public String uploadStickerPack(String path) throws IOException, StickerPackInvalidException { + public String uploadStickerPack(File path) throws IOException, StickerPackInvalidException { SignalServiceStickerManifestUpload manifest = getSignalServiceStickerManifestUpload(path); SignalServiceMessageSender messageSender = createMessageSender(); @@ -1186,12 +1282,11 @@ public class Manager implements Closeable { } private SignalServiceStickerManifestUpload getSignalServiceStickerManifestUpload( - final String path + final File file ) throws IOException, StickerPackInvalidException { ZipFile zip = null; String rootPath = null; - final File file = new File(path); if (file.getName().endsWith(".zip")) { zip = new ZipFile(file); } else if (file.getName().equals("manifest.json")) { @@ -1422,7 +1517,7 @@ public class Manager implements Closeable { .saveIdentity(resolveSignalServiceAddress(e.getIdentifier()), e.getIdentityKey(), TrustLevel.UNTRUSTED); - return new Pair<>(timestamp, Collections.emptyList()); + return new Pair<>(timestamp, List.of()); } } else { // Send to all individually, so sync messages are sent correctly @@ -1465,7 +1560,7 @@ public class Manager implements Closeable { message.getTimestamp(), message, message.getExpiresInSeconds(), - Collections.singletonMap(recipient, unidentifiedAccess.isPresent()), + Map.of(recipient, unidentifiedAccess.isPresent()), false); SignalServiceSyncMessage syncMessage = SignalServiceSyncMessage.forSentTranscript(transcript); @@ -1504,7 +1599,7 @@ public class Manager implements Closeable { private SignalServiceContent decryptMessage(SignalServiceEnvelope envelope) throws InvalidMetadataMessageException, ProtocolInvalidMessageException, ProtocolDuplicateMessageException, ProtocolLegacyMessageException, ProtocolInvalidKeyIdException, InvalidMetadataVersionException, ProtocolInvalidVersionException, ProtocolNoSessionException, ProtocolInvalidKeyException, SelfSendException, UnsupportedDataMessageException, org.whispersystems.libsignal.UntrustedIdentityException { SignalServiceCipher cipher = new SignalServiceCipher(account.getSelfAddress(), account.getSignalProtocolStore(), - Utils.getCertificateValidator()); + certificateValidator); try { return cipher.decrypt(envelope); } catch (ProtocolUntrustedIdentityException e) { @@ -1788,7 +1883,7 @@ public class Manager implements Closeable { private void retryFailedReceivedMessages( ReceiveMessageHandler handler, boolean ignoreAttachments ) { - final File cachePath = new File(getMessageCachePath()); + final File cachePath = getMessageCachePath(); if (!cachePath.exists()) { return; } @@ -1814,7 +1909,7 @@ public class Manager implements Closeable { ) { SignalServiceEnvelope envelope; try { - envelope = Utils.loadEnvelope(fileEntry); + envelope = MessageCacheUtils.loadEnvelope(fileEntry); if (envelope == null) { return; } @@ -1881,7 +1976,7 @@ public class Manager implements Closeable { try { String source = envelope1.getSourceE164().isPresent() ? envelope1.getSourceE164().get() : ""; File cacheFile = getMessageCacheFile(source, now, envelope1.getTimestamp()); - Utils.storeEnvelope(envelope1, cacheFile); + MessageCacheUtils.storeEnvelope(envelope1, cacheFile); } catch (IOException e) { logger.warn("Failed to store encrypted message in disk cache, ignoring: {}", e.getMessage()); } @@ -1954,7 +2049,7 @@ public class Manager implements Closeable { cacheFile = getMessageCacheFile(source, now, envelope.getTimestamp()); Files.delete(cacheFile.toPath()); // Try to delete directory if empty - new File(getMessageCachePath()).delete(); + getMessageCachePath().delete(); } catch (IOException e) { logger.warn("Failed to delete cached message file “{}”, ignoring: {}", cacheFile, e.getMessage()); } @@ -2073,7 +2168,7 @@ public class Manager implements Closeable { syncGroup.removeMember(account.getSelfAddress()); } else { // Add ourself to the member set as it's marked as active - syncGroup.addMembers(Collections.singleton(account.getSelfAddress())); + syncGroup.addMembers(List.of(account.getSelfAddress())); } syncGroup.blocked = g.isBlocked(); if (g.getColor().isPresent()) { @@ -2234,7 +2329,7 @@ public class Manager implements Closeable { return retrieveAttachment(pointer, getContactAvatarFile(number), false); } else { SignalServiceAttachmentStream stream = attachment.asStream(); - return Utils.retrieveAttachment(stream, getContactAvatarFile(number)); + return AttachmentUtils.retrieveAttachment(stream, getContactAvatarFile(number)); } } @@ -2251,7 +2346,7 @@ public class Manager implements Closeable { return retrieveAttachment(pointer, getGroupAvatarFile(groupId), false); } else { SignalServiceAttachmentStream stream = attachment.asStream(); - return Utils.retrieveAttachment(stream, getGroupAvatarFile(groupId)); + return AttachmentUtils.retrieveAttachment(stream, getGroupAvatarFile(groupId)); } } @@ -2416,8 +2511,7 @@ public class Manager implements Closeable { DeviceContactsOutputStream out = new DeviceContactsOutputStream(fos); for (ContactInfo record : account.getContactStore().getContacts()) { VerifiedMessage verifiedMessage = null; - JsonIdentityKeyStore.Identity currentIdentity = account.getSignalProtocolStore() - .getIdentity(record.getAddress()); + IdentityInfo currentIdentity = account.getSignalProtocolStore().getIdentity(record.getAddress()); if (currentIdentity != null) { verifiedMessage = new VerifiedMessage(record.getAddress(), currentIdentity.getIdentityKey(), @@ -2504,18 +2598,18 @@ public class Manager implements Closeable { } public ContactInfo getContact(String number) { - return account.getContactStore().getContact(Util.getSignalServiceAddressFromIdentifier(number)); + return account.getContactStore().getContact(Utils.getSignalServiceAddressFromIdentifier(number)); } public GroupInfo getGroup(GroupId groupId) { return account.getGroupStore().getGroup(groupId); } - public List getIdentities() { + public List getIdentities() { return account.getSignalProtocolStore().getIdentities(); } - public List getIdentities(String number) throws InvalidNumberException { + public List getIdentities(String number) throws InvalidNumberException { return account.getSignalProtocolStore().getIdentities(canonicalizeAndResolveSignalServiceAddress(number)); } @@ -2527,11 +2621,11 @@ public class Manager implements Closeable { */ public boolean trustIdentityVerified(String name, byte[] fingerprint) throws InvalidNumberException { SignalServiceAddress address = canonicalizeAndResolveSignalServiceAddress(name); - List ids = account.getSignalProtocolStore().getIdentities(address); + List ids = account.getSignalProtocolStore().getIdentities(address); if (ids == null) { return false; } - for (JsonIdentityKeyStore.Identity id : ids) { + for (IdentityInfo id : ids) { if (!Arrays.equals(id.getIdentityKey().serialize(), fingerprint)) { continue; } @@ -2557,11 +2651,11 @@ public class Manager implements Closeable { */ public boolean trustIdentityVerifiedSafetyNumber(String name, String safetyNumber) throws InvalidNumberException { SignalServiceAddress address = canonicalizeAndResolveSignalServiceAddress(name); - List ids = account.getSignalProtocolStore().getIdentities(address); + List ids = account.getSignalProtocolStore().getIdentities(address); if (ids == null) { return false; } - for (JsonIdentityKeyStore.Identity id : ids) { + for (IdentityInfo id : ids) { if (!safetyNumber.equals(computeSafetyNumber(address, id.getIdentityKey()))) { continue; } @@ -2586,11 +2680,11 @@ public class Manager implements Closeable { */ public boolean trustIdentityAllKeys(String name) { SignalServiceAddress address = resolveSignalServiceAddress(name); - List ids = account.getSignalProtocolStore().getIdentities(address); + List ids = account.getSignalProtocolStore().getIdentities(address); if (ids == null) { return false; } - for (JsonIdentityKeyStore.Identity id : ids) { + for (IdentityInfo id : ids) { if (id.getTrustLevel() == TrustLevel.UNTRUSTED) { account.getSignalProtocolStore() .setIdentityTrustLevel(address, id.getIdentityKey(), TrustLevel.TRUSTED_UNVERIFIED); @@ -2608,7 +2702,8 @@ public class Manager implements Closeable { public String computeSafetyNumber( SignalServiceAddress theirAddress, IdentityKey theirIdentityKey ) { - return Utils.computeSafetyNumber(account.getSelfAddress(), + return Utils.computeSafetyNumber(ServiceConfig.capabilities.isUuid(), + account.getSelfAddress(), getIdentityKeyPair().getPublicKey(), theirAddress, theirIdentityKey); @@ -2621,12 +2716,12 @@ public class Manager implements Closeable { public SignalServiceAddress canonicalizeAndResolveSignalServiceAddress(String identifier) throws InvalidNumberException { String canonicalizedNumber = UuidUtil.isUuid(identifier) ? identifier - : Util.canonicalizeNumber(identifier, account.getUsername()); + : PhoneNumberFormatter.formatNumber(identifier, account.getUsername()); return resolveSignalServiceAddress(canonicalizedNumber); } public SignalServiceAddress resolveSignalServiceAddress(String identifier) { - SignalServiceAddress address = Util.getSignalServiceAddressFromIdentifier(identifier); + SignalServiceAddress address = Utils.getSignalServiceAddressFromIdentifier(identifier); return resolveSignalServiceAddress(address); }