Merge remote-tracking branch 'refs/remotes/origin/master'

This commit is contained in:
Adimarantis 2021-08-30 19:27:45 +02:00
commit 54583161e2
12 changed files with 228 additions and 172 deletions

View file

@ -58,7 +58,6 @@ import org.asamk.signal.manager.storage.stickers.StickerPackId;
import org.asamk.signal.manager.util.KeyUtils; import org.asamk.signal.manager.util.KeyUtils;
import org.asamk.signal.manager.util.StickerUtils; import org.asamk.signal.manager.util.StickerUtils;
import org.asamk.signal.manager.util.Utils; import org.asamk.signal.manager.util.Utils;
import org.signal.libsignal.metadata.ProtocolUntrustedIdentityException;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.whispersystems.libsignal.IdentityKey; import org.whispersystems.libsignal.IdentityKey;
@ -165,8 +164,7 @@ public class Manager implements Closeable {
return LEGACY_LOCK::unlock; return LEGACY_LOCK::unlock;
} }
}; };
this.dependencies = new SignalDependencies(account.getSelfAddress(), this.dependencies = new SignalDependencies(serviceEnvironmentConfig,
serviceEnvironmentConfig,
userAgent, userAgent,
credentialsProvider, credentialsProvider,
account.getSignalProtocolStore(), account.getSignalProtocolStore(),
@ -187,8 +185,6 @@ public class Manager implements Closeable {
avatarStore, avatarStore,
account.getProfileStore()::getProfileKey, account.getProfileStore()::getProfileKey,
unidentifiedAccessHelper::getAccessFor, unidentifiedAccessHelper::getAccessFor,
dependencies::getProfileService,
dependencies::getMessageReceiver,
this::resolveSignalServiceAddress); this::resolveSignalServiceAddress);
final GroupV2Helper groupV2Helper = new GroupV2Helper(profileHelper::getRecipientProfileKeyCredential, final GroupV2Helper groupV2Helper = new GroupV2Helper(profileHelper::getRecipientProfileKeyCredential,
this::getRecipientProfile, this::getRecipientProfile,
@ -221,8 +217,7 @@ public class Manager implements Closeable {
this::resolveSignalServiceAddress); this::resolveSignalServiceAddress);
this.context = new Context(account, this.context = new Context(account,
dependencies.getAccountManager(), dependencies,
dependencies.getMessageReceiver(),
stickerPackStore, stickerPackStore,
sendHelper, sendHelper,
groupHelper, groupHelper,
@ -386,6 +381,13 @@ public class Manager implements Closeable {
} }
public void deleteAccount() throws IOException { public void deleteAccount() throws IOException {
try {
pinHelper.removeRegistrationLockPin();
} catch (UnauthenticatedResponseException e) {
logger.warn("Failed to remove registration lock pin");
}
account.setRegistrationLockPin(null, null);
dependencies.getAccountManager().deleteAccount(); dependencies.getAccountManager().deleteAccount();
account.setRegistered(false); account.setRegistered(false);
@ -818,37 +820,33 @@ public class Manager implements Closeable {
) { ) {
var envelope = cachedMessage.loadEnvelope(); var envelope = cachedMessage.loadEnvelope();
if (envelope == null) { if (envelope == null) {
cachedMessage.delete();
return null; return null;
} }
SignalServiceContent content = null;
List<HandleAction> actions = null; final var result = incomingMessageHandler.handleRetryEnvelope(envelope, ignoreAttachments, handler);
if (!envelope.isReceipt()) { final var actions = result.first();
try { final var exception = result.second();
content = dependencies.getCipher().decrypt(envelope);
} catch (ProtocolUntrustedIdentityException e) { if (exception instanceof UntrustedIdentityException) {
if (System.currentTimeMillis() - envelope.getServerDeliveredTimestamp() > 1000L * 60 * 60 * 24 * 30) { if (System.currentTimeMillis() - envelope.getServerDeliveredTimestamp() > 1000L * 60 * 60 * 24 * 30) {
// Envelope is more than a month old, cleaning up. // Envelope is more than a month old, cleaning up.
cachedMessage.delete();
return null;
}
if (!envelope.hasSourceUuid()) {
final var identifier = e.getSender();
final var recipientId = account.getRecipientStore().resolveRecipient(identifier);
try {
account.getMessageCache().replaceSender(cachedMessage, recipientId);
} catch (IOException ioException) {
logger.warn("Failed to move cached message to recipient folder: {}", ioException.getMessage());
}
}
return null;
} catch (Exception er) {
// All other errors are not recoverable, so delete the cached message
cachedMessage.delete(); cachedMessage.delete();
return null; return null;
} }
actions = incomingMessageHandler.handleMessage(envelope, content, ignoreAttachments); if (!envelope.hasSourceUuid()) {
final var identifier = ((UntrustedIdentityException) exception).getSender();
final var recipientId = account.getRecipientStore().resolveRecipient(identifier);
try {
account.getMessageCache().replaceSender(cachedMessage, recipientId);
} catch (IOException ioException) {
logger.warn("Failed to move cached message to recipient folder: {}", ioException.getMessage());
}
}
return null;
} }
handler.handleMessage(envelope, content, null);
// If successful and for all other errors that are not recoverable, delete the cached message
cachedMessage.delete(); cachedMessage.delete();
return actions; return actions;
} }
@ -1147,10 +1145,6 @@ public class Manager implements Closeable {
} }
public SignalServiceAddress resolveSignalServiceAddress(SignalServiceAddress address) { public SignalServiceAddress resolveSignalServiceAddress(SignalServiceAddress address) {
if (address.matches(account.getSelfAddress())) {
return account.getSelfAddress();
}
return resolveSignalServiceAddress(resolveRecipient(address)); return resolveSignalServiceAddress(resolveRecipient(address));
} }

View file

@ -3,7 +3,6 @@ package org.asamk.signal.manager;
import org.asamk.signal.manager.config.ServiceConfig; import org.asamk.signal.manager.config.ServiceConfig;
import org.asamk.signal.manager.config.ServiceEnvironmentConfig; import org.asamk.signal.manager.config.ServiceEnvironmentConfig;
import org.signal.libsignal.metadata.certificate.CertificateValidator; import org.signal.libsignal.metadata.certificate.CertificateValidator;
import org.signal.zkgroup.profiles.ClientZkProfileOperations;
import org.whispersystems.libsignal.util.guava.Optional; import org.whispersystems.libsignal.util.guava.Optional;
import org.whispersystems.signalservice.api.KeyBackupService; import org.whispersystems.signalservice.api.KeyBackupService;
import org.whispersystems.signalservice.api.SignalServiceAccountManager; import org.whispersystems.signalservice.api.SignalServiceAccountManager;
@ -18,32 +17,41 @@ import org.whispersystems.signalservice.api.groupsv2.GroupsV2Api;
import org.whispersystems.signalservice.api.groupsv2.GroupsV2Operations; import org.whispersystems.signalservice.api.groupsv2.GroupsV2Operations;
import org.whispersystems.signalservice.api.push.SignalServiceAddress; import org.whispersystems.signalservice.api.push.SignalServiceAddress;
import org.whispersystems.signalservice.api.services.ProfileService; import org.whispersystems.signalservice.api.services.ProfileService;
import org.whispersystems.signalservice.api.util.SleepTimer;
import org.whispersystems.signalservice.api.util.UptimeSleepTimer; import org.whispersystems.signalservice.api.util.UptimeSleepTimer;
import org.whispersystems.signalservice.api.websocket.WebSocketFactory; import org.whispersystems.signalservice.api.websocket.WebSocketFactory;
import org.whispersystems.signalservice.internal.util.DynamicCredentialsProvider; import org.whispersystems.signalservice.internal.util.DynamicCredentialsProvider;
import org.whispersystems.signalservice.internal.websocket.WebSocketConnection; import org.whispersystems.signalservice.internal.websocket.WebSocketConnection;
import java.util.concurrent.ExecutorService; import java.util.concurrent.ExecutorService;
import java.util.function.Supplier;
import static org.asamk.signal.manager.config.ServiceConfig.capabilities; import static org.asamk.signal.manager.config.ServiceConfig.capabilities;
public class SignalDependencies { public class SignalDependencies {
private final SignalServiceAccountManager accountManager; private final Object LOCK = new Object();
private final GroupsV2Api groupsV2Api;
private final GroupsV2Operations groupsV2Operations;
private final SignalWebSocket signalWebSocket; private final ServiceEnvironmentConfig serviceEnvironmentConfig;
private final SignalServiceMessageReceiver messageReceiver; private final String userAgent;
private final SignalServiceMessageSender messageSender; private final DynamicCredentialsProvider credentialsProvider;
private final SignalServiceDataStore dataStore;
private final ExecutorService executor;
private final SignalSessionLock sessionLock;
private final KeyBackupService keyBackupService; private SignalServiceAccountManager accountManager;
private final ProfileService profileService; private GroupsV2Api groupsV2Api;
private final SignalServiceCipher cipher; private GroupsV2Operations groupsV2Operations;
private ClientZkOperations clientZkOperations;
private SignalWebSocket signalWebSocket;
private SignalServiceMessageReceiver messageReceiver;
private SignalServiceMessageSender messageSender;
private KeyBackupService keyBackupService;
private ProfileService profileService;
private SignalServiceCipher cipher;
public SignalDependencies( public SignalDependencies(
final SignalServiceAddress selfAddress,
final ServiceEnvironmentConfig serviceEnvironmentConfig, final ServiceEnvironmentConfig serviceEnvironmentConfig,
final String userAgent, final String userAgent,
final DynamicCredentialsProvider credentialsProvider, final DynamicCredentialsProvider credentialsProvider,
@ -51,100 +59,134 @@ public class SignalDependencies {
final ExecutorService executor, final ExecutorService executor,
final SignalSessionLock sessionLock final SignalSessionLock sessionLock
) { ) {
this.groupsV2Operations = capabilities.isGv2() ? new GroupsV2Operations(ClientZkOperations.create( this.serviceEnvironmentConfig = serviceEnvironmentConfig;
serviceEnvironmentConfig.getSignalServiceConfiguration())) : null; this.userAgent = userAgent;
final SleepTimer timer = new UptimeSleepTimer(); this.credentialsProvider = credentialsProvider;
this.accountManager = new SignalServiceAccountManager(serviceEnvironmentConfig.getSignalServiceConfiguration(), this.dataStore = dataStore;
credentialsProvider, this.executor = executor;
userAgent, this.sessionLock = sessionLock;
groupsV2Operations,
ServiceConfig.AUTOMATIC_NETWORK_RETRY);
this.groupsV2Api = accountManager.getGroupsV2Api();
this.keyBackupService = accountManager.getKeyBackupService(ServiceConfig.getIasKeyStore(),
serviceEnvironmentConfig.getKeyBackupConfig().getEnclaveName(),
serviceEnvironmentConfig.getKeyBackupConfig().getServiceId(),
serviceEnvironmentConfig.getKeyBackupConfig().getMrenclave(),
10);
final ClientZkProfileOperations clientZkProfileOperations = capabilities.isGv2() ? ClientZkOperations.create(
serviceEnvironmentConfig.getSignalServiceConfiguration()).getProfileOperations() : null;
this.messageReceiver = new SignalServiceMessageReceiver(serviceEnvironmentConfig.getSignalServiceConfiguration(),
credentialsProvider,
userAgent,
clientZkProfileOperations,
ServiceConfig.AUTOMATIC_NETWORK_RETRY);
final var healthMonitor = new SignalWebSocketHealthMonitor(timer);
final WebSocketFactory webSocketFactory = new WebSocketFactory() {
@Override
public WebSocketConnection createWebSocket() {
return new WebSocketConnection("normal",
serviceEnvironmentConfig.getSignalServiceConfiguration(),
Optional.of(credentialsProvider),
userAgent,
healthMonitor);
}
@Override
public WebSocketConnection createUnidentifiedWebSocket() {
return new WebSocketConnection("unidentified",
serviceEnvironmentConfig.getSignalServiceConfiguration(),
Optional.absent(),
userAgent,
healthMonitor);
}
};
this.signalWebSocket = new SignalWebSocket(webSocketFactory);
healthMonitor.monitor(signalWebSocket);
this.profileService = new ProfileService(clientZkProfileOperations, messageReceiver, signalWebSocket);
final var certificateValidator = new CertificateValidator(serviceEnvironmentConfig.getUnidentifiedSenderTrustRoot());
this.cipher = new SignalServiceCipher(selfAddress, dataStore, sessionLock, certificateValidator);
this.messageSender = new SignalServiceMessageSender(serviceEnvironmentConfig.getSignalServiceConfiguration(),
credentialsProvider,
dataStore,
sessionLock,
userAgent,
signalWebSocket,
Optional.absent(),
clientZkProfileOperations,
executor,
ServiceConfig.MAX_ENVELOPE_SIZE,
ServiceConfig.AUTOMATIC_NETWORK_RETRY);
} }
public SignalServiceAccountManager getAccountManager() { public SignalServiceAccountManager getAccountManager() {
return accountManager; return getOrCreate(() -> accountManager,
() -> accountManager = new SignalServiceAccountManager(serviceEnvironmentConfig.getSignalServiceConfiguration(),
credentialsProvider,
userAgent,
getGroupsV2Operations(),
ServiceConfig.AUTOMATIC_NETWORK_RETRY));
} }
public GroupsV2Api getGroupsV2Api() { public GroupsV2Api getGroupsV2Api() {
return groupsV2Api; return getOrCreate(() -> groupsV2Api, () -> groupsV2Api = getAccountManager().getGroupsV2Api());
} }
public GroupsV2Operations getGroupsV2Operations() { public GroupsV2Operations getGroupsV2Operations() {
return groupsV2Operations; return getOrCreate(() -> groupsV2Operations,
() -> groupsV2Operations = capabilities.isGv2() ? new GroupsV2Operations(ClientZkOperations.create(
serviceEnvironmentConfig.getSignalServiceConfiguration())) : null);
}
private ClientZkOperations getClientZkOperations() {
return getOrCreate(() -> clientZkOperations,
() -> clientZkOperations = capabilities.isGv2()
? ClientZkOperations.create(serviceEnvironmentConfig.getSignalServiceConfiguration())
: null);
} }
public SignalWebSocket getSignalWebSocket() { public SignalWebSocket getSignalWebSocket() {
return signalWebSocket; return getOrCreate(() -> signalWebSocket, () -> {
final var timer = new UptimeSleepTimer();
final var healthMonitor = new SignalWebSocketHealthMonitor(timer);
final var webSocketFactory = new WebSocketFactory() {
@Override
public WebSocketConnection createWebSocket() {
return new WebSocketConnection("normal",
serviceEnvironmentConfig.getSignalServiceConfiguration(),
Optional.of(credentialsProvider),
userAgent,
healthMonitor);
}
@Override
public WebSocketConnection createUnidentifiedWebSocket() {
return new WebSocketConnection("unidentified",
serviceEnvironmentConfig.getSignalServiceConfiguration(),
Optional.absent(),
userAgent,
healthMonitor);
}
};
signalWebSocket = new SignalWebSocket(webSocketFactory);
healthMonitor.monitor(signalWebSocket);
});
} }
public SignalServiceMessageReceiver getMessageReceiver() { public SignalServiceMessageReceiver getMessageReceiver() {
return messageReceiver; return getOrCreate(() -> messageReceiver,
() -> messageReceiver = new SignalServiceMessageReceiver(serviceEnvironmentConfig.getSignalServiceConfiguration(),
credentialsProvider,
userAgent,
getClientZkOperations().getProfileOperations(),
ServiceConfig.AUTOMATIC_NETWORK_RETRY));
} }
public SignalServiceMessageSender getMessageSender() { public SignalServiceMessageSender getMessageSender() {
return messageSender; return getOrCreate(() -> messageSender,
() -> messageSender = new SignalServiceMessageSender(serviceEnvironmentConfig.getSignalServiceConfiguration(),
credentialsProvider,
dataStore,
sessionLock,
userAgent,
getSignalWebSocket(),
Optional.absent(),
getClientZkOperations().getProfileOperations(),
executor,
ServiceConfig.MAX_ENVELOPE_SIZE,
ServiceConfig.AUTOMATIC_NETWORK_RETRY));
} }
public KeyBackupService getKeyBackupService() { public KeyBackupService getKeyBackupService() {
return keyBackupService; return getOrCreate(() -> keyBackupService,
() -> keyBackupService = getAccountManager().getKeyBackupService(ServiceConfig.getIasKeyStore(),
serviceEnvironmentConfig.getKeyBackupConfig().getEnclaveName(),
serviceEnvironmentConfig.getKeyBackupConfig().getServiceId(),
serviceEnvironmentConfig.getKeyBackupConfig().getMrenclave(),
10));
} }
public ProfileService getProfileService() { public ProfileService getProfileService() {
return profileService; return getOrCreate(() -> profileService,
() -> profileService = new ProfileService(getClientZkOperations().getProfileOperations(),
getMessageReceiver(),
getSignalWebSocket()));
} }
public SignalServiceCipher getCipher() { public SignalServiceCipher getCipher() {
return cipher; return getOrCreate(() -> cipher, () -> {
final var certificateValidator = new CertificateValidator(serviceEnvironmentConfig.getUnidentifiedSenderTrustRoot());
final var address = new SignalServiceAddress(credentialsProvider.getUuid(), credentialsProvider.getE164());
cipher = new SignalServiceCipher(address, dataStore, sessionLock, certificateValidator);
});
}
private <T> T getOrCreate(Supplier<T> supplier, Callable creator) {
var value = supplier.get();
if (value != null) {
return value;
}
synchronized (LOCK) {
value = supplier.get();
if (value != null) {
return value;
}
creator.call();
return supplier.get();
}
}
private interface Callable {
void call();
} }
} }

View file

@ -79,6 +79,28 @@ public final class IncomingMessageHandler {
this.jobExecutor = jobExecutor; this.jobExecutor = jobExecutor;
} }
public Pair<List<HandleAction>, Exception> handleRetryEnvelope(
final SignalServiceEnvelope envelope,
final boolean ignoreAttachments,
final Manager.ReceiveMessageHandler handler
) {
SignalServiceContent content = null;
if (!envelope.isReceipt()) {
try {
content = dependencies.getCipher().decrypt(envelope);
} catch (ProtocolUntrustedIdentityException e) {
final var recipientId = account.getRecipientStore().resolveRecipient(e.getSender());
final var exception = new UntrustedIdentityException(addressResolver.resolveSignalServiceAddress(
recipientId), e.getSenderDevice());
return new Pair<>(List.of(), exception);
} catch (Exception e) {
return new Pair<>(List.of(), e);
}
}
final var actions = checkAndHandleMessage(envelope, content, ignoreAttachments, handler, null);
return new Pair<>(actions, null);
}
public Pair<List<HandleAction>, Exception> handleEnvelope( public Pair<List<HandleAction>, Exception> handleEnvelope(
final SignalServiceEnvelope envelope, final SignalServiceEnvelope envelope,
final boolean ignoreAttachments, final boolean ignoreAttachments,
@ -108,35 +130,48 @@ public final class IncomingMessageHandler {
} catch (Exception e) { } catch (Exception e) {
exception = e; exception = e;
} }
if (!envelope.hasSourceUuid() && content != null) {
// Store uuid if we don't have it already
// address/uuid is validated by unidentified sender certificate
account.getRecipientStore().resolveRecipientTrusted(content.getSender());
}
} }
actions.addAll(checkAndHandleMessage(envelope, content, ignoreAttachments, handler, exception));
return new Pair<>(actions, exception);
}
private List<HandleAction> checkAndHandleMessage(
final SignalServiceEnvelope envelope,
final SignalServiceContent content,
final boolean ignoreAttachments,
final Manager.ReceiveMessageHandler handler,
final Exception exception
) {
if (!envelope.hasSourceUuid() && content != null) {
// Store uuid if we don't have it already
// address/uuid is validated by unidentified sender certificate
account.getRecipientStore().resolveRecipientTrusted(content.getSender());
}
if (isMessageBlocked(envelope, content)) { if (isMessageBlocked(envelope, content)) {
logger.info("Ignoring a message from blocked user/group: {}", envelope.getTimestamp()); logger.info("Ignoring a message from blocked user/group: {}", envelope.getTimestamp());
return List.of();
} else if (isNotAllowedToSendToGroup(envelope, content)) { } else if (isNotAllowedToSendToGroup(envelope, content)) {
logger.info("Ignoring a group message from an unauthorized sender (no member or admin): {} {}", logger.info("Ignoring a group message from an unauthorized sender (no member or admin): {} {}",
(envelope.hasSourceUuid() ? envelope.getSourceAddress() : content.getSender()).getIdentifier(), (envelope.hasSourceUuid() ? envelope.getSourceAddress() : content.getSender()).getIdentifier(),
envelope.getTimestamp()); envelope.getTimestamp());
return List.of();
} else { } else {
actions.addAll(handleMessage(envelope, content, ignoreAttachments)); List<HandleAction> actions;
if (content != null) {
actions = handleMessage(envelope, content, ignoreAttachments);
} else {
actions = List.of();
}
handler.handleMessage(envelope, content, exception); handler.handleMessage(envelope, content, exception);
return actions;
} }
return new Pair<>(actions, exception);
} }
public List<HandleAction> handleMessage( public List<HandleAction> handleMessage(
SignalServiceEnvelope envelope, SignalServiceContent content, boolean ignoreAttachments SignalServiceEnvelope envelope, SignalServiceContent content, boolean ignoreAttachments
) { ) {
var actions = new ArrayList<HandleAction>(); var actions = new ArrayList<HandleAction>();
if (content == null) {
return actions;
}
final RecipientId sender; final RecipientId sender;
if (!envelope.isUnidentifiedSender() && envelope.hasSourceUuid()) { if (!envelope.isUnidentifiedSender() && envelope.hasSourceUuid()) {
sender = recipientResolver.resolveRecipient(envelope.getSourceAddress()); sender = recipientResolver.resolveRecipient(envelope.getSourceAddress());

View file

@ -1,8 +0,0 @@
package org.asamk.signal.manager.helper;
import org.whispersystems.signalservice.api.SignalServiceMessageReceiver;
public interface MessageReceiverProvider {
SignalServiceMessageReceiver getMessageReceiver();
}

View file

@ -45,8 +45,6 @@ public final class ProfileHelper {
private final AvatarStore avatarStore; private final AvatarStore avatarStore;
private final ProfileKeyProvider profileKeyProvider; private final ProfileKeyProvider profileKeyProvider;
private final UnidentifiedAccessProvider unidentifiedAccessProvider; private final UnidentifiedAccessProvider unidentifiedAccessProvider;
private final ProfileServiceProvider profileServiceProvider;
private final MessageReceiverProvider messageReceiverProvider;
private final SignalServiceAddressResolver addressResolver; private final SignalServiceAddressResolver addressResolver;
public ProfileHelper( public ProfileHelper(
@ -55,8 +53,6 @@ public final class ProfileHelper {
final AvatarStore avatarStore, final AvatarStore avatarStore,
final ProfileKeyProvider profileKeyProvider, final ProfileKeyProvider profileKeyProvider,
final UnidentifiedAccessProvider unidentifiedAccessProvider, final UnidentifiedAccessProvider unidentifiedAccessProvider,
final ProfileServiceProvider profileServiceProvider,
final MessageReceiverProvider messageReceiverProvider,
final SignalServiceAddressResolver addressResolver final SignalServiceAddressResolver addressResolver
) { ) {
this.account = account; this.account = account;
@ -64,8 +60,6 @@ public final class ProfileHelper {
this.avatarStore = avatarStore; this.avatarStore = avatarStore;
this.profileKeyProvider = profileKeyProvider; this.profileKeyProvider = profileKeyProvider;
this.unidentifiedAccessProvider = unidentifiedAccessProvider; this.unidentifiedAccessProvider = unidentifiedAccessProvider;
this.profileServiceProvider = profileServiceProvider;
this.messageReceiverProvider = messageReceiverProvider;
this.addressResolver = addressResolver; this.addressResolver = addressResolver;
} }
@ -218,7 +212,7 @@ public final class ProfileHelper {
} }
private SignalServiceProfile retrieveProfileSync(String username) throws IOException { private SignalServiceProfile retrieveProfileSync(String username) throws IOException {
return messageReceiverProvider.getMessageReceiver().retrieveProfileByUsername(username, Optional.absent()); return dependencies.getMessageReceiver().retrieveProfileByUsername(username, Optional.absent());
} }
private ProfileAndCredential retrieveProfileAndCredential( private ProfileAndCredential retrieveProfileAndCredential(
@ -287,7 +281,7 @@ public final class ProfileHelper {
Optional<UnidentifiedAccess> unidentifiedAccess, Optional<UnidentifiedAccess> unidentifiedAccess,
SignalServiceProfile.RequestType requestType SignalServiceProfile.RequestType requestType
) { ) {
var profileService = profileServiceProvider.getProfileService(); var profileService = dependencies.getProfileService();
Single<ServiceResponse<ProfileAndCredential>> responseSingle; Single<ServiceResponse<ProfileAndCredential>> responseSingle;
try { try {

View file

@ -1,8 +0,0 @@
package org.asamk.signal.manager.helper;
import org.whispersystems.signalservice.api.services.ProfileService;
public interface ProfileServiceProvider {
ProfileService getProfileService();
}

View file

@ -222,8 +222,13 @@ public class SyncHelper {
try { try {
c = s.read(); c = s.read();
} catch (IOException e) { } catch (IOException e) {
logger.warn("Sync contacts contained invalid contact, ignoring: {}", e.getMessage()); if (e.getMessage() != null && e.getMessage().contains("Missing contact address!")) {
continue; logger.warn("Sync contacts contained invalid contact, ignoring: {}", e.getMessage());
continue;
} else {
logger.warn("Failed to read sync contacts", e);
break;
}
} }
if (c == null) { if (c == null) {
break; break;

View file

@ -1,19 +1,17 @@
package org.asamk.signal.manager.jobs; package org.asamk.signal.manager.jobs;
import org.asamk.signal.manager.SignalDependencies;
import org.asamk.signal.manager.StickerPackStore; 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.SyncHelper; import org.asamk.signal.manager.helper.SyncHelper;
import org.asamk.signal.manager.storage.SignalAccount; import org.asamk.signal.manager.storage.SignalAccount;
import org.whispersystems.signalservice.api.SignalServiceAccountManager;
import org.whispersystems.signalservice.api.SignalServiceMessageReceiver;
public class Context { public class Context {
private final SignalAccount account; private final SignalAccount account;
private final SignalServiceAccountManager accountManager; private final SignalDependencies dependencies;
private final SignalServiceMessageReceiver messageReceiver;
private final StickerPackStore stickerPackStore; private final StickerPackStore stickerPackStore;
private final SendHelper sendHelper; private final SendHelper sendHelper;
private final GroupHelper groupHelper; private final GroupHelper groupHelper;
@ -22,8 +20,7 @@ public class Context {
public Context( public Context(
final SignalAccount account, final SignalAccount account,
final SignalServiceAccountManager accountManager, final SignalDependencies dependencies,
final SignalServiceMessageReceiver messageReceiver,
final StickerPackStore stickerPackStore, final StickerPackStore stickerPackStore,
final SendHelper sendHelper, final SendHelper sendHelper,
final GroupHelper groupHelper, final GroupHelper groupHelper,
@ -31,8 +28,7 @@ public class Context {
final ProfileHelper profileHelper final ProfileHelper profileHelper
) { ) {
this.account = account; this.account = account;
this.accountManager = accountManager; this.dependencies = dependencies;
this.messageReceiver = messageReceiver;
this.stickerPackStore = stickerPackStore; this.stickerPackStore = stickerPackStore;
this.sendHelper = sendHelper; this.sendHelper = sendHelper;
this.groupHelper = groupHelper; this.groupHelper = groupHelper;
@ -44,12 +40,8 @@ public class Context {
return account; return account;
} }
public SignalServiceAccountManager getAccountManager() { public SignalDependencies getDependencies() {
return accountManager; return dependencies;
}
public SignalServiceMessageReceiver getMessageReceiver() {
return messageReceiver;
} }
public StickerPackStore getStickerPackStore() { public StickerPackStore getStickerPackStore() {

View file

@ -32,7 +32,9 @@ public class RetrieveStickerPackJob implements Job {
} }
logger.debug("Retrieving sticker pack {}.", Hex.toStringCondensed(packId.serialize())); logger.debug("Retrieving sticker pack {}.", Hex.toStringCondensed(packId.serialize()));
try { try {
final var manifest = context.getMessageReceiver().retrieveStickerManifest(packId.serialize(), packKey); final var manifest = context.getDependencies()
.getMessageReceiver()
.retrieveStickerManifest(packId.serialize(), packKey);
final var stickerIds = new HashSet<Integer>(); final var stickerIds = new HashSet<Integer>();
if (manifest.getCover().isPresent()) { if (manifest.getCover().isPresent()) {
@ -43,7 +45,9 @@ public class RetrieveStickerPackJob implements Job {
} }
for (var id : stickerIds) { for (var id : stickerIds) {
final var inputStream = context.getMessageReceiver().retrieveSticker(packId.serialize(), packKey, id); final var inputStream = context.getDependencies()
.getMessageReceiver()
.retrieveSticker(packId.serialize(), packKey, id);
context.getStickerPackStore().storeSticker(packId, id, o -> IOUtils.copyStream(inputStream, o)); context.getStickerPackStore().storeSticker(packId, id, o -> IOUtils.copyStream(inputStream, o));
} }

View file

@ -21,6 +21,7 @@ import org.asamk.signal.manager.storage.protocol.SignalProtocolStore;
import org.asamk.signal.manager.storage.recipients.Contact; import org.asamk.signal.manager.storage.recipients.Contact;
import org.asamk.signal.manager.storage.recipients.LegacyRecipientStore; import org.asamk.signal.manager.storage.recipients.LegacyRecipientStore;
import org.asamk.signal.manager.storage.recipients.Profile; import org.asamk.signal.manager.storage.recipients.Profile;
import org.asamk.signal.manager.storage.recipients.RecipientAddress;
import org.asamk.signal.manager.storage.recipients.RecipientId; import org.asamk.signal.manager.storage.recipients.RecipientId;
import org.asamk.signal.manager.storage.recipients.RecipientStore; import org.asamk.signal.manager.storage.recipients.RecipientStore;
import org.asamk.signal.manager.storage.sessions.SessionStore; import org.asamk.signal.manager.storage.sessions.SessionStore;
@ -789,7 +790,7 @@ public class SignalAccount implements Closeable {
} }
public RecipientId getSelfRecipientId() { public RecipientId getSelfRecipientId() {
return recipientStore.resolveRecipientTrusted(getSelfAddress()); return recipientStore.resolveRecipientTrusted(new RecipientAddress(uuid, username));
} }
public String getEncryptedDeviceName() { public String getEncryptedDeviceName() {

View file

@ -5,7 +5,7 @@ public class BaseConfig {
public final static String PROJECT_NAME = BaseConfig.class.getPackage().getImplementationTitle(); public final static String PROJECT_NAME = BaseConfig.class.getPackage().getImplementationTitle();
public final static String PROJECT_VERSION = BaseConfig.class.getPackage().getImplementationVersion(); public final static String PROJECT_VERSION = BaseConfig.class.getPackage().getImplementationVersion();
final static String USER_AGENT_SIGNAL_ANDROID = "Signal-Android/5.12.4"; final static String USER_AGENT_SIGNAL_ANDROID = "Signal-Android/5.22.3";
final static String USER_AGENT_SIGNAL_CLI = PROJECT_NAME == null final static String USER_AGENT_SIGNAL_CLI = PROJECT_NAME == null
? "signal-cli" ? "signal-cli"
: PROJECT_NAME + "/" + PROJECT_VERSION; : PROJECT_NAME + "/" + PROJECT_VERSION;

View file

@ -13,6 +13,7 @@ import org.whispersystems.libsignal.util.Pair;
import org.whispersystems.signalservice.api.KeyBackupServicePinException; import org.whispersystems.signalservice.api.KeyBackupServicePinException;
import org.whispersystems.signalservice.api.KeyBackupSystemNoDataException; import org.whispersystems.signalservice.api.KeyBackupSystemNoDataException;
import org.whispersystems.signalservice.api.push.exceptions.CaptchaRequiredException; import org.whispersystems.signalservice.api.push.exceptions.CaptchaRequiredException;
import org.whispersystems.signalservice.api.util.PhoneNumberFormatter;
import java.io.IOException; import java.io.IOException;
import java.net.URI; import java.net.URI;
@ -99,6 +100,10 @@ public class DbusSignalControlImpl implements org.asamk.SignalControl {
public void registerWithCaptcha( public void registerWithCaptcha(
final String number, final boolean voiceVerification, final String captcha final String number, final boolean voiceVerification, final String captcha
) throws Error.Failure, Error.InvalidNumber { ) throws Error.Failure, Error.InvalidNumber {
if (!PhoneNumberFormatter.isValidNumber(number, null)) {
throw new SignalControl.Error.InvalidNumber(
"Invalid username (phone number), make sure you include the country code.");
}
try (final RegistrationManager registrationManager = c.getNewRegistrationManager(number)) { try (final RegistrationManager registrationManager = c.getNewRegistrationManager(number)) {
registrationManager.register(voiceVerification, captcha); registrationManager.register(voiceVerification, captcha);
} catch (CaptchaRequiredException e) { } catch (CaptchaRequiredException e) {