import org.whispersystems.signalservice.api.SignalServiceMessagePipe;
import org.whispersystems.signalservice.api.SignalServiceMessageReceiver;
import org.whispersystems.signalservice.api.SignalServiceMessageSender;
+import org.whispersystems.signalservice.api.SignalSessionLock;
import org.whispersystems.signalservice.api.crypto.SignalServiceCipher;
import org.whispersystems.signalservice.api.crypto.UntrustedIdentityException;
import org.whispersystems.signalservice.api.groupsv2.ClientZkOperations;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
+import java.util.concurrent.locks.ReentrantLock;
import java.util.function.Function;
import java.util.stream.Collectors;
private final PinHelper pinHelper;
private final AvatarStore avatarStore;
private final AttachmentStore attachmentStore;
+ private final SignalSessionLock sessionLock = new SignalSessionLock() {
+ private final ReentrantLock LEGACY_LOCK = new ReentrantLock();
+
+ @Override
+ public Lock acquire() {
+ LEGACY_LOCK.lock();
+ return LEGACY_LOCK::unlock;
+ }
+ };
Manager(
SignalAccount account,
throw new NotRegisteredException();
}
- var account = SignalAccount.load(pathConfig.getDataPath(), username);
+ var account = SignalAccount.load(pathConfig.getDataPath(), username, true);
if (!account.isRegistered()) {
throw new NotRegisteredException();
newProfile.getInternalServiceName(),
newProfile.getAbout() == null ? "" : newProfile.getAbout(),
newProfile.getAboutEmoji() == null ? "" : newProfile.getAboutEmoji(),
+ Optional.absent(),
streamDetails);
}
account.getPassword(),
account.getDeviceId(),
account.getSignalProtocolStore(),
+ sessionLock,
userAgent,
account.isMultiDevice(),
Optional.fromNullable(messagePipe),
Profile getRecipientProfile(
RecipientId recipientId, boolean force
) {
- var profileKey = account.getProfileStore().getProfileKey(recipientId);
- if (profileKey == null) {
- if (force) {
- // retrieve profile to get identity key
- retrieveEncryptedProfile(recipientId);
- }
- return null;
- }
var profile = account.getProfileStore().getProfile(recipientId);
var now = new Date().getTime();
return null;
}
- profile = decryptProfileAndDownloadAvatar(recipientId, profileKey, encryptedProfile);
+ var profileKey = account.getProfileStore().getProfileKey(recipientId);
+ if (profileKey == null) {
+ profile = new Profile(new Date().getTime(),
+ null,
+ null,
+ null,
+ null,
+ ProfileUtils.getUnidentifiedAccessMode(encryptedProfile, null),
+ ProfileUtils.getCapabilities(encryptedProfile));
+ } else {
+ profile = decryptProfileAndDownloadAvatar(recipientId, profileKey, encryptedProfile);
+ }
account.getProfileStore().storeProfile(recipientId, profile);
return profile;
public Pair<GroupId, List<SendMessageResult>> updateGroup(
GroupId groupId, String name, List<String> members, File avatarFile
) throws IOException, GroupNotFoundException, AttachmentInvalidException, InvalidNumberException, NotAGroupMemberException {
- return sendUpdateGroupMessage(groupId,
- name,
- members == null ? null : getSignalServiceAddresses(members),
- avatarFile);
+ final var membersRecipientIds = members == null ? null : getSignalServiceAddresses(members);
+ if (membersRecipientIds != null) {
+ membersRecipientIds.remove(account.getSelfRecipientId());
+ }
+ return sendUpdateGroupMessage(groupId, name, membersRecipientIds, avatarFile);
}
private Pair<GroupId, List<SendMessageResult>> sendUpdateGroupMessage(
}
}
- SendMessageResult renewSession(RecipientId recipientId) throws IOException {
+ void renewSession(RecipientId recipientId) throws IOException {
account.getSessionStore().archiveSessions(recipientId);
- return sendNullMessage(recipientId);
+ if (!recipientId.equals(getSelfRecipientId())) {
+ sendNullMessage(recipientId);
+ }
}
public String getContactName(String number) throws InvalidNumberException {
}
private byte[] getSenderCertificate() {
- // TODO support UUID capable sender certificates
- // byte[] certificate = accountManager.getSenderCertificateForPhoneNumberPrivacy();
byte[] certificate;
try {
- certificate = accountManager.getSenderCertificate();
+ if (account.isPhoneNumberShared()) {
+ certificate = accountManager.getSenderCertificate();
+ } else {
+ certificate = accountManager.getSenderCertificateForPhoneNumberPrivacy();
+ }
} catch (IOException e) {
logger.warn("Failed to get sender certificate, ignoring: {}", e.getMessage());
return null;
}
}
- private SignalServiceContent decryptMessage(SignalServiceEnvelope envelope) throws InvalidMetadataMessageException, ProtocolInvalidMessageException, ProtocolDuplicateMessageException, ProtocolLegacyMessageException, ProtocolInvalidKeyIdException, InvalidMetadataVersionException, ProtocolInvalidVersionException, ProtocolNoSessionException, ProtocolInvalidKeyException, SelfSendException, UnsupportedDataMessageException, org.whispersystems.libsignal.UntrustedIdentityException {
+ private SignalServiceContent decryptMessage(SignalServiceEnvelope envelope) throws InvalidMetadataMessageException, ProtocolInvalidMessageException, ProtocolDuplicateMessageException, ProtocolLegacyMessageException, ProtocolInvalidKeyIdException, InvalidMetadataVersionException, ProtocolInvalidVersionException, ProtocolNoSessionException, ProtocolInvalidKeyException, SelfSendException, UnsupportedDataMessageException, ProtocolUntrustedIdentityException {
var cipher = new SignalServiceCipher(account.getSelfAddress(),
account.getSignalProtocolStore(),
+ sessionLock,
certificateValidator);
- try {
- return cipher.decrypt(envelope);
- } catch (ProtocolUntrustedIdentityException e) {
- if (e.getCause() instanceof org.whispersystems.libsignal.UntrustedIdentityException) {
- throw (org.whispersystems.libsignal.UntrustedIdentityException) e.getCause();
- }
- throw new AssertionError(e);
- }
+ return cipher.decrypt(envelope);
}
private void handleEndSession(RecipientId recipientId) {
if (!envelope.isReceipt()) {
try {
content = decryptMessage(envelope);
- } catch (org.whispersystems.libsignal.UntrustedIdentityException e) {
+ } catch (ProtocolUntrustedIdentityException e) {
if (!envelope.hasSource()) {
- final var identifier = ((org.whispersystems.libsignal.UntrustedIdentityException) e).getName();
+ final var identifier = e.getSender();
final var recipientId = resolveRecipient(identifier);
try {
account.getMessageCache().replaceSender(cachedMessage, recipientId);
if (envelope.hasSource()) {
// Store uuid if we don't have it already
+ // address/uuid in envelope is sent by server
resolveRecipientTrusted(envelope.getSourceAddress());
}
final var notAGroupMember = isNotAGroupMember(envelope, content);
} catch (Exception e) {
exception = e;
}
+ if (!envelope.hasSource() && content != null) {
+ // Store uuid if we don't have it already
+ // address/uuid is validated by unidentified sender certificate
+ resolveRecipientTrusted(content.getSender());
+ }
var actions = handleMessage(envelope, content, ignoreAttachments);
if (exception instanceof ProtocolInvalidMessageException) {
final var sender = resolveRecipient(((ProtocolInvalidMessageException) exception).getSender());
handler.handleMessage(envelope, content, exception);
}
if (cachedMessage[0] != null) {
- if (exception instanceof org.whispersystems.libsignal.UntrustedIdentityException) {
- final var identifier = ((org.whispersystems.libsignal.UntrustedIdentityException) exception).getName();
+ if (exception instanceof ProtocolUntrustedIdentityException) {
+ final var identifier = ((ProtocolUntrustedIdentityException) exception).getSender();
final var recipientId = resolveRecipient(identifier);
queuedActions.add(new RetrieveProfileAction(recipientId));
if (!envelope.hasSource()) {