Refactor Context to create helpers lazily

This commit is contained in:
AsamK 2021-12-30 22:02:03 +01:00
parent c88c92086e
commit c7a7d00da5
41 changed files with 559 additions and 762 deletions

View file

@ -1,6 +1,6 @@
package org.asamk.signal.manager;
import org.asamk.signal.manager.jobs.Context;
import org.asamk.signal.manager.helper.Context;
import org.asamk.signal.manager.jobs.Job;
public class JobExecutor {

View file

@ -39,21 +39,7 @@ import org.asamk.signal.manager.groups.GroupNotFoundException;
import org.asamk.signal.manager.groups.GroupSendingNotAllowedException;
import org.asamk.signal.manager.groups.LastGroupAdminException;
import org.asamk.signal.manager.groups.NotAGroupMemberException;
import org.asamk.signal.manager.helper.AttachmentHelper;
import org.asamk.signal.manager.helper.ContactHelper;
import org.asamk.signal.manager.helper.GroupHelper;
import org.asamk.signal.manager.helper.GroupV2Helper;
import org.asamk.signal.manager.helper.IdentityHelper;
import org.asamk.signal.manager.helper.IncomingMessageHandler;
import org.asamk.signal.manager.helper.PinHelper;
import org.asamk.signal.manager.helper.PreKeyHelper;
import org.asamk.signal.manager.helper.ProfileHelper;
import org.asamk.signal.manager.helper.RecipientHelper;
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.UnidentifiedAccessHelper;
import org.asamk.signal.manager.jobs.Context;
import org.asamk.signal.manager.helper.Context;
import org.asamk.signal.manager.storage.SignalAccount;
import org.asamk.signal.manager.storage.groups.GroupInfo;
import org.asamk.signal.manager.storage.identities.IdentityInfo;
@ -125,20 +111,8 @@ public class ManagerImpl implements Manager {
private final ExecutorService executor = Executors.newCachedThreadPool();
private final ProfileHelper profileHelper;
private final PinHelper pinHelper;
private final StorageHelper storageHelper;
private final SendHelper sendHelper;
private final SyncHelper syncHelper;
private final AttachmentHelper attachmentHelper;
private final GroupHelper groupHelper;
private final ContactHelper contactHelper;
private final IncomingMessageHandler incomingMessageHandler;
private final PreKeyHelper preKeyHelper;
private final IdentityHelper identityHelper;
private final RecipientHelper recipientHelper;
private final Context context;
private boolean hasCaughtUpWithOldMessages = false;
private boolean ignoreAttachments = false;
@ -180,76 +154,7 @@ public class ManagerImpl implements Manager {
final var attachmentStore = new AttachmentStore(pathConfig.attachmentsPath());
final var stickerPackStore = new StickerPackStore(pathConfig.stickerPacksPath());
this.attachmentHelper = new AttachmentHelper(dependencies, attachmentStore);
this.pinHelper = new PinHelper(dependencies.getKeyBackupService());
final var unidentifiedAccessHelper = new UnidentifiedAccessHelper(account,
dependencies,
account::getProfileKey,
this::getRecipientProfile);
this.recipientHelper = new RecipientHelper(account, dependencies, serviceEnvironmentConfig);
this.profileHelper = new ProfileHelper(account,
dependencies,
avatarStore,
unidentifiedAccessHelper::getAccessFor,
recipientHelper::resolveSignalServiceAddress);
final GroupV2Helper groupV2Helper = new GroupV2Helper(profileHelper,
account::getSelfRecipientId,
dependencies.getGroupsV2Operations(),
dependencies.getGroupsV2Api(),
recipientHelper::resolveSignalServiceAddress);
this.sendHelper = new SendHelper(account,
dependencies,
unidentifiedAccessHelper,
recipientHelper::resolveSignalServiceAddress,
account.getRecipientStore(),
this::handleIdentityFailure,
this::getGroupInfo,
profileHelper,
recipientHelper::refreshRegisteredUser);
this.groupHelper = new GroupHelper(account,
dependencies,
attachmentHelper,
sendHelper,
groupV2Helper,
avatarStore,
recipientHelper::resolveSignalServiceAddress,
account.getRecipientStore());
this.storageHelper = new StorageHelper(account, dependencies, groupHelper, profileHelper);
this.contactHelper = new ContactHelper(account);
this.syncHelper = new SyncHelper(account,
attachmentHelper,
sendHelper,
groupHelper,
avatarStore,
recipientHelper::resolveSignalServiceAddress);
preKeyHelper = new PreKeyHelper(account, dependencies);
this.context = new Context(account,
dependencies,
stickerPackStore,
sendHelper,
groupHelper,
syncHelper,
profileHelper,
storageHelper,
preKeyHelper);
var jobExecutor = new JobExecutor(context);
this.incomingMessageHandler = new IncomingMessageHandler(account,
dependencies,
account.getRecipientStore(),
recipientHelper::resolveSignalServiceAddress,
groupHelper,
contactHelper,
attachmentHelper,
syncHelper,
profileHelper::getRecipientProfile,
jobExecutor);
this.identityHelper = new IdentityHelper(account,
dependencies,
recipientHelper::resolveSignalServiceAddress,
syncHelper,
profileHelper);
this.context = new Context(account, dependencies, avatarStore, attachmentStore, stickerPackStore);
}
@Override
@ -271,7 +176,7 @@ public class ManagerImpl implements Manager {
}
}
try {
preKeyHelper.refreshPreKeysIfNecessary();
context.getPreKeyHelper().refreshPreKeysIfNecessary();
if (account.getAci() == null) {
account.setAci(ACI.parseOrNull(dependencies.getAccountManager().getWhoAmI().getAci()));
}
@ -308,7 +213,7 @@ public class ManagerImpl implements Manager {
.stream()
.filter(s -> !s.isEmpty())
.collect(Collectors.toSet());
final var registeredUsers = recipientHelper.getRegisteredUsers(canonicalizedNumbersSet);
final var registeredUsers = context.getRecipientHelper().getRegisteredUsers(canonicalizedNumbersSet);
return numbers.stream().collect(Collectors.toMap(n -> n, n -> {
final var number = canonicalizedNumbers.get(n);
@ -370,7 +275,7 @@ public class ManagerImpl implements Manager {
if (configuration.linkPreviews().isPresent()) {
configurationStore.setLinkPreviews(configuration.linkPreviews().get());
}
syncHelper.sendConfigurationMessage();
context.getSyncHelper().sendConfigurationMessage();
}
/**
@ -384,12 +289,13 @@ public class ManagerImpl implements Manager {
public void setProfile(
String givenName, final String familyName, String about, String aboutEmoji, java.util.Optional<File> avatar
) throws IOException {
profileHelper.setProfile(givenName,
context.getProfileHelper()
.setProfile(givenName,
familyName,
about,
aboutEmoji,
avatar == null ? null : Optional.fromNullable(avatar.orElse(null)));
syncHelper.sendSyncFetchProfileMessage();
context.getSyncHelper().sendSyncFetchProfileMessage();
}
@Override
@ -406,7 +312,7 @@ public class ManagerImpl implements Manager {
@Override
public void deleteAccount() throws IOException {
try {
pinHelper.removeRegistrationLockPin();
context.getPinHelper().removeRegistrationLockPin();
} catch (IOException e) {
logger.warn("Failed to remove registration lock pin");
}
@ -490,28 +396,24 @@ public class ManagerImpl implements Manager {
? account.getPinMasterKey()
: KeyUtils.createMasterKey();
pinHelper.setRegistrationLockPin(pin.get(), masterKey);
context.getPinHelper().setRegistrationLockPin(pin.get(), masterKey);
account.setRegistrationLockPin(pin.get(), masterKey);
} else {
// Remove KBS Pin
pinHelper.removeRegistrationLockPin();
context.getPinHelper().removeRegistrationLockPin();
account.setRegistrationLockPin(null, null);
}
}
void refreshPreKeys() throws IOException {
preKeyHelper.refreshPreKeys();
context.getPreKeyHelper().refreshPreKeys();
}
@Override
public Profile getRecipientProfile(RecipientIdentifier.Single recipient) throws IOException, UnregisteredRecipientException {
return profileHelper.getRecipientProfile(recipientHelper.resolveRecipient(recipient));
}
private Profile getRecipientProfile(RecipientId recipientId) {
return profileHelper.getRecipientProfile(recipientId);
return context.getProfileHelper().getRecipientProfile(context.getRecipientHelper().resolveRecipient(recipient));
}
@Override
@ -557,21 +459,22 @@ public class ManagerImpl implements Manager {
public SendGroupMessageResults quitGroup(
GroupId groupId, Set<RecipientIdentifier.Single> groupAdmins
) throws GroupNotFoundException, IOException, NotAGroupMemberException, LastGroupAdminException, UnregisteredRecipientException {
final var newAdmins = recipientHelper.resolveRecipients(groupAdmins);
return groupHelper.quitGroup(groupId, newAdmins);
final var newAdmins = context.getRecipientHelper().resolveRecipients(groupAdmins);
return context.getGroupHelper().quitGroup(groupId, newAdmins);
}
@Override
public void deleteGroup(GroupId groupId) throws IOException {
groupHelper.deleteGroup(groupId);
context.getGroupHelper().deleteGroup(groupId);
}
@Override
public Pair<GroupId, SendGroupMessageResults> createGroup(
String name, Set<RecipientIdentifier.Single> members, File avatarFile
) throws IOException, AttachmentInvalidException, UnregisteredRecipientException {
return groupHelper.createGroup(name,
members == null ? null : recipientHelper.resolveRecipients(members),
return context.getGroupHelper()
.createGroup(name,
members == null ? null : context.getRecipientHelper().resolveRecipients(members),
avatarFile);
}
@ -579,17 +482,22 @@ public class ManagerImpl implements Manager {
public SendGroupMessageResults updateGroup(
final GroupId groupId, final UpdateGroup updateGroup
) throws IOException, GroupNotFoundException, AttachmentInvalidException, NotAGroupMemberException, GroupSendingNotAllowedException, UnregisteredRecipientException {
return groupHelper.updateGroup(groupId,
return context.getGroupHelper()
.updateGroup(groupId,
updateGroup.getName(),
updateGroup.getDescription(),
updateGroup.getMembers() == null ? null : recipientHelper.resolveRecipients(updateGroup.getMembers()),
updateGroup.getMembers() == null
? null
: context.getRecipientHelper().resolveRecipients(updateGroup.getMembers()),
updateGroup.getRemoveMembers() == null
? null
: recipientHelper.resolveRecipients(updateGroup.getRemoveMembers()),
updateGroup.getAdmins() == null ? null : recipientHelper.resolveRecipients(updateGroup.getAdmins()),
: context.getRecipientHelper().resolveRecipients(updateGroup.getRemoveMembers()),
updateGroup.getAdmins() == null
? null
: context.getRecipientHelper().resolveRecipients(updateGroup.getAdmins()),
updateGroup.getRemoveAdmins() == null
? null
: recipientHelper.resolveRecipients(updateGroup.getRemoveAdmins()),
: context.getRecipientHelper().resolveRecipients(updateGroup.getRemoveAdmins()),
updateGroup.isResetGroupLink(),
updateGroup.getGroupLinkState(),
updateGroup.getAddMemberPermission(),
@ -603,7 +511,7 @@ public class ManagerImpl implements Manager {
public Pair<GroupId, SendGroupMessageResults> joinGroup(
GroupInviteLinkUrl inviteLinkUrl
) throws IOException, InactiveGroupLinkException {
return groupHelper.joinGroup(inviteLinkUrl);
return context.getGroupHelper().joinGroup(inviteLinkUrl);
}
private SendMessageResults sendMessage(
@ -615,8 +523,8 @@ public class ManagerImpl implements Manager {
for (final var recipient : recipients) {
if (recipient instanceof RecipientIdentifier.Single single) {
try {
final var recipientId = recipientHelper.resolveRecipient(single);
final var result = sendHelper.sendMessage(messageBuilder, recipientId);
final var recipientId = context.getRecipientHelper().resolveRecipient(single);
final var result = context.getSendHelper().sendMessage(messageBuilder, recipientId);
results.put(recipient,
List.of(SendMessageResult.from(result,
account.getRecipientStore(),
@ -626,13 +534,13 @@ public class ManagerImpl implements Manager {
List.of(SendMessageResult.unregisteredFailure(single.toPartialRecipientAddress())));
}
} else if (recipient instanceof RecipientIdentifier.NoteToSelf) {
final var result = sendHelper.sendSelfMessage(messageBuilder);
final var result = context.getSendHelper().sendSelfMessage(messageBuilder);
results.put(recipient,
List.of(SendMessageResult.from(result,
account.getRecipientStore(),
account.getRecipientStore()::resolveRecipientAddress)));
} else if (recipient instanceof RecipientIdentifier.Group group) {
final var result = sendHelper.sendAsGroupMessage(messageBuilder, group.groupId());
final var result = context.getSendHelper().sendAsGroupMessage(messageBuilder, group.groupId());
results.put(recipient,
result.stream()
.map(sendMessageResult -> SendMessageResult.from(sendMessageResult,
@ -653,8 +561,8 @@ public class ManagerImpl implements Manager {
if (recipient instanceof RecipientIdentifier.Single single) {
final var message = new SignalServiceTypingMessage(action, timestamp, Optional.absent());
try {
final var recipientId = recipientHelper.resolveRecipient(single);
final var result = sendHelper.sendTypingMessage(message, recipientId);
final var recipientId = context.getRecipientHelper().resolveRecipient(single);
final var result = context.getSendHelper().sendTypingMessage(message, recipientId);
results.put(recipient,
List.of(SendMessageResult.from(result,
account.getRecipientStore(),
@ -666,7 +574,7 @@ public class ManagerImpl implements Manager {
} else if (recipient instanceof RecipientIdentifier.Group) {
final var groupId = ((RecipientIdentifier.Group) recipient).groupId();
final var message = new SignalServiceTypingMessage(action, timestamp, Optional.of(groupId.serialize()));
final var result = sendHelper.sendGroupTypingMessage(message, groupId);
final var result = context.getSendHelper().sendGroupTypingMessage(message, groupId);
results.put(recipient,
result.stream()
.map(r -> SendMessageResult.from(r,
@ -715,7 +623,8 @@ public class ManagerImpl implements Manager {
final SignalServiceReceiptMessage receiptMessage
) throws IOException {
try {
final var result = sendHelper.sendReceiptMessage(receiptMessage, recipientHelper.resolveRecipient(sender));
final var result = context.getSendHelper()
.sendReceiptMessage(receiptMessage, context.getRecipientHelper().resolveRecipient(sender));
return new SendMessageResults(timestamp,
Map.of(sender,
List.of(SendMessageResult.from(result,
@ -742,7 +651,7 @@ public class ManagerImpl implements Manager {
messageBuilder.withBody(message.messageText());
final var attachments = message.attachments();
if (attachments != null) {
messageBuilder.withAttachments(attachmentHelper.uploadAttachments(attachments));
messageBuilder.withAttachments(context.getAttachmentHelper().uploadAttachments(attachments));
}
if (message.mentions().size() > 0) {
messageBuilder.withMentions(resolveMentions(message.mentions()));
@ -750,7 +659,8 @@ public class ManagerImpl implements Manager {
if (message.quote().isPresent()) {
final var quote = message.quote().get();
messageBuilder.withQuote(new SignalServiceDataMessage.Quote(quote.timestamp(),
recipientHelper.resolveSignalServiceAddress(recipientHelper.resolveRecipient(quote.author())),
context.getRecipientHelper()
.resolveSignalServiceAddress(context.getRecipientHelper().resolveRecipient(quote.author())),
quote.message(),
List.of(),
resolveMentions(quote.mentions())));
@ -760,8 +670,9 @@ public class ManagerImpl implements Manager {
private ArrayList<SignalServiceDataMessage.Mention> resolveMentions(final List<Message.Mention> mentionList) throws IOException, UnregisteredRecipientException {
final var mentions = new ArrayList<SignalServiceDataMessage.Mention>();
for (final var m : mentionList) {
final var recipientId = recipientHelper.resolveRecipient(m.recipient());
mentions.add(new SignalServiceDataMessage.Mention(recipientHelper.resolveSignalServiceAddress(recipientId)
final var recipientId = context.getRecipientHelper().resolveRecipient(m.recipient());
mentions.add(new SignalServiceDataMessage.Mention(context.getRecipientHelper()
.resolveSignalServiceAddress(recipientId)
.getAci(), m.start(), m.length()));
}
return mentions;
@ -784,10 +695,10 @@ public class ManagerImpl implements Manager {
long targetSentTimestamp,
Set<RecipientIdentifier> recipients
) throws IOException, NotAGroupMemberException, GroupNotFoundException, GroupSendingNotAllowedException, UnregisteredRecipientException {
var targetAuthorRecipientId = recipientHelper.resolveRecipient(targetAuthor);
var targetAuthorRecipientId = context.getRecipientHelper().resolveRecipient(targetAuthor);
var reaction = new SignalServiceDataMessage.Reaction(emoji,
remove,
recipientHelper.resolveSignalServiceAddress(targetAuthorRecipientId),
context.getRecipientHelper().resolveSignalServiceAddress(targetAuthorRecipientId),
targetSentTimestamp);
final var messageBuilder = SignalServiceDataMessage.newBuilder().withReaction(reaction);
return sendMessage(messageBuilder, recipients);
@ -806,7 +717,7 @@ public class ManagerImpl implements Manager {
for (var recipient : recipients) {
final RecipientId recipientId;
try {
recipientId = recipientHelper.resolveRecipient(recipient);
recipientId = context.getRecipientHelper().resolveRecipient(recipient);
} catch (UnregisteredRecipientException e) {
continue;
}
@ -833,7 +744,7 @@ public class ManagerImpl implements Manager {
if (!account.isMasterDevice()) {
throw new NotMasterDeviceException();
}
contactHelper.setContactName(recipientHelper.resolveRecipient(recipient), name);
context.getContactHelper().setContactName(context.getRecipientHelper().resolveRecipient(recipient), name);
}
@Override
@ -843,9 +754,9 @@ public class ManagerImpl implements Manager {
if (!account.isMasterDevice()) {
throw new NotMasterDeviceException();
}
contactHelper.setContactBlocked(recipientHelper.resolveRecipient(recipient), blocked);
context.getContactHelper().setContactBlocked(context.getRecipientHelper().resolveRecipient(recipient), blocked);
// TODO cycle our profile key, if we're not together in a group with recipient
syncHelper.sendBlockedList();
context.getSyncHelper().sendBlockedList();
}
@Override
@ -855,9 +766,9 @@ public class ManagerImpl implements Manager {
if (!account.isMasterDevice()) {
throw new NotMasterDeviceException();
}
groupHelper.setGroupBlocked(groupId, blocked);
context.getGroupHelper().setGroupBlocked(groupId, blocked);
// TODO cycle our profile key
syncHelper.sendBlockedList();
context.getSyncHelper().sendBlockedList();
}
/**
@ -867,8 +778,8 @@ public class ManagerImpl implements Manager {
public void setExpirationTimer(
RecipientIdentifier.Single recipient, int messageExpirationTimer
) throws IOException, UnregisteredRecipientException {
var recipientId = recipientHelper.resolveRecipient(recipient);
contactHelper.setExpirationTimer(recipientId, messageExpirationTimer);
var recipientId = context.getRecipientHelper().resolveRecipient(recipient);
context.getContactHelper().setExpirationTimer(recipientId, messageExpirationTimer);
final var messageBuilder = SignalServiceDataMessage.newBuilder().asExpirationUpdate();
try {
sendMessage(messageBuilder, Set.of(recipient));
@ -911,13 +822,13 @@ public class ManagerImpl implements Manager {
@Override
public void requestAllSyncData() throws IOException {
syncHelper.requestAllSyncData();
context.getSyncHelper().requestAllSyncData();
retrieveRemoteStorage();
}
void retrieveRemoteStorage() throws IOException {
if (account.getStorageKey() != null) {
storageHelper.readDataFromStorage();
context.getStorageHelper().readDataFromStorage();
}
}
@ -941,7 +852,8 @@ public class ManagerImpl implements Manager {
return null;
}
final var result = incomingMessageHandler.handleRetryEnvelope(envelope, ignoreAttachments, handler);
final var result = context.getIncomingMessageHandler()
.handleRetryEnvelope(envelope, ignoreAttachments, handler);
final var actions = result.first();
final var exception = result.second();
@ -1171,7 +1083,7 @@ public class ManagerImpl implements Manager {
continue;
}
final var result = incomingMessageHandler.handleEnvelope(envelope, ignoreAttachments, handler);
final var result = context.getIncomingMessageHandler().handleEnvelope(envelope, ignoreAttachments, handler);
for (final var h : result.first()) {
final var existingAction = queuedActions.get(h);
if (existingAction == null) {
@ -1256,16 +1168,16 @@ public class ManagerImpl implements Manager {
public boolean isContactBlocked(final RecipientIdentifier.Single recipient) {
final RecipientId recipientId;
try {
recipientId = recipientHelper.resolveRecipient(recipient);
recipientId = context.getRecipientHelper().resolveRecipient(recipient);
} catch (IOException | UnregisteredRecipientException e) {
return false;
}
return contactHelper.isContactBlocked(recipientId);
return context.getContactHelper().isContactBlocked(recipientId);
}
@Override
public void sendContacts() throws IOException {
syncHelper.sendContacts();
context.getSyncHelper().sendContacts();
}
@Override
@ -1281,7 +1193,7 @@ public class ManagerImpl implements Manager {
public String getContactOrProfileName(RecipientIdentifier.Single recipient) {
final RecipientId recipientId;
try {
recipientId = recipientHelper.resolveRecipient(recipient);
recipientId = context.getRecipientHelper().resolveRecipient(recipient);
} catch (IOException | UnregisteredRecipientException e) {
return null;
}
@ -1291,7 +1203,7 @@ public class ManagerImpl implements Manager {
return contact.getName();
}
final var profile = profileHelper.getRecipientProfile(recipientId);
final var profile = context.getProfileHelper().getRecipientProfile(recipientId);
if (profile != null) {
return profile.getDisplayName();
}
@ -1301,11 +1213,7 @@ public class ManagerImpl implements Manager {
@Override
public Group getGroup(GroupId groupId) {
return toGroup(groupHelper.getGroup(groupId));
}
private GroupInfo getGroupInfo(GroupId groupId) {
return groupHelper.getGroup(groupId);
return toGroup(context.getGroupHelper().getGroup(groupId));
}
@Override
@ -1319,11 +1227,12 @@ public class ManagerImpl implements Manager {
}
final var address = account.getRecipientStore().resolveRecipientAddress(identityInfo.getRecipientId());
final var scannableFingerprint = identityHelper.computeSafetyNumberForScanning(identityInfo.getRecipientId(),
identityInfo.getIdentityKey());
final var scannableFingerprint = context.getIdentityHelper()
.computeSafetyNumberForScanning(identityInfo.getRecipientId(), identityInfo.getIdentityKey());
return new Identity(address,
identityInfo.getIdentityKey(),
identityHelper.computeSafetyNumber(identityInfo.getRecipientId(), identityInfo.getIdentityKey()),
context.getIdentityHelper()
.computeSafetyNumber(identityInfo.getRecipientId(), identityInfo.getIdentityKey()),
scannableFingerprint == null ? null : scannableFingerprint.getSerialized(),
identityInfo.getTrustLevel(),
identityInfo.getDateAdded());
@ -1333,7 +1242,8 @@ public class ManagerImpl implements Manager {
public List<Identity> getIdentities(RecipientIdentifier.Single recipient) {
IdentityInfo identity;
try {
identity = account.getIdentityKeyStore().getIdentity(recipientHelper.resolveRecipient(recipient));
identity = account.getIdentityKeyStore()
.getIdentity(context.getRecipientHelper().resolveRecipient(recipient));
} catch (IOException | UnregisteredRecipientException e) {
identity = null;
}
@ -1352,11 +1262,11 @@ public class ManagerImpl implements Manager {
) throws UnregisteredRecipientException {
RecipientId recipientId;
try {
recipientId = recipientHelper.resolveRecipient(recipient);
recipientId = context.getRecipientHelper().resolveRecipient(recipient);
} catch (IOException e) {
return false;
}
final var updated = identityHelper.trustIdentityVerified(recipientId, fingerprint);
final var updated = context.getIdentityHelper().trustIdentityVerified(recipientId, fingerprint);
if (updated && this.isReceiving()) {
needsToRetryFailedMessages = true;
}
@ -1375,11 +1285,11 @@ public class ManagerImpl implements Manager {
) throws UnregisteredRecipientException {
RecipientId recipientId;
try {
recipientId = recipientHelper.resolveRecipient(recipient);
recipientId = context.getRecipientHelper().resolveRecipient(recipient);
} catch (IOException e) {
return false;
}
final var updated = identityHelper.trustIdentityVerifiedSafetyNumber(recipientId, safetyNumber);
final var updated = context.getIdentityHelper().trustIdentityVerifiedSafetyNumber(recipientId, safetyNumber);
if (updated && this.isReceiving()) {
needsToRetryFailedMessages = true;
}
@ -1398,11 +1308,11 @@ public class ManagerImpl implements Manager {
) throws UnregisteredRecipientException {
RecipientId recipientId;
try {
recipientId = recipientHelper.resolveRecipient(recipient);
recipientId = context.getRecipientHelper().resolveRecipient(recipient);
} catch (IOException e) {
return false;
}
final var updated = identityHelper.trustIdentityVerifiedSafetyNumber(recipientId, safetyNumber);
final var updated = context.getIdentityHelper().trustIdentityVerifiedSafetyNumber(recipientId, safetyNumber);
if (updated && this.isReceiving()) {
needsToRetryFailedMessages = true;
}
@ -1418,11 +1328,11 @@ public class ManagerImpl implements Manager {
public boolean trustIdentityAllKeys(RecipientIdentifier.Single recipient) throws UnregisteredRecipientException {
RecipientId recipientId;
try {
recipientId = recipientHelper.resolveRecipient(recipient);
recipientId = context.getRecipientHelper().resolveRecipient(recipient);
} catch (IOException e) {
return false;
}
final var updated = identityHelper.trustIdentityAllKeys(recipientId);
final var updated = context.getIdentityHelper().trustIdentityAllKeys(recipientId);
if (updated && this.isReceiving()) {
needsToRetryFailedMessages = true;
}
@ -1436,13 +1346,6 @@ public class ManagerImpl implements Manager {
}
}
private void handleIdentityFailure(
final RecipientId recipientId,
final org.whispersystems.signalservice.api.messages.SendMessageResult.IdentityFailure identityFailure
) {
this.identityHelper.handleIdentityFailure(recipientId, identityFailure);
}
@Override
public void close() throws IOException {
Thread thread;

View file

@ -68,6 +68,10 @@ public class SignalDependencies {
this.sessionLock = sessionLock;
}
public ServiceEnvironmentConfig getServiceEnvironmentConfig() {
return serviceEnvironmentConfig;
}
public SignalServiceAccountManager getAccountManager() {
return getOrCreate(() -> accountManager,
() -> accountManager = new SignalServiceAccountManager(serviceEnvironmentConfig.getSignalServiceConfiguration(),

View file

@ -1,6 +1,6 @@
package org.asamk.signal.manager.actions;
import org.asamk.signal.manager.jobs.Context;
import org.asamk.signal.manager.helper.Context;
public interface HandleAction {

View file

@ -1,6 +1,6 @@
package org.asamk.signal.manager.actions;
import org.asamk.signal.manager.jobs.Context;
import org.asamk.signal.manager.helper.Context;
public class RefreshPreKeysAction implements HandleAction {

View file

@ -1,6 +1,6 @@
package org.asamk.signal.manager.actions;
import org.asamk.signal.manager.jobs.Context;
import org.asamk.signal.manager.helper.Context;
import org.asamk.signal.manager.storage.recipients.RecipientId;
public class RenewSessionAction implements HandleAction {

View file

@ -1,6 +1,6 @@
package org.asamk.signal.manager.actions;
import org.asamk.signal.manager.jobs.Context;
import org.asamk.signal.manager.helper.Context;
import org.asamk.signal.manager.storage.recipients.RecipientId;
public class RetrieveProfileAction implements HandleAction {

View file

@ -1,6 +1,6 @@
package org.asamk.signal.manager.actions;
import org.asamk.signal.manager.jobs.Context;
import org.asamk.signal.manager.helper.Context;
public class RetrieveStorageDataAction implements HandleAction {

View file

@ -1,7 +1,7 @@
package org.asamk.signal.manager.actions;
import org.asamk.signal.manager.groups.GroupIdV1;
import org.asamk.signal.manager.jobs.Context;
import org.asamk.signal.manager.helper.Context;
import org.asamk.signal.manager.storage.recipients.RecipientId;
public class SendGroupInfoAction implements HandleAction {

View file

@ -1,7 +1,7 @@
package org.asamk.signal.manager.actions;
import org.asamk.signal.manager.groups.GroupIdV1;
import org.asamk.signal.manager.jobs.Context;
import org.asamk.signal.manager.helper.Context;
import org.asamk.signal.manager.storage.recipients.RecipientId;
public class SendGroupInfoRequestAction implements HandleAction {

View file

@ -1,6 +1,6 @@
package org.asamk.signal.manager.actions;
import org.asamk.signal.manager.jobs.Context;
import org.asamk.signal.manager.helper.Context;
import org.asamk.signal.manager.storage.recipients.RecipientId;
import java.util.ArrayList;

View file

@ -1,7 +1,7 @@
package org.asamk.signal.manager.actions;
import org.asamk.signal.manager.groups.GroupId;
import org.asamk.signal.manager.jobs.Context;
import org.asamk.signal.manager.helper.Context;
import org.asamk.signal.manager.storage.recipients.RecipientId;
import org.signal.libsignal.metadata.ProtocolException;
import org.whispersystems.libsignal.protocol.CiphertextMessage;

View file

@ -1,6 +1,6 @@
package org.asamk.signal.manager.actions;
import org.asamk.signal.manager.jobs.Context;
import org.asamk.signal.manager.helper.Context;
public class SendSyncBlockedListAction implements HandleAction {

View file

@ -1,6 +1,6 @@
package org.asamk.signal.manager.actions;
import org.asamk.signal.manager.jobs.Context;
import org.asamk.signal.manager.helper.Context;
public class SendSyncConfigurationAction implements HandleAction {

View file

@ -1,6 +1,6 @@
package org.asamk.signal.manager.actions;
import org.asamk.signal.manager.jobs.Context;
import org.asamk.signal.manager.helper.Context;
public class SendSyncContactsAction implements HandleAction {

View file

@ -1,6 +1,6 @@
package org.asamk.signal.manager.actions;
import org.asamk.signal.manager.jobs.Context;
import org.asamk.signal.manager.helper.Context;
public class SendSyncGroupsAction implements HandleAction {

View file

@ -1,6 +1,6 @@
package org.asamk.signal.manager.actions;
import org.asamk.signal.manager.jobs.Context;
import org.asamk.signal.manager.helper.Context;
public class SendSyncKeysAction implements HandleAction {

View file

@ -29,11 +29,9 @@ public class AttachmentHelper {
private final SignalDependencies dependencies;
private final AttachmentStore attachmentStore;
public AttachmentHelper(
final SignalDependencies dependencies, final AttachmentStore attachmentStore
) {
this.dependencies = dependencies;
this.attachmentStore = attachmentStore;
public AttachmentHelper(final Context context) {
this.dependencies = context.getDependencies();
this.attachmentStore = context.getAttachmentStore();
}
public File getAttachmentFile(SignalServiceAttachmentRemoteId attachmentId) {

View file

@ -0,0 +1,155 @@
package org.asamk.signal.manager.helper;
import org.asamk.signal.manager.AttachmentStore;
import org.asamk.signal.manager.AvatarStore;
import org.asamk.signal.manager.JobExecutor;
import org.asamk.signal.manager.SignalDependencies;
import org.asamk.signal.manager.StickerPackStore;
import org.asamk.signal.manager.storage.SignalAccount;
import java.util.function.Supplier;
public class Context {
private final Object LOCK = new Object();
private final SignalAccount account;
private final SignalDependencies dependencies;
private final AvatarStore avatarStore;
private final StickerPackStore stickerPackStore;
private final AttachmentStore attachmentStore;
private final JobExecutor jobExecutor;
private AttachmentHelper attachmentHelper;
private ContactHelper contactHelper;
private GroupHelper groupHelper;
private GroupV2Helper groupV2Helper;
private IdentityHelper identityHelper;
private IncomingMessageHandler incomingMessageHandler;
private PinHelper pinHelper;
private PreKeyHelper preKeyHelper;
private ProfileHelper profileHelper;
private RecipientHelper recipientHelper;
private SendHelper sendHelper;
private StorageHelper storageHelper;
private SyncHelper syncHelper;
private UnidentifiedAccessHelper unidentifiedAccessHelper;
public Context(
final SignalAccount account,
final SignalDependencies dependencies,
final AvatarStore avatarStore,
final AttachmentStore attachmentStore,
final StickerPackStore stickerPackStore
) {
this.account = account;
this.dependencies = dependencies;
this.avatarStore = avatarStore;
this.stickerPackStore = stickerPackStore;
this.attachmentStore = attachmentStore;
this.jobExecutor = new JobExecutor(this);
}
public SignalAccount getAccount() {
return account;
}
public SignalDependencies getDependencies() {
return dependencies;
}
public AvatarStore getAvatarStore() {
return avatarStore;
}
public StickerPackStore getStickerPackStore() {
return stickerPackStore;
}
AttachmentStore getAttachmentStore() {
return attachmentStore;
}
JobExecutor getJobExecutor() {
return jobExecutor;
}
public AttachmentHelper getAttachmentHelper() {
return getOrCreate(() -> attachmentHelper, () -> attachmentHelper = new AttachmentHelper(this));
}
public ContactHelper getContactHelper() {
return getOrCreate(() -> contactHelper, () -> contactHelper = new ContactHelper(account));
}
GroupV2Helper getGroupV2Helper() {
return getOrCreate(() -> groupV2Helper, () -> groupV2Helper = new GroupV2Helper(this));
}
public GroupHelper getGroupHelper() {
return getOrCreate(() -> groupHelper, () -> groupHelper = new GroupHelper(this));
}
public IdentityHelper getIdentityHelper() {
return getOrCreate(() -> identityHelper, () -> identityHelper = new IdentityHelper(this));
}
public IncomingMessageHandler getIncomingMessageHandler() {
return getOrCreate(() -> incomingMessageHandler,
() -> this.incomingMessageHandler = new IncomingMessageHandler(this));
}
public PinHelper getPinHelper() {
return getOrCreate(() -> pinHelper, () -> pinHelper = new PinHelper(dependencies.getKeyBackupService()));
}
public PreKeyHelper getPreKeyHelper() {
return getOrCreate(() -> preKeyHelper, () -> preKeyHelper = new PreKeyHelper(account, dependencies));
}
public ProfileHelper getProfileHelper() {
return getOrCreate(() -> profileHelper, () -> profileHelper = new ProfileHelper(this));
}
public RecipientHelper getRecipientHelper() {
return getOrCreate(() -> recipientHelper, () -> recipientHelper = new RecipientHelper(this));
}
public SendHelper getSendHelper() {
return getOrCreate(() -> sendHelper, () -> sendHelper = new SendHelper(this));
}
public StorageHelper getStorageHelper() {
return getOrCreate(() -> storageHelper, () -> storageHelper = new StorageHelper(this));
}
public SyncHelper getSyncHelper() {
return getOrCreate(() -> syncHelper, () -> syncHelper = new SyncHelper(this));
}
UnidentifiedAccessHelper getUnidentifiedAccessHelper() {
return getOrCreate(() -> unidentifiedAccessHelper,
() -> unidentifiedAccessHelper = new UnidentifiedAccessHelper(this));
}
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

@ -1,7 +1,6 @@
package org.asamk.signal.manager.helper;
import org.asamk.signal.manager.AttachmentInvalidException;
import org.asamk.signal.manager.AvatarStore;
import org.asamk.signal.manager.SignalDependencies;
import org.asamk.signal.manager.api.InactiveGroupLinkException;
import org.asamk.signal.manager.api.Pair;
@ -24,7 +23,6 @@ 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.recipients.RecipientId;
import org.asamk.signal.manager.storage.recipients.RecipientResolver;
import org.asamk.signal.manager.util.AttachmentUtils;
import org.asamk.signal.manager.util.IOUtils;
import org.signal.storageservice.protos.groups.GroupChange;
@ -63,31 +61,12 @@ public class GroupHelper {
private final SignalAccount account;
private final SignalDependencies dependencies;
private final AttachmentHelper attachmentHelper;
private final SendHelper sendHelper;
private final GroupV2Helper groupV2Helper;
private final AvatarStore avatarStore;
private final SignalServiceAddressResolver addressResolver;
private final RecipientResolver recipientResolver;
private final Context context;
public GroupHelper(
final SignalAccount account,
final SignalDependencies dependencies,
final AttachmentHelper attachmentHelper,
final SendHelper sendHelper,
final GroupV2Helper groupV2Helper,
final AvatarStore avatarStore,
final SignalServiceAddressResolver addressResolver,
final RecipientResolver recipientResolver
) {
this.account = account;
this.dependencies = dependencies;
this.attachmentHelper = attachmentHelper;
this.sendHelper = sendHelper;
this.groupV2Helper = groupV2Helper;
this.avatarStore = avatarStore;
this.addressResolver = addressResolver;
this.recipientResolver = recipientResolver;
public GroupHelper(final Context context) {
this.account = context.getAccount();
this.dependencies = context.getDependencies();
this.context = context;
}
public GroupInfo getGroup(GroupId groupId) {
@ -101,15 +80,16 @@ public class GroupHelper {
public void downloadGroupAvatar(GroupIdV1 groupId, SignalServiceAttachment avatar) {
try {
avatarStore.storeGroupAvatar(groupId,
outputStream -> attachmentHelper.retrieveAttachment(avatar, outputStream));
context.getAvatarStore()
.storeGroupAvatar(groupId,
outputStream -> context.getAttachmentHelper().retrieveAttachment(avatar, outputStream));
} catch (IOException e) {
logger.warn("Failed to download avatar for group {}, ignoring: {}", groupId.toBase64(), e.getMessage());
}
}
public Optional<SignalServiceAttachmentStream> createGroupAvatarAttachment(GroupIdV1 groupId) throws IOException {
final var streamDetails = avatarStore.retrieveGroupAvatar(groupId);
final var streamDetails = context.getAvatarStore().retrieveGroupAvatar(groupId);
if (streamDetails == null) {
return Optional.absent();
}
@ -143,13 +123,12 @@ public class GroupHelper {
if (signedGroupChange != null
&& groupInfoV2.getGroup() != null
&& groupInfoV2.getGroup().getRevision() + 1 == revision) {
group = groupV2Helper.getUpdatedDecryptedGroup(groupInfoV2.getGroup(),
signedGroupChange,
groupMasterKey);
group = context.getGroupV2Helper()
.getUpdatedDecryptedGroup(groupInfoV2.getGroup(), signedGroupChange, groupMasterKey);
}
if (group == null) {
try {
group = groupV2Helper.getDecryptedGroup(groupSecretParams);
group = context.getGroupV2Helper().getDecryptedGroup(groupSecretParams);
} catch (NotAGroupMemberException ignored) {
}
}
@ -160,7 +139,7 @@ public class GroupHelper {
downloadGroupAvatar(groupId, groupSecretParams, avatar);
}
}
groupInfoV2.setGroup(group, recipientResolver);
groupInfoV2.setGroup(group, account.getRecipientStore());
account.getGroupStore().updateGroup(groupInfoV2);
}
@ -176,9 +155,8 @@ public class GroupHelper {
members.remove(selfRecipientId);
}
var gv2Pair = groupV2Helper.createGroup(name == null ? "" : name,
members == null ? Set.of() : members,
avatarFile);
var gv2Pair = context.getGroupV2Helper()
.createGroup(name == null ? "" : name, members == null ? Set.of() : members, avatarFile);
if (gv2Pair == null) {
// Failed to create v2 group, creating v1 group instead
@ -191,9 +169,10 @@ public class GroupHelper {
final var gv2 = gv2Pair.first();
final var decryptedGroup = gv2Pair.second();
gv2.setGroup(decryptedGroup, recipientResolver);
gv2.setGroup(decryptedGroup, account.getRecipientStore());
if (avatarFile != null) {
avatarStore.storeGroupAvatar(gv2.getGroupId(),
context.getAvatarStore()
.storeGroupAvatar(gv2.getGroupId(),
outputStream -> IOUtils.copyFileToStream(avatarFile, outputStream));
}
@ -274,14 +253,13 @@ public class GroupHelper {
) throws IOException, InactiveGroupLinkException {
final DecryptedGroupJoinInfo groupJoinInfo;
try {
groupJoinInfo = groupV2Helper.getDecryptedGroupJoinInfo(inviteLinkUrl.getGroupMasterKey(),
inviteLinkUrl.getPassword());
groupJoinInfo = context.getGroupV2Helper()
.getDecryptedGroupJoinInfo(inviteLinkUrl.getGroupMasterKey(), inviteLinkUrl.getPassword());
} catch (GroupLinkNotActiveException e) {
throw new InactiveGroupLinkException("Group link inactive", e);
}
final var groupChange = groupV2Helper.joinGroup(inviteLinkUrl.getGroupMasterKey(),
inviteLinkUrl.getPassword(),
groupJoinInfo);
final var groupChange = context.getGroupV2Helper()
.joinGroup(inviteLinkUrl.getGroupMasterKey(), inviteLinkUrl.getPassword(), groupJoinInfo);
final var group = getOrMigrateGroup(inviteLinkUrl.getGroupMasterKey(),
groupJoinInfo.getRevision() + 1,
groupChange.toByteArray());
@ -315,7 +293,7 @@ public class GroupHelper {
public void deleteGroup(GroupId groupId) throws IOException {
account.getGroupStore().deleteGroup(groupId);
avatarStore.deleteGroupAvatar(groupId);
context.getAvatarStore().deleteGroupAvatar(groupId);
}
public void setGroupBlocked(final GroupId groupId, final boolean blocked) throws GroupNotFoundException {
@ -366,12 +344,12 @@ public class GroupHelper {
final var groupSecretParams = GroupSecretParams.deriveFromMasterKey(groupInfoV2.getMasterKey());
DecryptedGroup decryptedGroup;
try {
decryptedGroup = groupV2Helper.getDecryptedGroup(groupSecretParams);
decryptedGroup = context.getGroupV2Helper().getDecryptedGroup(groupSecretParams);
} catch (NotAGroupMemberException e) {
groupInfoV2.setPermissionDenied(true);
decryptedGroup = null;
}
groupInfoV2.setGroup(decryptedGroup, recipientResolver);
groupInfoV2.setGroup(decryptedGroup, account.getRecipientStore());
account.getGroupStore().updateGroup(group);
}
}
@ -380,7 +358,8 @@ public class GroupHelper {
private void downloadGroupAvatar(GroupIdV2 groupId, GroupSecretParams groupSecretParams, String cdnKey) {
try {
avatarStore.storeGroupAvatar(groupId,
context.getAvatarStore()
.storeGroupAvatar(groupId,
outputStream -> retrieveGroupV2Avatar(groupSecretParams, cdnKey, outputStream));
} catch (IOException e) {
logger.warn("Failed to download avatar for group {}, ignoring: {}", groupId.toBase64(), e.getMessage());
@ -458,7 +437,8 @@ public class GroupHelper {
}
if (avatarFile != null) {
avatarStore.storeGroupAvatar(g.getGroupId(),
context.getAvatarStore()
.storeGroupAvatar(g.getGroupId(),
outputStream -> IOUtils.copyFileToStream(avatarFile, outputStream));
}
}
@ -476,7 +456,7 @@ public class GroupHelper {
private void sendExpirationTimerUpdate(GroupIdV1 groupId) throws IOException, NotAGroupMemberException, GroupNotFoundException, GroupSendingNotAllowedException {
final var messageBuilder = SignalServiceDataMessage.newBuilder().asExpirationUpdate();
sendHelper.sendAsGroupMessage(messageBuilder, groupId);
context.getSendHelper().sendAsGroupMessage(messageBuilder, groupId);
}
private SendGroupMessageResults updateGroupV2(
@ -496,6 +476,7 @@ public class GroupHelper {
final Boolean isAnnouncementGroup
) throws IOException {
SendGroupMessageResults result = null;
final var groupV2Helper = context.getGroupV2Helper();
if (group.isPendingMember(account.getSelfRecipientId())) {
var groupGroupChangePair = groupV2Helper.acceptInvite(group);
result = sendUpdateGroupV2Message(group, groupGroupChangePair.first(), groupGroupChangePair.second());
@ -587,7 +568,8 @@ public class GroupHelper {
if (name != null || description != null || avatarFile != null) {
var groupGroupChangePair = groupV2Helper.updateGroup(group, name, description, avatarFile);
if (avatarFile != null) {
avatarStore.storeGroupAvatar(group.getGroupId(),
context.getAvatarStore()
.storeGroupAvatar(group.getGroupId(),
outputStream -> IOUtils.copyFileToStream(avatarFile, outputStream));
}
result = sendUpdateGroupV2Message(group, groupGroupChangePair.first(), groupGroupChangePair.second());
@ -622,8 +604,8 @@ public class GroupHelper {
// Last admin can't leave the group, unless she's also the last member
throw new LastGroupAdminException(groupInfoV2.getGroupId(), groupInfoV2.getTitle());
}
final var groupGroupChangePair = groupV2Helper.leaveGroup(groupInfoV2, newAdmins);
groupInfoV2.setGroup(groupGroupChangePair.first(), recipientResolver);
final var groupGroupChangePair = context.getGroupV2Helper().leaveGroup(groupInfoV2, newAdmins);
groupInfoV2.setGroup(groupGroupChangePair.first(), account.getRecipientStore());
account.getGroupStore().updateGroup(groupInfoV2);
var messageBuilder = getGroupUpdateMessageBuilder(groupInfoV2, groupGroupChangePair.second().toByteArray());
@ -636,7 +618,10 @@ public class GroupHelper {
var group = SignalServiceGroup.newBuilder(SignalServiceGroup.Type.UPDATE)
.withId(g.getGroupId().serialize())
.withName(g.name)
.withMembers(g.getMembers().stream().map(addressResolver::resolveSignalServiceAddress).toList());
.withMembers(g.getMembers()
.stream()
.map(context.getRecipientHelper()::resolveSignalServiceAddress)
.toList());
try {
final var attachment = createGroupAvatarAttachment(g.getGroupId());
@ -666,7 +651,7 @@ public class GroupHelper {
) throws IOException {
final var selfRecipientId = account.getSelfRecipientId();
final var members = group.getMembersIncludingPendingWithout(selfRecipientId);
group.setGroup(newDecryptedGroup, recipientResolver);
group.setGroup(newDecryptedGroup, account.getRecipientStore());
members.addAll(group.getMembersIncludingPendingWithout(selfRecipientId));
account.getGroupStore().updateGroup(group);
@ -681,11 +666,11 @@ public class GroupHelper {
) throws IOException {
final var timestamp = System.currentTimeMillis();
messageBuilder.withTimestamp(timestamp);
final var results = sendHelper.sendGroupMessage(messageBuilder.build(), members, distributionId);
final var results = context.getSendHelper().sendGroupMessage(messageBuilder.build(), members, distributionId);
return new SendGroupMessageResults(timestamp,
results.stream()
.map(sendMessageResult -> SendMessageResult.from(sendMessageResult,
recipientResolver,
account.getRecipientStore(),
account.getRecipientStore()::resolveRecipientAddress))
.toList());
}

View file

@ -1,9 +0,0 @@
package org.asamk.signal.manager.helper;
import org.asamk.signal.manager.groups.GroupId;
import org.asamk.signal.manager.storage.groups.GroupInfo;
public interface GroupProvider {
GroupInfo getGroup(GroupId groupId);
}

View file

@ -2,6 +2,7 @@ package org.asamk.signal.manager.helper;
import com.google.protobuf.InvalidProtocolBufferException;
import org.asamk.signal.manager.SignalDependencies;
import org.asamk.signal.manager.api.Pair;
import org.asamk.signal.manager.groups.GroupLinkPassword;
import org.asamk.signal.manager.groups.GroupLinkState;
@ -32,7 +33,6 @@ import org.whispersystems.libsignal.util.guava.Optional;
import org.whispersystems.signalservice.api.groupsv2.DecryptedGroupUtil;
import org.whispersystems.signalservice.api.groupsv2.GroupCandidate;
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.groupsv2.InvalidGroupStateException;
@ -56,32 +56,20 @@ public class GroupV2Helper {
private final static Logger logger = LoggerFactory.getLogger(GroupV2Helper.class);
private final ProfileHelper profileHelper;
private final SelfRecipientIdProvider selfRecipientIdProvider;
private final GroupsV2Operations groupsV2Operations;
private final GroupsV2Api groupsV2Api;
private final SignalServiceAddressResolver addressResolver;
private final SignalDependencies dependencies;
private final Context context;
private HashMap<Integer, AuthCredentialResponse> groupApiCredentials;
public GroupV2Helper(
final ProfileHelper profileHelper,
final SelfRecipientIdProvider selfRecipientIdProvider,
final GroupsV2Operations groupsV2Operations,
final GroupsV2Api groupsV2Api,
final SignalServiceAddressResolver addressResolver
) {
this.profileHelper = profileHelper;
this.selfRecipientIdProvider = selfRecipientIdProvider;
this.groupsV2Operations = groupsV2Operations;
this.groupsV2Api = groupsV2Api;
this.addressResolver = addressResolver;
public GroupV2Helper(final Context context) {
this.dependencies = context.getDependencies();
this.context = context;
}
public DecryptedGroup getDecryptedGroup(final GroupSecretParams groupSecretParams) throws NotAGroupMemberException {
try {
final var groupsV2AuthorizationString = getGroupAuthForToday(groupSecretParams);
return groupsV2Api.getGroup(groupSecretParams, groupsV2AuthorizationString);
return dependencies.getGroupsV2Api().getGroup(groupSecretParams, groupsV2AuthorizationString);
} catch (NonSuccessfulResponseCodeException e) {
if (e.getCode() == 403) {
throw new NotAGroupMemberException(GroupUtils.getGroupIdV2(groupSecretParams), null);
@ -99,7 +87,8 @@ public class GroupV2Helper {
) throws IOException, GroupLinkNotActiveException {
var groupSecretParams = GroupSecretParams.deriveFromMasterKey(groupMasterKey);
return groupsV2Api.getGroupJoinInfo(groupSecretParams,
return dependencies.getGroupsV2Api()
.getGroupJoinInfo(groupSecretParams,
Optional.fromNullable(password).transform(GroupLinkPassword::serialize),
getGroupAuthForToday(groupSecretParams));
}
@ -119,8 +108,8 @@ public class GroupV2Helper {
final DecryptedGroup decryptedGroup;
try {
groupAuthForToday = getGroupAuthForToday(groupSecretParams);
groupsV2Api.putNewGroup(newGroup, groupAuthForToday);
decryptedGroup = groupsV2Api.getGroup(groupSecretParams, groupAuthForToday);
dependencies.getGroupsV2Api().putNewGroup(newGroup, groupAuthForToday);
decryptedGroup = dependencies.getGroupsV2Api().getGroup(groupSecretParams, groupAuthForToday);
} catch (IOException | VerificationFailedException | InvalidGroupStateException e) {
logger.warn("Failed to create V2 group: {}", e.getMessage());
return null;
@ -148,7 +137,8 @@ public class GroupV2Helper {
private GroupsV2Operations.NewGroup buildNewGroup(
String name, Set<RecipientId> members, byte[] avatar
) {
final var profileKeyCredential = profileHelper.getRecipientProfileKeyCredential(selfRecipientIdProvider.getSelfRecipientId());
final var profileKeyCredential = context.getProfileHelper()
.getRecipientProfileKeyCredential(context.getAccount().getSelfRecipientId());
if (profileKeyCredential == null) {
logger.warn("Cannot create a V2 group as self does not have a versioned profile");
return null;
@ -158,16 +148,17 @@ public class GroupV2Helper {
final var self = new GroupCandidate(getSelfAci().uuid(), Optional.fromNullable(profileKeyCredential));
final var memberList = new ArrayList<>(members);
final var credentials = profileHelper.getRecipientProfileKeyCredential(memberList).stream();
final var credentials = context.getProfileHelper().getRecipientProfileKeyCredential(memberList).stream();
final var uuids = memberList.stream()
.map(member -> addressResolver.resolveSignalServiceAddress(member).getAci().uuid());
.map(member -> context.getRecipientHelper().resolveSignalServiceAddress(member).getAci().uuid());
var candidates = Utils.zip(uuids,
credentials,
(uuid, credential) -> new GroupCandidate(uuid, Optional.fromNullable(credential)))
.collect(Collectors.toSet());
final var groupSecretParams = GroupSecretParams.generate();
return groupsV2Operations.createNewGroup(groupSecretParams,
return dependencies.getGroupsV2Operations()
.createNewGroup(groupSecretParams,
name,
Optional.fromNullable(avatar),
self,
@ -177,7 +168,8 @@ public class GroupV2Helper {
}
private boolean areMembersValid(final Set<RecipientId> members) {
final var noGv2Capability = profileHelper.getRecipientProfile(new ArrayList<>(members))
final var noGv2Capability = context.getProfileHelper()
.getRecipientProfile(new ArrayList<>(members))
.stream()
.filter(profile -> profile != null && !profile.getCapabilities().contains(Profile.Capability.gv2))
.collect(Collectors.toSet());
@ -194,7 +186,7 @@ public class GroupV2Helper {
GroupInfoV2 groupInfoV2, String name, String description, File avatarFile
) throws IOException {
final var groupSecretParams = GroupSecretParams.deriveFromMasterKey(groupInfoV2.getMasterKey());
var groupOperations = groupsV2Operations.forGroup(groupSecretParams);
var groupOperations = dependencies.getGroupsV2Operations().forGroup(groupSecretParams);
var change = name != null ? groupOperations.createModifyGroupTitle(name) : GroupChange.Actions.newBuilder();
@ -204,9 +196,8 @@ public class GroupV2Helper {
if (avatarFile != null) {
final var avatarBytes = readAvatarBytes(avatarFile);
var avatarCdnKey = groupsV2Api.uploadAvatar(avatarBytes,
groupSecretParams,
getGroupAuthForToday(groupSecretParams));
var avatarCdnKey = dependencies.getGroupsV2Api()
.uploadAvatar(avatarBytes, groupSecretParams, getGroupAuthForToday(groupSecretParams));
change.setModifyAvatar(GroupChange.Actions.ModifyAvatarAction.newBuilder().setAvatar(avatarCdnKey));
}
@ -225,9 +216,9 @@ public class GroupV2Helper {
}
final var memberList = new ArrayList<>(newMembers);
final var credentials = profileHelper.getRecipientProfileKeyCredential(memberList).stream();
final var credentials = context.getProfileHelper().getRecipientProfileKeyCredential(memberList).stream();
final var uuids = memberList.stream()
.map(member -> addressResolver.resolveSignalServiceAddress(member).getAci().uuid());
.map(member -> context.getRecipientHelper().resolveSignalServiceAddress(member).getAci().uuid());
var candidates = Utils.zip(uuids,
credentials,
(uuid, credential) -> new GroupCandidate(uuid, Optional.fromNullable(credential)))
@ -253,7 +244,7 @@ public class GroupV2Helper {
}
final var adminUuids = membersToMakeAdmin.stream()
.map(addressResolver::resolveSignalServiceAddress)
.map(context.getRecipientHelper()::resolveSignalServiceAddress)
.map(SignalServiceAddress::getAci)
.map(ACI::uuid)
.toList();
@ -266,7 +257,7 @@ public class GroupV2Helper {
GroupInfoV2 groupInfoV2, Set<RecipientId> members
) throws IOException {
final var memberUuids = members.stream()
.map(addressResolver::resolveSignalServiceAddress)
.map(context.getRecipientHelper()::resolveSignalServiceAddress)
.map(SignalServiceAddress::getAci)
.map(ACI::uuid)
.collect(Collectors.toSet());
@ -278,7 +269,7 @@ public class GroupV2Helper {
) throws IOException {
var pendingMembersList = groupInfoV2.getGroup().getPendingMembersList();
final var memberUuids = members.stream()
.map(addressResolver::resolveSignalServiceAddress)
.map(context.getRecipientHelper()::resolveSignalServiceAddress)
.map(SignalServiceAddress::getAci)
.map(ACI::uuid)
.map(uuid -> DecryptedGroupUtil.findPendingByUuid(pendingMembersList, uuid))
@ -337,10 +328,10 @@ public class GroupV2Helper {
DecryptedGroupJoinInfo decryptedGroupJoinInfo
) throws IOException {
final var groupSecretParams = GroupSecretParams.deriveFromMasterKey(groupMasterKey);
final var groupOperations = groupsV2Operations.forGroup(groupSecretParams);
final var groupOperations = dependencies.getGroupsV2Operations().forGroup(groupSecretParams);
final var selfRecipientId = this.selfRecipientIdProvider.getSelfRecipientId();
final var profileKeyCredential = profileHelper.getRecipientProfileKeyCredential(selfRecipientId);
final var selfRecipientId = context.getAccount().getSelfRecipientId();
final var profileKeyCredential = context.getProfileHelper().getRecipientProfileKeyCredential(selfRecipientId);
if (profileKeyCredential == null) {
throw new IOException("Cannot join a V2 group as self does not have a versioned profile");
}
@ -350,7 +341,10 @@ public class GroupV2Helper {
? groupOperations.createGroupJoinRequest(profileKeyCredential)
: groupOperations.createGroupJoinDirect(profileKeyCredential);
change.setSourceUuid(addressResolver.resolveSignalServiceAddress(selfRecipientId).getAci().toByteString());
change.setSourceUuid(context.getRecipientHelper()
.resolveSignalServiceAddress(selfRecipientId)
.getAci()
.toByteString());
return commitChange(groupSecretParams, decryptedGroupJoinInfo.getRevision(), change, groupLinkPassword);
}
@ -358,15 +352,15 @@ public class GroupV2Helper {
public Pair<DecryptedGroup, GroupChange> acceptInvite(GroupInfoV2 groupInfoV2) throws IOException {
final GroupsV2Operations.GroupOperations groupOperations = getGroupOperations(groupInfoV2);
final var selfRecipientId = this.selfRecipientIdProvider.getSelfRecipientId();
final var profileKeyCredential = profileHelper.getRecipientProfileKeyCredential(selfRecipientId);
final var selfRecipientId = context.getAccount().getSelfRecipientId();
final var profileKeyCredential = context.getProfileHelper().getRecipientProfileKeyCredential(selfRecipientId);
if (profileKeyCredential == null) {
throw new IOException("Cannot join a V2 group as self does not have a versioned profile");
}
final var change = groupOperations.createAcceptInviteChange(profileKeyCredential);
final var aci = addressResolver.resolveSignalServiceAddress(selfRecipientId).getAci();
final var aci = context.getRecipientHelper().resolveSignalServiceAddress(selfRecipientId).getAci();
change.setSourceUuid(aci.toByteString());
return commitChange(groupInfoV2, change);
@ -376,7 +370,7 @@ public class GroupV2Helper {
GroupInfoV2 groupInfoV2, RecipientId recipientId, boolean admin
) throws IOException {
final GroupsV2Operations.GroupOperations groupOperations = getGroupOperations(groupInfoV2);
final var address = addressResolver.resolveSignalServiceAddress(recipientId);
final var address = context.getRecipientHelper().resolveSignalServiceAddress(recipientId);
final var newRole = admin ? Member.Role.ADMINISTRATOR : Member.Role.DEFAULT;
final var change = groupOperations.createChangeMemberRole(address.getAci().uuid(), newRole);
return commitChange(groupInfoV2, change);
@ -415,7 +409,7 @@ public class GroupV2Helper {
private GroupsV2Operations.GroupOperations getGroupOperations(final GroupInfoV2 groupInfoV2) {
final var groupSecretParams = GroupSecretParams.deriveFromMasterKey(groupInfoV2.getMasterKey());
return groupsV2Operations.forGroup(groupSecretParams);
return dependencies.getGroupsV2Operations().forGroup(groupSecretParams);
}
private Pair<DecryptedGroup, GroupChange> revokeInvites(
@ -443,7 +437,7 @@ public class GroupV2Helper {
GroupInfoV2 groupInfoV2, GroupChange.Actions.Builder change
) throws IOException {
final var groupSecretParams = GroupSecretParams.deriveFromMasterKey(groupInfoV2.getMasterKey());
final var groupOperations = groupsV2Operations.forGroup(groupSecretParams);
final var groupOperations = dependencies.getGroupsV2Operations().forGroup(groupSecretParams);
final var previousGroupState = groupInfoV2.getGroup();
final var nextRevision = previousGroupState.getRevision() + 1;
final var changeActions = change.setRevision(nextRevision).build();
@ -457,9 +451,8 @@ public class GroupV2Helper {
throw new IOException(e);
}
var signedGroupChange = groupsV2Api.patchGroup(changeActions,
getGroupAuthForToday(groupSecretParams),
Optional.absent());
var signedGroupChange = dependencies.getGroupsV2Api()
.patchGroup(changeActions, getGroupAuthForToday(groupSecretParams), Optional.absent());
return new Pair<>(decryptedGroupState, signedGroupChange);
}
@ -473,7 +466,8 @@ public class GroupV2Helper {
final var nextRevision = currentRevision + 1;
final var changeActions = change.setRevision(nextRevision).build();
return groupsV2Api.patchGroup(changeActions,
return dependencies.getGroupsV2Api()
.patchGroup(changeActions,
getGroupAuthForToday(groupSecretParams),
Optional.fromNullable(password).transform(GroupLinkPassword::serialize));
}
@ -494,7 +488,8 @@ public class GroupV2Helper {
private DecryptedGroupChange getDecryptedGroupChange(byte[] signedGroupChange, GroupMasterKey groupMasterKey) {
if (signedGroupChange != null) {
var groupOperations = groupsV2Operations.forGroup(GroupSecretParams.deriveFromMasterKey(groupMasterKey));
var groupOperations = dependencies.getGroupsV2Operations()
.forGroup(GroupSecretParams.deriveFromMasterKey(groupMasterKey));
try {
return groupOperations.decryptChange(GroupChange.parseFrom(signedGroupChange), true).orNull();
@ -516,19 +511,20 @@ public class GroupV2Helper {
final var today = currentTimeDays();
if (groupApiCredentials == null || !groupApiCredentials.containsKey(today)) {
// Returns credentials for the next 7 days
groupApiCredentials = groupsV2Api.getCredentials(today);
groupApiCredentials = dependencies.getGroupsV2Api().getCredentials(today);
// TODO cache credentials on disk until they expire
}
var authCredentialResponse = groupApiCredentials.get(today);
final var aci = getSelfAci();
try {
return groupsV2Api.getGroupsV2AuthorizationString(aci, today, groupSecretParams, authCredentialResponse);
return dependencies.getGroupsV2Api()
.getGroupsV2AuthorizationString(aci, today, groupSecretParams, authCredentialResponse);
} catch (VerificationFailedException e) {
throw new IOException(e);
}
}
private ACI getSelfAci() {
return addressResolver.resolveSignalServiceAddress(this.selfRecipientIdProvider.getSelfRecipientId()).getAci();
return context.getAccount().getAci();
}
}

View file

@ -1,9 +0,0 @@
package org.asamk.signal.manager.helper;
import org.asamk.signal.manager.storage.recipients.RecipientId;
import org.whispersystems.signalservice.api.messages.SendMessageResult;
public interface IdentityFailureHandler {
void handleIdentityFailure(RecipientId recipientId, SendMessageResult.IdentityFailure identityFailure);
}

View file

@ -1,6 +1,5 @@
package org.asamk.signal.manager.helper;
import org.asamk.signal.manager.SignalDependencies;
import org.asamk.signal.manager.TrustLevel;
import org.asamk.signal.manager.storage.SignalAccount;
import org.asamk.signal.manager.storage.recipients.RecipientId;
@ -27,23 +26,11 @@ public class IdentityHelper {
private final static Logger logger = LoggerFactory.getLogger(IdentityHelper.class);
private final SignalAccount account;
private final SignalDependencies dependencies;
private final SignalServiceAddressResolver addressResolver;
private final SyncHelper syncHelper;
private final ProfileHelper profileHelper;
private final Context context;
public IdentityHelper(
final SignalAccount account,
final SignalDependencies dependencies,
final SignalServiceAddressResolver addressResolver,
final SyncHelper syncHelper,
final ProfileHelper profileHelper
) {
this.account = account;
this.dependencies = dependencies;
this.addressResolver = addressResolver;
this.syncHelper = syncHelper;
this.profileHelper = profileHelper;
public IdentityHelper(final Context context) {
this.account = context.getAccount();
this.context = context;
}
public boolean trustIdentityVerified(RecipientId recipientId, byte[] fingerprint) {
@ -74,13 +61,13 @@ public class IdentityHelper {
}
public String computeSafetyNumber(RecipientId recipientId, IdentityKey theirIdentityKey) {
var address = addressResolver.resolveSignalServiceAddress(recipientId);
var address = context.getRecipientHelper().resolveSignalServiceAddress(recipientId);
final Fingerprint fingerprint = computeSafetyNumberFingerprint(address, theirIdentityKey);
return fingerprint == null ? null : fingerprint.getDisplayableFingerprint().getDisplayText();
}
public ScannableFingerprint computeSafetyNumberForScanning(RecipientId recipientId, IdentityKey theirIdentityKey) {
var address = addressResolver.resolveSignalServiceAddress(recipientId);
var address = context.getRecipientHelper().resolveSignalServiceAddress(recipientId);
final Fingerprint fingerprint = computeSafetyNumberFingerprint(address, theirIdentityKey);
return fingerprint == null ? null : fingerprint.getScannableFingerprint();
}
@ -109,8 +96,8 @@ public class IdentityHelper {
account.getIdentityKeyStore().setIdentityTrustLevel(recipientId, identity.getIdentityKey(), trustLevel);
try {
var address = addressResolver.resolveSignalServiceAddress(recipientId);
syncHelper.sendVerifiedMessage(address, identity.getIdentityKey(), trustLevel);
var address = context.getRecipientHelper().resolveSignalServiceAddress(recipientId);
context.getSyncHelper().sendVerifiedMessage(address, identity.getIdentityKey(), trustLevel);
} catch (IOException e) {
logger.warn("Failed to send verification sync message: {}", e.getMessage());
}
@ -130,7 +117,7 @@ public class IdentityHelper {
}
} else {
// Retrieve profile to get the current identity key from the server
profileHelper.refreshRecipientProfile(recipientId);
context.getProfileHelper().refreshRecipientProfile(recipientId);
}
}
}

View file

@ -1,6 +1,5 @@
package org.asamk.signal.manager.helper;
import org.asamk.signal.manager.JobExecutor;
import org.asamk.signal.manager.Manager;
import org.asamk.signal.manager.SignalDependencies;
import org.asamk.signal.manager.TrustLevel;
@ -29,7 +28,6 @@ import org.asamk.signal.manager.storage.SignalAccount;
import org.asamk.signal.manager.storage.groups.GroupInfoV1;
import org.asamk.signal.manager.storage.recipients.Profile;
import org.asamk.signal.manager.storage.recipients.RecipientId;
import org.asamk.signal.manager.storage.recipients.RecipientResolver;
import org.asamk.signal.manager.storage.stickers.Sticker;
import org.asamk.signal.manager.storage.stickers.StickerPackId;
import org.signal.libsignal.metadata.ProtocolInvalidKeyException;
@ -61,37 +59,12 @@ public final class IncomingMessageHandler {
private final SignalAccount account;
private final SignalDependencies dependencies;
private final RecipientResolver recipientResolver;
private final SignalServiceAddressResolver addressResolver;
private final GroupHelper groupHelper;
private final ContactHelper contactHelper;
private final AttachmentHelper attachmentHelper;
private final SyncHelper syncHelper;
private final ProfileProvider profileProvider;
private final JobExecutor jobExecutor;
private final Context context;
public IncomingMessageHandler(
final SignalAccount account,
final SignalDependencies dependencies,
final RecipientResolver recipientResolver,
final SignalServiceAddressResolver addressResolver,
final GroupHelper groupHelper,
final ContactHelper contactHelper,
final AttachmentHelper attachmentHelper,
final SyncHelper syncHelper,
final ProfileProvider profileProvider,
final JobExecutor jobExecutor
) {
this.account = account;
this.dependencies = dependencies;
this.recipientResolver = recipientResolver;
this.addressResolver = addressResolver;
this.groupHelper = groupHelper;
this.contactHelper = contactHelper;
this.attachmentHelper = attachmentHelper;
this.syncHelper = syncHelper;
this.profileProvider = profileProvider;
this.jobExecutor = jobExecutor;
public IncomingMessageHandler(final Context context) {
this.account = context.getAccount();
this.dependencies = context.getDependencies();
this.context = context;
}
public Pair<List<HandleAction>, Exception> handleRetryEnvelope(
@ -147,8 +120,8 @@ public final class IncomingMessageHandler {
.resolveRecipientAddress(recipientId), e.getSenderDevice());
} catch (ProtocolInvalidKeyIdException | ProtocolInvalidKeyException | ProtocolNoSessionException | ProtocolInvalidMessageException e) {
final var sender = account.getRecipientStore().resolveRecipient(e.getSender());
final var senderProfile = profileProvider.getProfile(sender);
final var selfProfile = profileProvider.getProfile(account.getSelfRecipientId());
final var senderProfile = context.getProfileHelper().getRecipientProfile(sender);
final var selfProfile = context.getProfileHelper().getRecipientProfile(account.getSelfRecipientId());
if (e.getSenderDevice() != account.getDeviceId()
&& senderProfile != null
&& senderProfile.getCapabilities().contains(Profile.Capability.senderKey)
@ -202,9 +175,9 @@ public final class IncomingMessageHandler {
}
handler.handleMessage(MessageEnvelope.from(envelope,
content,
recipientResolver,
account.getRecipientStore(),
account.getRecipientStore()::resolveRecipientAddress,
attachmentHelper::getAttachmentFile), exception);
context.getAttachmentHelper()::getAttachmentFile), exception);
return actions;
}
}
@ -216,16 +189,17 @@ public final class IncomingMessageHandler {
final RecipientId sender;
final int senderDeviceId;
if (!envelope.isUnidentifiedSender() && envelope.hasSourceUuid()) {
sender = recipientResolver.resolveRecipient(envelope.getSourceAddress());
sender = context.getRecipientHelper().resolveRecipient(envelope.getSourceAddress());
senderDeviceId = envelope.getSourceDevice();
} else {
sender = recipientResolver.resolveRecipient(content.getSender());
sender = context.getRecipientHelper().resolveRecipient(content.getSender());
senderDeviceId = content.getSenderDevice();
}
if (content.getSenderKeyDistributionMessage().isPresent()) {
final var message = content.getSenderKeyDistributionMessage().get();
final var protocolAddress = new SignalProtocolAddress(addressResolver.resolveSignalServiceAddress(sender)
final var protocolAddress = new SignalProtocolAddress(context.getRecipientHelper()
.resolveSignalServiceAddress(sender)
.getIdentifier(), senderDeviceId);
logger.debug("Received a sender key distribution message for distributionId {} from {}",
message.getDistributionId(),
@ -281,7 +255,7 @@ public final class IncomingMessageHandler {
actions.addAll(handleSignalServiceDataMessage(message.getMessage(),
true,
sender,
destination == null ? null : recipientResolver.resolveRecipient(destination),
destination == null ? null : context.getRecipientHelper().resolveRecipient(destination),
ignoreAttachments));
}
if (syncMessage.getRequest().isPresent() && account.isMasterDevice()) {
@ -308,14 +282,15 @@ public final class IncomingMessageHandler {
if (syncMessage.getBlockedList().isPresent()) {
final var blockedListMessage = syncMessage.getBlockedList().get();
for (var address : blockedListMessage.getAddresses()) {
contactHelper.setContactBlocked(recipientResolver.resolveRecipient(address), true);
context.getContactHelper()
.setContactBlocked(context.getRecipientHelper().resolveRecipient(address), true);
}
for (var groupId : blockedListMessage.getGroupIds()
.stream()
.map(GroupId::unknownVersion)
.collect(Collectors.toSet())) {
try {
groupHelper.setGroupBlocked(groupId, true);
context.getGroupHelper().setGroupBlocked(groupId, true);
} catch (GroupNotFoundException e) {
logger.warn("BlockedListMessage contained groupID that was not found in GroupStore: {}",
groupId.toBase64());
@ -325,8 +300,9 @@ public final class IncomingMessageHandler {
if (syncMessage.getContacts().isPresent()) {
try {
final var contactsMessage = syncMessage.getContacts().get();
attachmentHelper.retrieveAttachment(contactsMessage.getContactsStream(),
syncHelper::handleSyncDeviceContacts);
context.getAttachmentHelper()
.retrieveAttachment(contactsMessage.getContactsStream(),
context.getSyncHelper()::handleSyncDeviceContacts);
} catch (Exception e) {
logger.warn("Failed to handle received sync contacts, ignoring: {}", e.getMessage());
}
@ -355,7 +331,8 @@ public final class IncomingMessageHandler {
sticker = new Sticker(stickerPackId, m.getPackKey().get());
}
if (installed) {
jobExecutor.enqueueJob(new RetrieveStickerPackJob(stickerPackId, m.getPackKey().get()));
context.getJobExecutor()
.enqueueJob(new RetrieveStickerPackJob(stickerPackId, m.getPackKey().get()));
}
}
@ -410,8 +387,8 @@ public final class IncomingMessageHandler {
} else {
return false;
}
final var recipientId = recipientResolver.resolveRecipient(source);
if (contactHelper.isContactBlocked(recipientId)) {
final var recipientId = context.getRecipientHelper().resolveRecipient(source);
if (context.getContactHelper().isContactBlocked(recipientId)) {
return true;
}
@ -419,7 +396,7 @@ public final class IncomingMessageHandler {
var message = content.getDataMessage().get();
if (message.getGroupContext().isPresent()) {
var groupId = GroupUtils.getGroupId(message.getGroupContext().get());
return groupHelper.isGroupBlocked(groupId);
return context.getGroupHelper().isGroupBlocked(groupId);
}
}
@ -453,12 +430,12 @@ public final class IncomingMessageHandler {
}
var groupId = GroupUtils.getGroupId(message.getGroupContext().get());
var group = groupHelper.getGroup(groupId);
var group = context.getGroupHelper().getGroup(groupId);
if (group == null) {
return false;
}
final var recipientId = recipientResolver.resolveRecipient(source);
final var recipientId = context.getRecipientHelper().resolveRecipient(source);
if (!group.isMember(recipientId) && !(group.isPendingMember(recipientId) && message.isGroupV2Update())) {
return true;
}
@ -487,7 +464,7 @@ public final class IncomingMessageHandler {
if (message.getGroupContext().get().getGroupV1().isPresent()) {
var groupInfo = message.getGroupContext().get().getGroupV1().get();
var groupId = GroupId.v1(groupInfo.getGroupId());
var group = groupHelper.getGroup(groupId);
var group = context.getGroupHelper().getGroup(groupId);
if (group == null || group instanceof GroupInfoV1) {
var groupV1 = (GroupInfoV1) group;
switch (groupInfo.getType()) {
@ -498,7 +475,7 @@ public final class IncomingMessageHandler {
if (groupInfo.getAvatar().isPresent()) {
var avatar = groupInfo.getAvatar().get();
groupHelper.downloadGroupAvatar(groupV1.getGroupId(), avatar);
context.getGroupHelper().downloadGroupAvatar(groupV1.getGroupId(), avatar);
}
if (groupInfo.getName().isPresent()) {
@ -509,7 +486,7 @@ public final class IncomingMessageHandler {
groupV1.addMembers(groupInfo.getMembers()
.get()
.stream()
.map(recipientResolver::resolveRecipient)
.map(context.getRecipientHelper()::resolveRecipient)
.collect(Collectors.toSet()));
}
@ -542,7 +519,8 @@ public final class IncomingMessageHandler {
final var groupContext = message.getGroupContext().get().getGroupV2().get();
final var groupMasterKey = groupContext.getMasterKey();
groupHelper.getOrMigrateGroup(groupMasterKey,
context.getGroupHelper()
.getOrMigrateGroup(groupMasterKey,
groupContext.getRevision(),
groupContext.hasSignedGroupChange() ? groupContext.getSignedGroupChange() : null);
}
@ -567,19 +545,20 @@ public final class IncomingMessageHandler {
// disappearing message timer already stored in the DecryptedGroup
}
} else if (conversationPartnerAddress != null) {
contactHelper.setExpirationTimer(conversationPartnerAddress, message.getExpiresInSeconds());
context.getContactHelper()
.setExpirationTimer(conversationPartnerAddress, message.getExpiresInSeconds());
}
}
if (!ignoreAttachments) {
if (message.getAttachments().isPresent()) {
for (var attachment : message.getAttachments().get()) {
attachmentHelper.downloadAttachment(attachment);
context.getAttachmentHelper().downloadAttachment(attachment);
}
}
if (message.getSharedContacts().isPresent()) {
for (var contact : message.getSharedContacts().get()) {
if (contact.getAvatar().isPresent()) {
attachmentHelper.downloadAttachment(contact.getAvatar().get().getAttachment());
context.getAttachmentHelper().downloadAttachment(contact.getAvatar().get().getAttachment());
}
}
}
@ -587,7 +566,7 @@ public final class IncomingMessageHandler {
final var previews = message.getPreviews().get();
for (var preview : previews) {
if (preview.getImage().isPresent()) {
attachmentHelper.downloadAttachment(preview.getImage().get());
context.getAttachmentHelper().downloadAttachment(preview.getImage().get());
}
}
}
@ -597,7 +576,7 @@ public final class IncomingMessageHandler {
for (var quotedAttachment : quote.getAttachments()) {
final var thumbnail = quotedAttachment.getThumbnail();
if (thumbnail != null) {
attachmentHelper.downloadAttachment(thumbnail);
context.getAttachmentHelper().downloadAttachment(thumbnail);
}
}
}
@ -622,7 +601,7 @@ public final class IncomingMessageHandler {
sticker = new Sticker(stickerPackId, messageSticker.getPackKey());
account.getStickerStore().updateSticker(sticker);
}
jobExecutor.enqueueJob(new RetrieveStickerPackJob(stickerPackId, messageSticker.getPackKey()));
context.getJobExecutor().enqueueJob(new RetrieveStickerPackJob(stickerPackId, messageSticker.getPackKey()));
}
return actions;
}

View file

@ -1,6 +1,5 @@
package org.asamk.signal.manager.helper;
import org.asamk.signal.manager.AvatarStore;
import org.asamk.signal.manager.SignalDependencies;
import org.asamk.signal.manager.config.ServiceConfig;
import org.asamk.signal.manager.storage.SignalAccount;
@ -43,22 +42,12 @@ public final class ProfileHelper {
private final SignalAccount account;
private final SignalDependencies dependencies;
private final AvatarStore avatarStore;
private final UnidentifiedAccessProvider unidentifiedAccessProvider;
private final SignalServiceAddressResolver addressResolver;
private final Context context;
public ProfileHelper(
final SignalAccount account,
final SignalDependencies dependencies,
final AvatarStore avatarStore,
final UnidentifiedAccessProvider unidentifiedAccessProvider,
final SignalServiceAddressResolver addressResolver
) {
this.account = account;
this.dependencies = dependencies;
this.avatarStore = avatarStore;
this.unidentifiedAccessProvider = unidentifiedAccessProvider;
this.addressResolver = addressResolver;
public ProfileHelper(final Context context) {
this.account = context.getAccount();
this.dependencies = context.getDependencies();
this.context = context;
}
public Profile getRecipientProfile(RecipientId recipientId) {
@ -139,7 +128,8 @@ public final class ProfileHelper {
if (uploadProfile) {
try (final var streamDetails = avatar == null
? avatarStore.retrieveProfileAvatar(account.getSelfAddress())
? context.getAvatarStore()
.retrieveProfileAvatar(account.getSelfAddress())
: avatar.isPresent() ? Utils.createStreamDetailsFromFile(avatar.get()) : null) {
final var avatarPath = dependencies.getAccountManager()
.setVersionedProfile(account.getAci(),
@ -157,10 +147,11 @@ public final class ProfileHelper {
if (avatar != null) {
if (avatar.isPresent()) {
avatarStore.storeProfileAvatar(account.getSelfAddress(),
context.getAvatarStore()
.storeProfileAvatar(account.getSelfAddress(),
outputStream -> IOUtils.copyFileToStream(avatar.get(), outputStream));
} else {
avatarStore.deleteProfileAvatar(account.getSelfAddress());
context.getAvatarStore().deleteProfileAvatar(account.getSelfAddress());
}
}
account.getProfileStore().storeProfile(account.getSelfRecipientId(), newProfile);
@ -224,7 +215,9 @@ public final class ProfileHelper {
) {
var profile = account.getProfileStore().getProfile(recipientId);
if (profile == null || !Objects.equals(avatarPath, profile.getAvatarUrlPath())) {
downloadProfileAvatar(addressResolver.resolveSignalServiceAddress(recipientId), avatarPath, profileKey);
downloadProfileAvatar(context.getRecipientHelper().resolveSignalServiceAddress(recipientId),
avatarPath,
profileKey);
var builder = profile == null ? Profile.newBuilder() : Profile.newBuilder(profile);
account.getProfileStore().storeProfile(recipientId, builder.withAvatarUrlPath(avatarPath).build());
}
@ -250,7 +243,7 @@ public final class ProfileHelper {
var unidentifiedAccess = getUnidentifiedAccess(recipientId);
var profileKey = Optional.fromNullable(account.getProfileStore().getProfileKey(recipientId));
final var address = addressResolver.resolveSignalServiceAddress(recipientId);
final var address = context.getRecipientHelper().resolveSignalServiceAddress(recipientId);
return retrieveProfile(address, profileKey, unidentifiedAccess, requestType).doOnSuccess(p -> {
final var encryptedProfile = p.getProfile();
@ -289,7 +282,7 @@ public final class ProfileHelper {
}
} catch (InvalidKeyException ignored) {
logger.warn("Got invalid identity key in profile for {}",
addressResolver.resolveSignalServiceAddress(recipientId).getIdentifier());
context.getRecipientHelper().resolveSignalServiceAddress(recipientId).getIdentifier());
}
}).doOnError(e -> {
logger.warn("Failed to retrieve profile, ignoring: {}", e.getMessage());
@ -333,7 +326,7 @@ public final class ProfileHelper {
) {
if (avatarPath == null) {
try {
avatarStore.deleteProfileAvatar(address);
context.getAvatarStore().deleteProfileAvatar(address);
} catch (IOException e) {
logger.warn("Failed to delete local profile avatar, ignoring: {}", e.getMessage());
}
@ -341,7 +334,8 @@ public final class ProfileHelper {
}
try {
avatarStore.storeProfileAvatar(address,
context.getAvatarStore()
.storeProfileAvatar(address,
outputStream -> retrieveProfileAvatar(avatarPath, profileKey, outputStream));
} catch (Throwable e) {
if (e instanceof AssertionError && e.getCause() instanceof InterruptedException) {
@ -374,7 +368,7 @@ public final class ProfileHelper {
}
private Optional<UnidentifiedAccess> getUnidentifiedAccess(RecipientId recipientId) {
var unidentifiedAccess = unidentifiedAccessProvider.getAccessFor(recipientId, true);
var unidentifiedAccess = context.getUnidentifiedAccessHelper().getAccessFor(recipientId, true);
if (unidentifiedAccess.isPresent()) {
return unidentifiedAccess.get().getTargetUnidentifiedAccess();

View file

@ -1,9 +0,0 @@
package org.asamk.signal.manager.helper;
import org.asamk.signal.manager.storage.recipients.RecipientId;
import org.signal.zkgroup.profiles.ProfileKeyCredential;
public interface ProfileKeyCredentialProvider {
ProfileKeyCredential getProfileKeyCredential(RecipientId recipientId);
}

View file

@ -1,9 +0,0 @@
package org.asamk.signal.manager.helper;
import org.asamk.signal.manager.storage.recipients.Profile;
import org.asamk.signal.manager.storage.recipients.RecipientId;
public interface ProfileProvider {
Profile getProfile(RecipientId recipientId);
}

View file

@ -32,14 +32,10 @@ public class RecipientHelper {
private final SignalDependencies dependencies;
private final ServiceEnvironmentConfig serviceEnvironmentConfig;
public RecipientHelper(
final SignalAccount account,
final SignalDependencies dependencies,
final ServiceEnvironmentConfig serviceEnvironmentConfig
) {
this.account = account;
this.dependencies = dependencies;
this.serviceEnvironmentConfig = serviceEnvironmentConfig;
public RecipientHelper(final Context context) {
this.account = context.getAccount();
this.dependencies = context.getDependencies();
this.serviceEnvironmentConfig = dependencies.getServiceEnvironmentConfig();
}
public SignalServiceAddress resolveSignalServiceAddress(RecipientId recipientId) {
@ -64,6 +60,10 @@ public class RecipientHelper {
.toSignalServiceAddress();
}
public RecipientId resolveRecipient(final SignalServiceAddress address) {
return account.getRecipientStore().resolveRecipient(address);
}
public Set<RecipientId> resolveRecipients(Collection<RecipientIdentifier.Single> recipients) throws IOException, UnregisteredRecipientException {
final var recipientIds = new HashSet<RecipientId>(recipients.size());
for (var number : recipients) {

View file

@ -1,11 +0,0 @@
package org.asamk.signal.manager.helper;
import org.asamk.signal.manager.api.UnregisteredRecipientException;
import org.asamk.signal.manager.storage.recipients.RecipientId;
import java.io.IOException;
public interface RecipientRegistrationRefresher {
RecipientId refreshRecipientRegistration(RecipientId recipientId) throws IOException, UnregisteredRecipientException;
}

View file

@ -1,8 +0,0 @@
package org.asamk.signal.manager.helper;
import org.signal.zkgroup.profiles.ProfileKey;
public interface SelfProfileKeyProvider {
ProfileKey getProfileKey();
}

View file

@ -1,8 +0,0 @@
package org.asamk.signal.manager.helper;
import org.asamk.signal.manager.storage.recipients.RecipientId;
public interface SelfRecipientIdProvider {
RecipientId getSelfRecipientId();
}

View file

@ -11,7 +11,6 @@ import org.asamk.signal.manager.storage.SignalAccount;
import org.asamk.signal.manager.storage.groups.GroupInfo;
import org.asamk.signal.manager.storage.recipients.Profile;
import org.asamk.signal.manager.storage.recipients.RecipientId;
import org.asamk.signal.manager.storage.recipients.RecipientResolver;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.whispersystems.libsignal.InvalidKeyException;
@ -53,34 +52,12 @@ public class SendHelper {
private final SignalAccount account;
private final SignalDependencies dependencies;
private final UnidentifiedAccessHelper unidentifiedAccessHelper;
private final SignalServiceAddressResolver addressResolver;
private final RecipientResolver recipientResolver;
private final IdentityFailureHandler identityFailureHandler;
private final GroupProvider groupProvider;
private final ProfileHelper profileHelper;
private final RecipientRegistrationRefresher recipientRegistrationRefresher;
private final Context context;
public SendHelper(
final SignalAccount account,
final SignalDependencies dependencies,
final UnidentifiedAccessHelper unidentifiedAccessHelper,
final SignalServiceAddressResolver addressResolver,
final RecipientResolver recipientResolver,
final IdentityFailureHandler identityFailureHandler,
final GroupProvider groupProvider,
final ProfileHelper profileHelper,
final RecipientRegistrationRefresher recipientRegistrationRefresher
) {
this.account = account;
this.dependencies = dependencies;
this.unidentifiedAccessHelper = unidentifiedAccessHelper;
this.addressResolver = addressResolver;
this.recipientResolver = recipientResolver;
this.identityFailureHandler = identityFailureHandler;
this.groupProvider = groupProvider;
this.profileHelper = profileHelper;
this.recipientRegistrationRefresher = recipientRegistrationRefresher;
public SendHelper(final Context context) {
this.account = context.getAccount();
this.dependencies = context.getDependencies();
this.context = context;
}
/**
@ -223,22 +200,22 @@ public class SendHelper {
public SendMessageResult sendSyncMessage(SignalServiceSyncMessage message) {
var messageSender = dependencies.getMessageSender();
try {
return messageSender.sendSyncMessage(message, unidentifiedAccessHelper.getAccessForSync());
return messageSender.sendSyncMessage(message, context.getUnidentifiedAccessHelper().getAccessForSync());
} catch (UnregisteredUserException e) {
var address = addressResolver.resolveSignalServiceAddress(account.getSelfRecipientId());
var address = context.getRecipientHelper().resolveSignalServiceAddress(account.getSelfRecipientId());
return SendMessageResult.unregisteredFailure(address);
} catch (ProofRequiredException e) {
var address = addressResolver.resolveSignalServiceAddress(account.getSelfRecipientId());
var address = context.getRecipientHelper().resolveSignalServiceAddress(account.getSelfRecipientId());
return SendMessageResult.proofRequiredFailure(address, e);
} catch (RateLimitException e) {
var address = addressResolver.resolveSignalServiceAddress(account.getSelfRecipientId());
var address = context.getRecipientHelper().resolveSignalServiceAddress(account.getSelfRecipientId());
logger.warn("Sending failed due to rate limiting from the signal server: {}", e.getMessage());
return SendMessageResult.networkFailure(address);
} catch (org.whispersystems.signalservice.api.crypto.UntrustedIdentityException e) {
var address = addressResolver.resolveSignalServiceAddress(account.getSelfRecipientId());
var address = context.getRecipientHelper().resolveSignalServiceAddress(account.getSelfRecipientId());
return SendMessageResult.identityFailure(address, e.getIdentityKey());
} catch (IOException e) {
var address = addressResolver.resolveSignalServiceAddress(account.getSelfRecipientId());
var address = context.getRecipientHelper().resolveSignalServiceAddress(account.getSelfRecipientId());
logger.warn("Failed to send message due to IO exception: {}", e.getMessage());
return SendMessageResult.networkFailure(address);
}
@ -292,7 +269,7 @@ public class SendHelper {
}
private GroupInfo getGroupForSending(GroupId groupId) throws GroupNotFoundException, NotAGroupMemberException {
var g = groupProvider.getGroup(groupId);
var g = context.getGroupHelper().getGroup(groupId);
if (g == null) {
throw new GroupNotFoundException(groupId);
}
@ -327,7 +304,7 @@ public class SendHelper {
results.stream().filter(SendMessageResult::isSuccess).forEach(allResults::add);
final var failedTargets = results.stream()
.filter(r -> !r.isSuccess())
.map(r -> recipientResolver.resolveRecipient(r.getAddress()))
.map(r -> context.getRecipientHelper().resolveRecipient(r.getAddress()))
.toList();
if (failedTargets.size() > 0) {
senderKeyTargets = new HashSet<>(senderKeyTargets);
@ -357,7 +334,7 @@ public class SendHelper {
}
private Set<RecipientId> getSenderKeyCapableRecipientIds(final Set<RecipientId> recipientIds) {
final var selfProfile = profileHelper.getRecipientProfile(account.getSelfRecipientId());
final var selfProfile = context.getProfileHelper().getRecipientProfile(account.getSelfRecipientId());
if (selfProfile == null || !selfProfile.getCapabilities().contains(Profile.Capability.senderKey)) {
logger.debug("Not all of our devices support sender key. Using legacy.");
return Set.of();
@ -365,14 +342,14 @@ public class SendHelper {
final var senderKeyTargets = new HashSet<RecipientId>();
final var recipientList = new ArrayList<>(recipientIds);
final var profiles = profileHelper.getRecipientProfile(recipientList).iterator();
final var profiles = context.getProfileHelper().getRecipientProfile(recipientList).iterator();
for (final var recipientId : recipientList) {
final var profile = profiles.next();
if (profile == null || !profile.getCapabilities().contains(Profile.Capability.senderKey)) {
continue;
}
final var access = unidentifiedAccessHelper.getAccessFor(recipientId);
final var access = context.getUnidentifiedAccessHelper().getAccessFor(recipientId);
if (!access.isPresent() || !access.get().getTargetUnidentifiedAccess().isPresent()) {
continue;
}
@ -398,8 +375,10 @@ public class SendHelper {
final LegacySenderHandler sender, final Set<RecipientId> recipientIds, final boolean isRecipientUpdate
) throws IOException {
final var recipientIdList = new ArrayList<>(recipientIds);
final var addresses = recipientIdList.stream().map(addressResolver::resolveSignalServiceAddress).toList();
final var unidentifiedAccesses = unidentifiedAccessHelper.getAccessFor(recipientIdList);
final var addresses = recipientIdList.stream()
.map(context.getRecipientHelper()::resolveSignalServiceAddress)
.toList();
final var unidentifiedAccesses = context.getUnidentifiedAccessHelper().getAccessFor(recipientIdList);
try {
final var results = sender.send(addresses, unidentifiedAccesses, isRecipientUpdate);
@ -433,9 +412,10 @@ public class SendHelper {
}
List<SignalServiceAddress> addresses = recipientIdList.stream()
.map(addressResolver::resolveSignalServiceAddress)
.map(context.getRecipientHelper()::resolveSignalServiceAddress)
.collect(Collectors.toList());
List<UnidentifiedAccess> unidentifiedAccesses = unidentifiedAccessHelper.getAccessFor(recipientIdList)
List<UnidentifiedAccess> unidentifiedAccesses = context.getUnidentifiedAccessHelper()
.getAccessFor(recipientIdList)
.stream()
.map(Optional::get)
.map(UnidentifiedAccessPair::getTargetUnidentifiedAccess)
@ -490,19 +470,21 @@ public class SendHelper {
private SendMessageResult handleSendMessage(RecipientId recipientId, SenderHandler s) {
var messageSender = dependencies.getMessageSender();
var address = addressResolver.resolveSignalServiceAddress(recipientId);
var address = context.getRecipientHelper().resolveSignalServiceAddress(recipientId);
try {
try {
return s.send(messageSender, address, unidentifiedAccessHelper.getAccessFor(recipientId));
return s.send(messageSender, address, context.getUnidentifiedAccessHelper().getAccessFor(recipientId));
} catch (UnregisteredUserException e) {
final RecipientId newRecipientId;
try {
newRecipientId = recipientRegistrationRefresher.refreshRecipientRegistration(recipientId);
newRecipientId = context.getRecipientHelper().refreshRegisteredUser(recipientId);
} catch (UnregisteredRecipientException ex) {
return SendMessageResult.unregisteredFailure(address);
}
address = addressResolver.resolveSignalServiceAddress(newRecipientId);
return s.send(messageSender, address, unidentifiedAccessHelper.getAccessFor(newRecipientId));
address = context.getRecipientHelper().resolveSignalServiceAddress(newRecipientId);
return s.send(messageSender,
address,
context.getUnidentifiedAccessHelper().getAccessFor(newRecipientId));
}
} catch (UnregisteredUserException e) {
return SendMessageResult.unregisteredFailure(address);
@ -534,7 +516,7 @@ public class SendHelper {
private void handleSendMessageResult(final SendMessageResult r) {
if (r.isSuccess() && !r.getSuccess().isUnidentified()) {
final var recipientId = recipientResolver.resolveRecipient(r.getAddress());
final var recipientId = context.getRecipientHelper().resolveRecipient(r.getAddress());
final var profile = account.getRecipientStore().getProfile(recipientId);
if (profile != null && (
profile.getUnidentifiedAccessMode() == Profile.UnidentifiedAccessMode.ENABLED
@ -548,7 +530,7 @@ public class SendHelper {
}
}
if (r.isUnregisteredFailure()) {
final var recipientId = recipientResolver.resolveRecipient(r.getAddress());
final var recipientId = context.getRecipientHelper().resolveRecipient(r.getAddress());
final var profile = account.getRecipientStore().getProfile(recipientId);
if (profile != null && (
profile.getUnidentifiedAccessMode() == Profile.UnidentifiedAccessMode.ENABLED
@ -562,8 +544,8 @@ public class SendHelper {
}
}
if (r.getIdentityFailure() != null) {
final var recipientId = recipientResolver.resolveRecipient(r.getAddress());
identityFailureHandler.handleIdentityFailure(recipientId, r.getIdentityFailure());
final var recipientId = context.getRecipientHelper().resolveRecipient(r.getAddress());
context.getIdentityHelper().handleIdentityFailure(recipientId, r.getIdentityFailure());
}
}

View file

@ -1,9 +0,0 @@
package org.asamk.signal.manager.helper;
import org.asamk.signal.manager.storage.recipients.RecipientId;
import org.whispersystems.signalservice.api.push.SignalServiceAddress;
public interface SignalServiceAddressResolver {
SignalServiceAddress resolveSignalServiceAddress(RecipientId recipientId);
}

View file

@ -32,19 +32,12 @@ public class StorageHelper {
private final SignalAccount account;
private final SignalDependencies dependencies;
private final GroupHelper groupHelper;
private final ProfileHelper profileHelper;
private final Context context;
public StorageHelper(
final SignalAccount account,
final SignalDependencies dependencies,
final GroupHelper groupHelper,
final ProfileHelper profileHelper
) {
this.account = account;
this.dependencies = dependencies;
this.groupHelper = groupHelper;
this.profileHelper = profileHelper;
public StorageHelper(final Context context) {
this.account = context.getAccount();
this.dependencies = context.getDependencies();
this.context = context;
}
public void readDataFromStorage() throws IOException {
@ -139,7 +132,7 @@ public class StorageHelper {
final var group = account.getGroupStore().getGroup(groupIdV1);
if (group == null) {
try {
groupHelper.sendGroupInfoRequest(groupIdV1, account.getSelfRecipientId());
context.getGroupHelper().sendGroupInfoRequest(groupIdV1, account.getSelfRecipientId());
} catch (Throwable e) {
logger.warn("Failed to send group request", e);
}
@ -169,7 +162,7 @@ public class StorageHelper {
return;
}
final var group = groupHelper.getOrMigrateGroup(groupMasterKey, 0, null);
final var group = context.getGroupHelper().getOrMigrateGroup(groupMasterKey, 0, null);
if (group.isBlocked() != groupV2Record.isBlocked()) {
group.setBlocked(groupV2Record.isBlocked());
account.getGroupStore().updateGroup(group);
@ -225,11 +218,12 @@ public class StorageHelper {
if (profileKey != null) {
account.setProfileKey(profileKey);
final var avatarPath = accountRecord.getAvatarUrlPath().orNull();
profileHelper.downloadProfileAvatar(account.getSelfRecipientId(), avatarPath, profileKey);
context.getProfileHelper().downloadProfileAvatar(account.getSelfRecipientId(), avatarPath, profileKey);
}
}
profileHelper.setProfile(false,
context.getProfileHelper()
.setProfile(false,
accountRecord.getGivenName().orNull(),
accountRecord.getFamilyName().orNull(),
null,

View file

@ -1,6 +1,5 @@
package org.asamk.signal.manager.helper;
import org.asamk.signal.manager.AvatarStore;
import org.asamk.signal.manager.TrustLevel;
import org.asamk.signal.manager.storage.SignalAccount;
import org.asamk.signal.manager.storage.groups.GroupInfoV1;
@ -40,30 +39,15 @@ public class SyncHelper {
private final static Logger logger = LoggerFactory.getLogger(SyncHelper.class);
private final Context context;
private final SignalAccount account;
private final AttachmentHelper attachmentHelper;
private final SendHelper sendHelper;
private final GroupHelper groupHelper;
private final AvatarStore avatarStore;
private final SignalServiceAddressResolver addressResolver;
public SyncHelper(
final SignalAccount account,
final AttachmentHelper attachmentHelper,
final SendHelper sendHelper,
final GroupHelper groupHelper,
final AvatarStore avatarStore,
final SignalServiceAddressResolver addressResolver
) {
this.account = account;
this.attachmentHelper = attachmentHelper;
this.sendHelper = sendHelper;
this.groupHelper = groupHelper;
this.avatarStore = avatarStore;
this.addressResolver = addressResolver;
public SyncHelper(final Context context) {
this.context = context;
this.account = context.getAccount();
}
public void requestAllSyncData() throws IOException {
public void requestAllSyncData() {
requestSyncGroups();
requestSyncContacts();
requestSyncBlocked();
@ -71,8 +55,9 @@ public class SyncHelper {
requestSyncKeys();
}
public void sendSyncFetchProfileMessage() throws IOException {
sendHelper.sendSyncMessage(SignalServiceSyncMessage.forFetchLatest(SignalServiceSyncMessage.FetchType.LOCAL_PROFILE));
public void sendSyncFetchProfileMessage() {
context.getSendHelper()
.sendSyncMessage(SignalServiceSyncMessage.forFetchLatest(SignalServiceSyncMessage.FetchType.LOCAL_PROFILE));
}
public void sendGroups() throws IOException {
@ -87,9 +72,9 @@ public class SyncHelper {
Optional.fromNullable(groupInfo.name),
groupInfo.getMembers()
.stream()
.map(addressResolver::resolveSignalServiceAddress)
.map(context.getRecipientHelper()::resolveSignalServiceAddress)
.toList(),
groupHelper.createGroupAvatarAttachment(groupInfo.getGroupId()),
context.getGroupHelper().createGroupAvatarAttachment(groupInfo.getGroupId()),
groupInfo.isMember(account.getSelfRecipientId()),
Optional.of(groupInfo.messageExpirationTime),
Optional.fromNullable(groupInfo.color),
@ -108,7 +93,7 @@ public class SyncHelper {
.withLength(groupsFile.length())
.build();
sendHelper.sendSyncMessage(SignalServiceSyncMessage.forGroups(attachmentStream));
context.getSendHelper().sendSyncMessage(SignalServiceSyncMessage.forGroups(attachmentStream));
}
}
} finally {
@ -129,7 +114,7 @@ public class SyncHelper {
for (var contactPair : account.getContactStore().getContacts()) {
final var recipientId = contactPair.first();
final var contact = contactPair.second();
final var address = addressResolver.resolveSignalServiceAddress(recipientId);
final var address = context.getRecipientHelper().resolveSignalServiceAddress(recipientId);
var currentIdentity = account.getIdentityKeyStore().getIdentity(recipientId);
VerifiedMessage verifiedMessage = null;
@ -176,7 +161,8 @@ public class SyncHelper {
.withLength(contactsFile.length())
.build();
sendHelper.sendSyncMessage(SignalServiceSyncMessage.forContacts(new ContactsMessage(attachmentStream,
context.getSendHelper()
.sendSyncMessage(SignalServiceSyncMessage.forContacts(new ContactsMessage(attachmentStream,
true)));
}
}
@ -189,11 +175,11 @@ public class SyncHelper {
}
}
public void sendBlockedList() throws IOException {
public void sendBlockedList() {
var addresses = new ArrayList<SignalServiceAddress>();
for (var record : account.getContactStore().getContacts()) {
if (record.second().isBlocked()) {
addresses.add(addressResolver.resolveSignalServiceAddress(record.first()));
addresses.add(context.getRecipientHelper().resolveSignalServiceAddress(record.first()));
}
}
var groupIds = new ArrayList<byte[]>();
@ -202,7 +188,8 @@ public class SyncHelper {
groupIds.add(record.getGroupId().serialize());
}
}
sendHelper.sendSyncMessage(SignalServiceSyncMessage.forBlocked(new BlockedListMessage(addresses, groupIds)));
context.getSendHelper()
.sendSyncMessage(SignalServiceSyncMessage.forBlocked(new BlockedListMessage(addresses, groupIds)));
}
public void sendVerifiedMessage(
@ -212,21 +199,21 @@ public class SyncHelper {
identityKey,
trustLevel.toVerifiedState(),
System.currentTimeMillis());
sendHelper.sendSyncMessage(SignalServiceSyncMessage.forVerified(verifiedMessage));
context.getSendHelper().sendSyncMessage(SignalServiceSyncMessage.forVerified(verifiedMessage));
}
public void sendKeysMessage() throws IOException {
public void sendKeysMessage() {
var keysMessage = new KeysMessage(Optional.fromNullable(account.getStorageKey()));
sendHelper.sendSyncMessage(SignalServiceSyncMessage.forKeys(keysMessage));
context.getSendHelper().sendSyncMessage(SignalServiceSyncMessage.forKeys(keysMessage));
}
public void sendConfigurationMessage() throws IOException {
public void sendConfigurationMessage() {
final var config = account.getConfigurationStore();
var configurationMessage = new ConfigurationMessage(Optional.fromNullable(config.getReadReceipts()),
Optional.fromNullable(config.getUnidentifiedDeliveryIndicators()),
Optional.fromNullable(config.getTypingIndicators()),
Optional.fromNullable(config.getLinkPreviews()));
sendHelper.sendSyncMessage(SignalServiceSyncMessage.forConfiguration(configurationMessage));
context.getSendHelper().sendSyncMessage(SignalServiceSyncMessage.forConfiguration(configurationMessage));
}
public void handleSyncDeviceContacts(final InputStream input) throws IOException {
@ -282,48 +269,48 @@ public class SyncHelper {
}
}
private void requestSyncGroups() throws IOException {
private void requestSyncGroups() {
var r = SignalServiceProtos.SyncMessage.Request.newBuilder()
.setType(SignalServiceProtos.SyncMessage.Request.Type.GROUPS)
.build();
var message = SignalServiceSyncMessage.forRequest(new RequestMessage(r));
sendHelper.sendSyncMessage(message);
context.getSendHelper().sendSyncMessage(message);
}
private void requestSyncContacts() throws IOException {
private void requestSyncContacts() {
var r = SignalServiceProtos.SyncMessage.Request.newBuilder()
.setType(SignalServiceProtos.SyncMessage.Request.Type.CONTACTS)
.build();
var message = SignalServiceSyncMessage.forRequest(new RequestMessage(r));
sendHelper.sendSyncMessage(message);
context.getSendHelper().sendSyncMessage(message);
}
private void requestSyncBlocked() throws IOException {
private void requestSyncBlocked() {
var r = SignalServiceProtos.SyncMessage.Request.newBuilder()
.setType(SignalServiceProtos.SyncMessage.Request.Type.BLOCKED)
.build();
var message = SignalServiceSyncMessage.forRequest(new RequestMessage(r));
sendHelper.sendSyncMessage(message);
context.getSendHelper().sendSyncMessage(message);
}
private void requestSyncConfiguration() throws IOException {
private void requestSyncConfiguration() {
var r = SignalServiceProtos.SyncMessage.Request.newBuilder()
.setType(SignalServiceProtos.SyncMessage.Request.Type.CONFIGURATION)
.build();
var message = SignalServiceSyncMessage.forRequest(new RequestMessage(r));
sendHelper.sendSyncMessage(message);
context.getSendHelper().sendSyncMessage(message);
}
private void requestSyncKeys() throws IOException {
private void requestSyncKeys() {
var r = SignalServiceProtos.SyncMessage.Request.newBuilder()
.setType(SignalServiceProtos.SyncMessage.Request.Type.KEYS)
.build();
var message = SignalServiceSyncMessage.forRequest(new RequestMessage(r));
sendHelper.sendSyncMessage(message);
context.getSendHelper().sendSyncMessage(message);
}
private Optional<SignalServiceAttachmentStream> createContactAvatarAttachment(SignalServiceAddress address) throws IOException {
final var streamDetails = avatarStore.retrieveContactAvatar(address);
final var streamDetails = context.getAvatarStore().retrieveContactAvatar(address);
if (streamDetails == null) {
return Optional.absent();
}
@ -333,8 +320,9 @@ public class SyncHelper {
private void downloadContactAvatar(SignalServiceAttachment avatar, SignalServiceAddress address) {
try {
avatarStore.storeContactAvatar(address,
outputStream -> attachmentHelper.retrieveAttachment(avatar, outputStream));
context.getAvatarStore()
.storeContactAvatar(address,
outputStream -> context.getAttachmentHelper().retrieveAttachment(avatar, outputStream));
} catch (IOException e) {
logger.warn("Failed to download avatar for contact {}, ignoring: {}", address, e.getMessage());
}

View file

@ -26,22 +26,15 @@ public class UnidentifiedAccessHelper {
private final SignalAccount account;
private final SignalDependencies dependencies;
private final SelfProfileKeyProvider selfProfileKeyProvider;
private final ProfileProvider profileProvider;
private final Context context;
private SenderCertificate privacySenderCertificate;
private SenderCertificate senderCertificate;
public UnidentifiedAccessHelper(
final SignalAccount account,
final SignalDependencies dependencies,
final SelfProfileKeyProvider selfProfileKeyProvider,
final ProfileProvider profileProvider
) {
this.account = account;
this.dependencies = dependencies;
this.selfProfileKeyProvider = selfProfileKeyProvider;
this.profileProvider = profileProvider;
public UnidentifiedAccessHelper(final Context context) {
this.account = context.getAccount();
this.dependencies = context.getDependencies();
this.context = context;
}
public List<Optional<UnidentifiedAccessPair>> getAccessFor(List<RecipientId> recipients) {
@ -145,18 +138,18 @@ public class UnidentifiedAccessHelper {
private byte[] getSelfUnidentifiedAccessKey(boolean noRefresh) {
var selfProfile = noRefresh
? account.getProfileStore().getProfile(account.getSelfRecipientId())
: profileProvider.getProfile(account.getSelfRecipientId());
: context.getProfileHelper().getRecipientProfile(account.getSelfRecipientId());
if (selfProfile != null
&& selfProfile.getUnidentifiedAccessMode() == Profile.UnidentifiedAccessMode.UNRESTRICTED) {
return createUnrestrictedUnidentifiedAccess();
}
return UnidentifiedAccess.deriveAccessKeyFrom(selfProfileKeyProvider.getProfileKey());
return UnidentifiedAccess.deriveAccessKeyFrom(account.getProfileKey());
}
private byte[] getTargetUnidentifiedAccessKey(RecipientId recipientId, boolean noRefresh) {
var targetProfile = noRefresh
? account.getProfileStore().getProfile(recipientId)
: profileProvider.getProfile(recipientId);
: context.getProfileHelper().getRecipientProfile(recipientId);
if (targetProfile == null) {
return null;
}

View file

@ -1,10 +0,0 @@
package org.asamk.signal.manager.helper;
import org.asamk.signal.manager.storage.recipients.RecipientId;
import org.whispersystems.libsignal.util.guava.Optional;
import org.whispersystems.signalservice.api.crypto.UnidentifiedAccessPair;
public interface UnidentifiedAccessProvider {
Optional<UnidentifiedAccessPair> getAccessFor(RecipientId recipientId, boolean noRefresh);
}

View file

@ -1,82 +0,0 @@
package org.asamk.signal.manager.jobs;
import org.asamk.signal.manager.SignalDependencies;
import org.asamk.signal.manager.StickerPackStore;
import org.asamk.signal.manager.helper.GroupHelper;
import org.asamk.signal.manager.helper.PreKeyHelper;
import org.asamk.signal.manager.helper.ProfileHelper;
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.storage.SignalAccount;
public class Context {
private final SignalAccount account;
private final SignalDependencies dependencies;
private final StickerPackStore stickerPackStore;
private final SendHelper sendHelper;
private final GroupHelper groupHelper;
private final SyncHelper syncHelper;
private final ProfileHelper profileHelper;
private final StorageHelper storageHelper;
private final PreKeyHelper preKeyHelper;
public Context(
final SignalAccount account,
final SignalDependencies dependencies,
final StickerPackStore stickerPackStore,
final SendHelper sendHelper,
final GroupHelper groupHelper,
final SyncHelper syncHelper,
final ProfileHelper profileHelper,
final StorageHelper storageHelper,
final PreKeyHelper preKeyHelper
) {
this.account = account;
this.dependencies = dependencies;
this.stickerPackStore = stickerPackStore;
this.sendHelper = sendHelper;
this.groupHelper = groupHelper;
this.syncHelper = syncHelper;
this.profileHelper = profileHelper;
this.storageHelper = storageHelper;
this.preKeyHelper = preKeyHelper;
}
public SignalAccount getAccount() {
return account;
}
public SignalDependencies getDependencies() {
return dependencies;
}
public StickerPackStore getStickerPackStore() {
return stickerPackStore;
}
public SendHelper getSendHelper() {
return sendHelper;
}
public GroupHelper getGroupHelper() {
return groupHelper;
}
public SyncHelper getSyncHelper() {
return syncHelper;
}
public ProfileHelper getProfileHelper() {
return profileHelper;
}
public StorageHelper getStorageHelper() {
return storageHelper;
}
public PreKeyHelper getPreKeyHelper() {
return preKeyHelper;
}
}

View file

@ -1,5 +1,7 @@
package org.asamk.signal.manager.jobs;
import org.asamk.signal.manager.helper.Context;
public interface Job {
void run(Context context);

View file

@ -1,6 +1,7 @@
package org.asamk.signal.manager.jobs;
import org.asamk.signal.manager.JsonStickerPack;
import org.asamk.signal.manager.helper.Context;
import org.asamk.signal.manager.storage.stickers.StickerPackId;
import org.asamk.signal.manager.util.IOUtils;
import org.slf4j.Logger;