]> nmode's Git Repositories - signal-cli/blob - lib/src/main/java/org/asamk/signal/manager/util/MessageCacheUtils.java
Fix NoSuchElementException in json serialization for messages from an untrusted identity
[signal-cli] / lib / src / main / java / org / asamk / signal / manager / util / MessageCacheUtils.java
1 package org.asamk.signal.manager.util;
2
3 import org.whispersystems.libsignal.util.guava.Optional;
4 import org.whispersystems.signalservice.api.messages.SignalServiceEnvelope;
5 import org.whispersystems.signalservice.api.push.ACI;
6 import org.whispersystems.signalservice.api.push.SignalServiceAddress;
7
8 import java.io.DataInputStream;
9 import java.io.DataOutputStream;
10 import java.io.File;
11 import java.io.FileInputStream;
12 import java.io.FileOutputStream;
13 import java.io.IOException;
14
15 public class MessageCacheUtils {
16
17 public static SignalServiceEnvelope loadEnvelope(File file) throws IOException {
18 try (var f = new FileInputStream(file)) {
19 var in = new DataInputStream(f);
20 var version = in.readInt();
21 if (version > 4) {
22 return null;
23 }
24 var type = in.readInt();
25 var source = in.readUTF();
26 ACI sourceAci = null;
27 if (version >= 3) {
28 sourceAci = ACI.parseOrNull(in.readUTF());
29 }
30 var sourceDevice = in.readInt();
31 if (version == 1) {
32 // read legacy relay field
33 in.readUTF();
34 }
35 var timestamp = in.readLong();
36 byte[] content = null;
37 var contentLen = in.readInt();
38 if (contentLen > 0) {
39 content = new byte[contentLen];
40 in.readFully(content);
41 }
42 byte[] legacyMessage = null;
43 var legacyMessageLen = in.readInt();
44 if (legacyMessageLen > 0) {
45 legacyMessage = new byte[legacyMessageLen];
46 in.readFully(legacyMessage);
47 }
48 long serverReceivedTimestamp = 0;
49 String uuid = null;
50 if (version >= 2) {
51 serverReceivedTimestamp = in.readLong();
52 uuid = in.readUTF();
53 if ("".equals(uuid)) {
54 uuid = null;
55 }
56 }
57 long serverDeliveredTimestamp = 0;
58 if (version >= 4) {
59 serverDeliveredTimestamp = in.readLong();
60 }
61 Optional<SignalServiceAddress> addressOptional = sourceAci == null
62 ? Optional.absent()
63 : Optional.of(new SignalServiceAddress(sourceAci, source));
64 return new SignalServiceEnvelope(type,
65 addressOptional,
66 sourceDevice,
67 timestamp,
68 legacyMessage,
69 content,
70 serverReceivedTimestamp,
71 serverDeliveredTimestamp,
72 uuid);
73 }
74 }
75
76 public static void storeEnvelope(SignalServiceEnvelope envelope, File file) throws IOException {
77 try (var f = new FileOutputStream(file)) {
78 try (var out = new DataOutputStream(f)) {
79 out.writeInt(4); // version
80 out.writeInt(envelope.getType());
81 out.writeUTF(envelope.getSourceE164().isPresent() ? envelope.getSourceE164().get() : "");
82 out.writeUTF(envelope.getSourceUuid().isPresent() ? envelope.getSourceUuid().get() : "");
83 out.writeInt(envelope.getSourceDevice());
84 out.writeLong(envelope.getTimestamp());
85 if (envelope.hasContent()) {
86 out.writeInt(envelope.getContent().length);
87 out.write(envelope.getContent());
88 } else {
89 out.writeInt(0);
90 }
91 if (envelope.hasLegacyMessage()) {
92 out.writeInt(envelope.getLegacyMessage().length);
93 out.write(envelope.getLegacyMessage());
94 } else {
95 out.writeInt(0);
96 }
97 out.writeLong(envelope.getServerReceivedTimestamp());
98 var uuid = envelope.getServerGuid();
99 out.writeUTF(uuid == null ? "" : uuid);
100 out.writeLong(envelope.getServerDeliveredTimestamp());
101 }
102 }
103 }
104 }