]> nmode's Git Repositories - signal-cli/blob - lib/src/main/java/org/asamk/signal/manager/helper/IncomingMessageHandler.java
Extract configurationStore variable
[signal-cli] / lib / src / main / java / org / asamk / signal / manager / helper / IncomingMessageHandler.java
1 package org.asamk.signal.manager.helper;
2
3 import org.asamk.signal.manager.JobExecutor;
4 import org.asamk.signal.manager.Manager;
5 import org.asamk.signal.manager.SignalDependencies;
6 import org.asamk.signal.manager.TrustLevel;
7 import org.asamk.signal.manager.UntrustedIdentityException;
8 import org.asamk.signal.manager.actions.HandleAction;
9 import org.asamk.signal.manager.actions.RefreshPreKeysAction;
10 import org.asamk.signal.manager.actions.RenewSessionAction;
11 import org.asamk.signal.manager.actions.RetrieveProfileAction;
12 import org.asamk.signal.manager.actions.RetrieveStorageDataAction;
13 import org.asamk.signal.manager.actions.SendGroupInfoAction;
14 import org.asamk.signal.manager.actions.SendGroupInfoRequestAction;
15 import org.asamk.signal.manager.actions.SendReceiptAction;
16 import org.asamk.signal.manager.actions.SendRetryMessageRequestAction;
17 import org.asamk.signal.manager.actions.SendSyncBlockedListAction;
18 import org.asamk.signal.manager.actions.SendSyncConfigurationAction;
19 import org.asamk.signal.manager.actions.SendSyncContactsAction;
20 import org.asamk.signal.manager.actions.SendSyncGroupsAction;
21 import org.asamk.signal.manager.actions.SendSyncKeysAction;
22 import org.asamk.signal.manager.groups.GroupId;
23 import org.asamk.signal.manager.groups.GroupNotFoundException;
24 import org.asamk.signal.manager.groups.GroupUtils;
25 import org.asamk.signal.manager.jobs.RetrieveStickerPackJob;
26 import org.asamk.signal.manager.storage.SignalAccount;
27 import org.asamk.signal.manager.storage.groups.GroupInfoV1;
28 import org.asamk.signal.manager.storage.recipients.Profile;
29 import org.asamk.signal.manager.storage.recipients.RecipientId;
30 import org.asamk.signal.manager.storage.recipients.RecipientResolver;
31 import org.asamk.signal.manager.storage.stickers.Sticker;
32 import org.asamk.signal.manager.storage.stickers.StickerPackId;
33 import org.signal.libsignal.metadata.ProtocolInvalidKeyException;
34 import org.signal.libsignal.metadata.ProtocolInvalidKeyIdException;
35 import org.signal.libsignal.metadata.ProtocolInvalidMessageException;
36 import org.signal.libsignal.metadata.ProtocolNoSessionException;
37 import org.signal.libsignal.metadata.ProtocolUntrustedIdentityException;
38 import org.signal.libsignal.metadata.SelfSendException;
39 import org.signal.zkgroup.InvalidInputException;
40 import org.signal.zkgroup.profiles.ProfileKey;
41 import org.slf4j.Logger;
42 import org.slf4j.LoggerFactory;
43 import org.whispersystems.libsignal.SignalProtocolAddress;
44 import org.whispersystems.libsignal.util.Pair;
45 import org.whispersystems.signalservice.api.messages.SignalServiceContent;
46 import org.whispersystems.signalservice.api.messages.SignalServiceDataMessage;
47 import org.whispersystems.signalservice.api.messages.SignalServiceEnvelope;
48 import org.whispersystems.signalservice.api.messages.SignalServiceGroup;
49 import org.whispersystems.signalservice.api.messages.multidevice.SignalServiceSyncMessage;
50 import org.whispersystems.signalservice.api.messages.multidevice.StickerPackOperationMessage;
51 import org.whispersystems.signalservice.api.push.SignalServiceAddress;
52
53 import java.util.ArrayList;
54 import java.util.List;
55 import java.util.stream.Collectors;
56
57 public final class IncomingMessageHandler {
58
59 private final static Logger logger = LoggerFactory.getLogger(IncomingMessageHandler.class);
60
61 private final SignalAccount account;
62 private final SignalDependencies dependencies;
63 private final RecipientResolver recipientResolver;
64 private final SignalServiceAddressResolver addressResolver;
65 private final GroupHelper groupHelper;
66 private final ContactHelper contactHelper;
67 private final AttachmentHelper attachmentHelper;
68 private final SyncHelper syncHelper;
69 private final ProfileProvider profileProvider;
70 private final JobExecutor jobExecutor;
71
72 public IncomingMessageHandler(
73 final SignalAccount account,
74 final SignalDependencies dependencies,
75 final RecipientResolver recipientResolver,
76 final SignalServiceAddressResolver addressResolver,
77 final GroupHelper groupHelper,
78 final ContactHelper contactHelper,
79 final AttachmentHelper attachmentHelper,
80 final SyncHelper syncHelper,
81 final ProfileProvider profileProvider,
82 final JobExecutor jobExecutor
83 ) {
84 this.account = account;
85 this.dependencies = dependencies;
86 this.recipientResolver = recipientResolver;
87 this.addressResolver = addressResolver;
88 this.groupHelper = groupHelper;
89 this.contactHelper = contactHelper;
90 this.attachmentHelper = attachmentHelper;
91 this.syncHelper = syncHelper;
92 this.profileProvider = profileProvider;
93 this.jobExecutor = jobExecutor;
94 }
95
96 public Pair<List<HandleAction>, Exception> handleRetryEnvelope(
97 final SignalServiceEnvelope envelope,
98 final boolean ignoreAttachments,
99 final Manager.ReceiveMessageHandler handler
100 ) {
101 final List<HandleAction> actions = new ArrayList<>();
102 if (envelope.isPreKeySignalMessage()) {
103 actions.add(RefreshPreKeysAction.create());
104 }
105
106 SignalServiceContent content = null;
107 if (!envelope.isReceipt()) {
108 try {
109 content = dependencies.getCipher().decrypt(envelope);
110 } catch (ProtocolUntrustedIdentityException e) {
111 final var recipientId = account.getRecipientStore().resolveRecipient(e.getSender());
112 final var exception = new UntrustedIdentityException(addressResolver.resolveSignalServiceAddress(
113 recipientId), e.getSenderDevice());
114 return new Pair<>(List.of(), exception);
115 } catch (Exception e) {
116 return new Pair<>(List.of(), e);
117 }
118 }
119 actions.addAll(checkAndHandleMessage(envelope, content, ignoreAttachments, handler, null));
120 return new Pair<>(actions, null);
121 }
122
123 public Pair<List<HandleAction>, Exception> handleEnvelope(
124 final SignalServiceEnvelope envelope,
125 final boolean ignoreAttachments,
126 final Manager.ReceiveMessageHandler handler
127 ) {
128 final var actions = new ArrayList<HandleAction>();
129 if (envelope.hasSourceUuid()) {
130 // Store uuid if we don't have it already
131 // address/uuid in envelope is sent by server
132 account.getRecipientStore().resolveRecipientTrusted(envelope.getSourceAddress());
133 }
134 SignalServiceContent content = null;
135 Exception exception = null;
136 if (!envelope.isReceipt()) {
137 try {
138 content = dependencies.getCipher().decrypt(envelope);
139 } catch (ProtocolUntrustedIdentityException e) {
140 final var recipientId = account.getRecipientStore().resolveRecipient(e.getSender());
141 actions.add(new RetrieveProfileAction(recipientId));
142 exception = new UntrustedIdentityException(addressResolver.resolveSignalServiceAddress(recipientId),
143 e.getSenderDevice());
144 } catch (ProtocolInvalidKeyIdException | ProtocolInvalidKeyException | ProtocolNoSessionException | ProtocolInvalidMessageException e) {
145 final var sender = account.getRecipientStore().resolveRecipient(e.getSender());
146 final var senderProfile = profileProvider.getProfile(sender);
147 final var selfProfile = profileProvider.getProfile(account.getSelfRecipientId());
148 if (e.getSenderDevice() != account.getDeviceId()
149 && senderProfile != null
150 && senderProfile.getCapabilities().contains(Profile.Capability.senderKey)
151 && selfProfile != null
152 && selfProfile.getCapabilities().contains(Profile.Capability.senderKey)) {
153 logger.debug("Received invalid message, requesting message resend.");
154 actions.add(new SendRetryMessageRequestAction(sender, e, envelope));
155 } else {
156 logger.debug("Received invalid message, queuing renew session action.");
157 actions.add(new RenewSessionAction(sender));
158 }
159 exception = e;
160 } catch (SelfSendException e) {
161 logger.debug("Dropping unidentified message from self.");
162 return new Pair<>(List.of(), null);
163 } catch (Exception e) {
164 exception = e;
165 }
166 }
167
168 actions.addAll(checkAndHandleMessage(envelope, content, ignoreAttachments, handler, exception));
169 return new Pair<>(actions, exception);
170 }
171
172 private List<HandleAction> checkAndHandleMessage(
173 final SignalServiceEnvelope envelope,
174 final SignalServiceContent content,
175 final boolean ignoreAttachments,
176 final Manager.ReceiveMessageHandler handler,
177 final Exception exception
178 ) {
179 if (!envelope.hasSourceUuid() && content != null) {
180 // Store uuid if we don't have it already
181 // address/uuid is validated by unidentified sender certificate
182 account.getRecipientStore().resolveRecipientTrusted(content.getSender());
183 }
184 if (isMessageBlocked(envelope, content)) {
185 logger.info("Ignoring a message from blocked user/group: {}", envelope.getTimestamp());
186 return List.of();
187 } else if (isNotAllowedToSendToGroup(envelope, content)) {
188 logger.info("Ignoring a group message from an unauthorized sender (no member or admin): {} {}",
189 (envelope.hasSourceUuid() ? envelope.getSourceAddress() : content.getSender()).getIdentifier(),
190 envelope.getTimestamp());
191 return List.of();
192 } else {
193 List<HandleAction> actions;
194 if (content != null) {
195 actions = handleMessage(envelope, content, ignoreAttachments);
196 } else {
197 actions = List.of();
198 }
199 handler.handleMessage(envelope, content, exception);
200 return actions;
201 }
202 }
203
204 public List<HandleAction> handleMessage(
205 SignalServiceEnvelope envelope, SignalServiceContent content, boolean ignoreAttachments
206 ) {
207 var actions = new ArrayList<HandleAction>();
208 final RecipientId sender;
209 final int senderDeviceId;
210 if (!envelope.isUnidentifiedSender() && envelope.hasSourceUuid()) {
211 sender = recipientResolver.resolveRecipient(envelope.getSourceAddress());
212 senderDeviceId = envelope.getSourceDevice();
213 } else {
214 sender = recipientResolver.resolveRecipient(content.getSender());
215 senderDeviceId = content.getSenderDevice();
216 }
217
218 if (content.getSenderKeyDistributionMessage().isPresent()) {
219 final var message = content.getSenderKeyDistributionMessage().get();
220 final var protocolAddress = new SignalProtocolAddress(addressResolver.resolveSignalServiceAddress(sender)
221 .getIdentifier(), senderDeviceId);
222 dependencies.getMessageSender().processSenderKeyDistributionMessage(protocolAddress, message);
223 }
224
225 if (content.getDataMessage().isPresent()) {
226 var message = content.getDataMessage().get();
227
228 if (content.isNeedsReceipt()) {
229 actions.add(new SendReceiptAction(sender, message.getTimestamp()));
230 }
231
232 actions.addAll(handleSignalServiceDataMessage(message,
233 false,
234 sender,
235 account.getSelfRecipientId(),
236 ignoreAttachments));
237 }
238
239 if (content.getSyncMessage().isPresent()) {
240 var syncMessage = content.getSyncMessage().get();
241 actions.addAll(handleSyncMessage(syncMessage, sender, ignoreAttachments));
242 }
243
244 return actions;
245 }
246
247 private List<HandleAction> handleSyncMessage(
248 final SignalServiceSyncMessage syncMessage, final RecipientId sender, final boolean ignoreAttachments
249 ) {
250 var actions = new ArrayList<HandleAction>();
251 account.setMultiDevice(true);
252 if (syncMessage.getSent().isPresent()) {
253 var message = syncMessage.getSent().get();
254 final var destination = message.getDestination().orNull();
255 actions.addAll(handleSignalServiceDataMessage(message.getMessage(),
256 true,
257 sender,
258 destination == null ? null : recipientResolver.resolveRecipient(destination),
259 ignoreAttachments));
260 }
261 if (syncMessage.getRequest().isPresent() && account.isMasterDevice()) {
262 var rm = syncMessage.getRequest().get();
263 if (rm.isContactsRequest()) {
264 actions.add(SendSyncContactsAction.create());
265 }
266 if (rm.isGroupsRequest()) {
267 actions.add(SendSyncGroupsAction.create());
268 }
269 if (rm.isBlockedListRequest()) {
270 actions.add(SendSyncBlockedListAction.create());
271 }
272 if (rm.isKeysRequest()) {
273 actions.add(SendSyncKeysAction.create());
274 }
275 if (rm.isConfigurationRequest()) {
276 actions.add(SendSyncConfigurationAction.create());
277 }
278 }
279 if (syncMessage.getGroups().isPresent()) {
280 logger.warn("Received a group v1 sync message, that can't be handled anymore, ignoring.");
281 }
282 if (syncMessage.getBlockedList().isPresent()) {
283 final var blockedListMessage = syncMessage.getBlockedList().get();
284 for (var address : blockedListMessage.getAddresses()) {
285 contactHelper.setContactBlocked(recipientResolver.resolveRecipient(address), true);
286 }
287 for (var groupId : blockedListMessage.getGroupIds()
288 .stream()
289 .map(GroupId::unknownVersion)
290 .collect(Collectors.toSet())) {
291 try {
292 groupHelper.setGroupBlocked(groupId, true);
293 } catch (GroupNotFoundException e) {
294 logger.warn("BlockedListMessage contained groupID that was not found in GroupStore: {}",
295 groupId.toBase64());
296 }
297 }
298 }
299 if (syncMessage.getContacts().isPresent()) {
300 try {
301 final var contactsMessage = syncMessage.getContacts().get();
302 attachmentHelper.retrieveAttachment(contactsMessage.getContactsStream(),
303 syncHelper::handleSyncDeviceContacts);
304 } catch (Exception e) {
305 logger.warn("Failed to handle received sync contacts, ignoring: {}", e.getMessage());
306 }
307 }
308 if (syncMessage.getVerified().isPresent()) {
309 final var verifiedMessage = syncMessage.getVerified().get();
310 account.getIdentityKeyStore()
311 .setIdentityTrustLevel(account.getRecipientStore()
312 .resolveRecipientTrusted(verifiedMessage.getDestination()),
313 verifiedMessage.getIdentityKey(),
314 TrustLevel.fromVerifiedState(verifiedMessage.getVerified()));
315 }
316 if (syncMessage.getStickerPackOperations().isPresent()) {
317 final var stickerPackOperationMessages = syncMessage.getStickerPackOperations().get();
318 for (var m : stickerPackOperationMessages) {
319 if (!m.getPackId().isPresent()) {
320 continue;
321 }
322 final var stickerPackId = StickerPackId.deserialize(m.getPackId().get());
323 final var installed = !m.getType().isPresent()
324 || m.getType().get() == StickerPackOperationMessage.Type.INSTALL;
325
326 var sticker = account.getStickerStore().getSticker(stickerPackId);
327 if (m.getPackKey().isPresent()) {
328 if (sticker == null) {
329 sticker = new Sticker(stickerPackId, m.getPackKey().get());
330 }
331 if (installed) {
332 jobExecutor.enqueueJob(new RetrieveStickerPackJob(stickerPackId, m.getPackKey().get()));
333 }
334 }
335
336 if (sticker != null) {
337 sticker.setInstalled(installed);
338 account.getStickerStore().updateSticker(sticker);
339 }
340 }
341 }
342 if (syncMessage.getFetchType().isPresent()) {
343 switch (syncMessage.getFetchType().get()) {
344 case LOCAL_PROFILE:
345 actions.add(new RetrieveProfileAction(account.getSelfRecipientId()));
346 case STORAGE_MANIFEST:
347 actions.add(RetrieveStorageDataAction.create());
348 }
349 }
350 if (syncMessage.getKeys().isPresent()) {
351 final var keysMessage = syncMessage.getKeys().get();
352 if (keysMessage.getStorageService().isPresent()) {
353 final var storageKey = keysMessage.getStorageService().get();
354 account.setStorageKey(storageKey);
355 actions.add(RetrieveStorageDataAction.create());
356 }
357 }
358 if (syncMessage.getConfiguration().isPresent()) {
359 final var configurationMessage = syncMessage.getConfiguration().get();
360 final var configurationStore = account.getConfigurationStore();
361 configurationStore.setReadReceipts(configurationMessage.getReadReceipts().orNull());
362 configurationStore.setLinkPreviews(configurationMessage.getLinkPreviews().orNull());
363 configurationStore.setTypingIndicators(configurationMessage.getTypingIndicators().orNull());
364 configurationStore.setUnidentifiedDeliveryIndicators(configurationMessage.getUnidentifiedDeliveryIndicators()
365 .orNull());
366 }
367 return actions;
368 }
369
370 private boolean isMessageBlocked(SignalServiceEnvelope envelope, SignalServiceContent content) {
371 SignalServiceAddress source;
372 if (!envelope.isUnidentifiedSender() && envelope.hasSourceUuid()) {
373 source = envelope.getSourceAddress();
374 } else if (content != null) {
375 source = content.getSender();
376 } else {
377 return false;
378 }
379 final var recipientId = recipientResolver.resolveRecipient(source);
380 if (contactHelper.isContactBlocked(recipientId)) {
381 return true;
382 }
383
384 if (content != null && content.getDataMessage().isPresent()) {
385 var message = content.getDataMessage().get();
386 if (message.getGroupContext().isPresent()) {
387 var groupId = GroupUtils.getGroupId(message.getGroupContext().get());
388 return groupHelper.isGroupBlocked(groupId);
389 }
390 }
391
392 return false;
393 }
394
395 private boolean isNotAllowedToSendToGroup(SignalServiceEnvelope envelope, SignalServiceContent content) {
396 SignalServiceAddress source;
397 if (!envelope.isUnidentifiedSender() && envelope.hasSourceUuid()) {
398 source = envelope.getSourceAddress();
399 } else if (content != null) {
400 source = content.getSender();
401 } else {
402 return false;
403 }
404
405 if (content == null || !content.getDataMessage().isPresent()) {
406 return false;
407 }
408
409 var message = content.getDataMessage().get();
410 if (!message.getGroupContext().isPresent()) {
411 return false;
412 }
413
414 if (message.getGroupContext().get().getGroupV1().isPresent()) {
415 var groupInfo = message.getGroupContext().get().getGroupV1().get();
416 if (groupInfo.getType() == SignalServiceGroup.Type.QUIT) {
417 return false;
418 }
419 }
420
421 var groupId = GroupUtils.getGroupId(message.getGroupContext().get());
422 var group = groupHelper.getGroup(groupId);
423 if (group == null) {
424 return false;
425 }
426
427 final var recipientId = recipientResolver.resolveRecipient(source);
428 if (!group.isMember(recipientId) && !(group.isPendingMember(recipientId) && message.isGroupV2Update())) {
429 return true;
430 }
431
432 if (group.isAnnouncementGroup() && !group.isAdmin(recipientId)) {
433 return message.getBody().isPresent()
434 || message.getAttachments().isPresent()
435 || message.getQuote()
436 .isPresent()
437 || message.getPreviews().isPresent()
438 || message.getMentions().isPresent()
439 || message.getSticker().isPresent();
440 }
441 return false;
442 }
443
444 private List<HandleAction> handleSignalServiceDataMessage(
445 SignalServiceDataMessage message,
446 boolean isSync,
447 RecipientId source,
448 RecipientId destination,
449 boolean ignoreAttachments
450 ) {
451 var actions = new ArrayList<HandleAction>();
452 if (message.getGroupContext().isPresent()) {
453 if (message.getGroupContext().get().getGroupV1().isPresent()) {
454 var groupInfo = message.getGroupContext().get().getGroupV1().get();
455 var groupId = GroupId.v1(groupInfo.getGroupId());
456 var group = groupHelper.getGroup(groupId);
457 if (group == null || group instanceof GroupInfoV1) {
458 var groupV1 = (GroupInfoV1) group;
459 switch (groupInfo.getType()) {
460 case UPDATE: {
461 if (groupV1 == null) {
462 groupV1 = new GroupInfoV1(groupId);
463 }
464
465 if (groupInfo.getAvatar().isPresent()) {
466 var avatar = groupInfo.getAvatar().get();
467 groupHelper.downloadGroupAvatar(groupV1.getGroupId(), avatar);
468 }
469
470 if (groupInfo.getName().isPresent()) {
471 groupV1.name = groupInfo.getName().get();
472 }
473
474 if (groupInfo.getMembers().isPresent()) {
475 groupV1.addMembers(groupInfo.getMembers()
476 .get()
477 .stream()
478 .map(recipientResolver::resolveRecipient)
479 .collect(Collectors.toSet()));
480 }
481
482 account.getGroupStore().updateGroup(groupV1);
483 break;
484 }
485 case DELIVER:
486 if (groupV1 == null && !isSync) {
487 actions.add(new SendGroupInfoRequestAction(source, groupId));
488 }
489 break;
490 case QUIT: {
491 if (groupV1 != null) {
492 groupV1.removeMember(source);
493 account.getGroupStore().updateGroup(groupV1);
494 }
495 break;
496 }
497 case REQUEST_INFO:
498 if (groupV1 != null && !isSync) {
499 actions.add(new SendGroupInfoAction(source, groupV1.getGroupId()));
500 }
501 break;
502 }
503 } else {
504 // Received a group v1 message for a v2 group
505 }
506 }
507 if (message.getGroupContext().get().getGroupV2().isPresent()) {
508 final var groupContext = message.getGroupContext().get().getGroupV2().get();
509 final var groupMasterKey = groupContext.getMasterKey();
510
511 groupHelper.getOrMigrateGroup(groupMasterKey,
512 groupContext.getRevision(),
513 groupContext.hasSignedGroupChange() ? groupContext.getSignedGroupChange() : null);
514 }
515 }
516
517 final var conversationPartnerAddress = isSync ? destination : source;
518 if (conversationPartnerAddress != null && message.isEndSession()) {
519 account.getSessionStore().deleteAllSessions(conversationPartnerAddress);
520 }
521 if (message.isExpirationUpdate() || message.getBody().isPresent()) {
522 if (message.getGroupContext().isPresent()) {
523 if (message.getGroupContext().get().getGroupV1().isPresent()) {
524 var groupInfo = message.getGroupContext().get().getGroupV1().get();
525 var group = account.getGroupStore().getOrCreateGroupV1(GroupId.v1(groupInfo.getGroupId()));
526 if (group != null) {
527 if (group.messageExpirationTime != message.getExpiresInSeconds()) {
528 group.messageExpirationTime = message.getExpiresInSeconds();
529 account.getGroupStore().updateGroup(group);
530 }
531 }
532 } else if (message.getGroupContext().get().getGroupV2().isPresent()) {
533 // disappearing message timer already stored in the DecryptedGroup
534 }
535 } else if (conversationPartnerAddress != null) {
536 contactHelper.setExpirationTimer(conversationPartnerAddress, message.getExpiresInSeconds());
537 }
538 }
539 if (!ignoreAttachments) {
540 if (message.getAttachments().isPresent()) {
541 for (var attachment : message.getAttachments().get()) {
542 attachmentHelper.downloadAttachment(attachment);
543 }
544 }
545 if (message.getSharedContacts().isPresent()) {
546 for (var contact : message.getSharedContacts().get()) {
547 if (contact.getAvatar().isPresent()) {
548 attachmentHelper.downloadAttachment(contact.getAvatar().get().getAttachment());
549 }
550 }
551 }
552 if (message.getPreviews().isPresent()) {
553 final var previews = message.getPreviews().get();
554 for (var preview : previews) {
555 if (preview.getImage().isPresent()) {
556 attachmentHelper.downloadAttachment(preview.getImage().get());
557 }
558 }
559 }
560 if (message.getQuote().isPresent()) {
561 final var quote = message.getQuote().get();
562
563 for (var quotedAttachment : quote.getAttachments()) {
564 final var thumbnail = quotedAttachment.getThumbnail();
565 if (thumbnail != null) {
566 attachmentHelper.downloadAttachment(thumbnail);
567 }
568 }
569 }
570 }
571 if (message.getProfileKey().isPresent() && message.getProfileKey().get().length == 32) {
572 final ProfileKey profileKey;
573 try {
574 profileKey = new ProfileKey(message.getProfileKey().get());
575 } catch (InvalidInputException e) {
576 throw new AssertionError(e);
577 }
578 if (account.getSelfRecipientId().equals(source)) {
579 this.account.setProfileKey(profileKey);
580 }
581 this.account.getProfileStore().storeProfileKey(source, profileKey);
582 }
583 if (message.getSticker().isPresent()) {
584 final var messageSticker = message.getSticker().get();
585 final var stickerPackId = StickerPackId.deserialize(messageSticker.getPackId());
586 var sticker = account.getStickerStore().getSticker(stickerPackId);
587 if (sticker == null) {
588 sticker = new Sticker(stickerPackId, messageSticker.getPackKey());
589 account.getStickerStore().updateSticker(sticker);
590 }
591 jobExecutor.enqueueJob(new RetrieveStickerPackJob(stickerPackId, messageSticker.getPackKey()));
592 }
593 return actions;
594 }
595 }