]> nmode's Git Repositories - signal-cli/blob - lib/src/main/java/org/asamk/signal/manager/storage/prekeys/SignedPreKeyStore.java
575e9256b7221af20a1d602a843301fb35d9c761
[signal-cli] / lib / src / main / java / org / asamk / signal / manager / storage / prekeys / SignedPreKeyStore.java
1 package org.asamk.signal.manager.storage.prekeys;
2
3 import org.asamk.signal.manager.util.IOUtils;
4 import org.signal.libsignal.protocol.InvalidKeyIdException;
5 import org.signal.libsignal.protocol.InvalidMessageException;
6 import org.signal.libsignal.protocol.state.SignedPreKeyRecord;
7 import org.slf4j.Logger;
8 import org.slf4j.LoggerFactory;
9
10 import java.io.File;
11 import java.io.FileInputStream;
12 import java.io.FileOutputStream;
13 import java.io.IOException;
14 import java.nio.file.Files;
15 import java.util.Arrays;
16 import java.util.List;
17 import java.util.regex.Pattern;
18
19 public class SignedPreKeyStore implements org.signal.libsignal.protocol.state.SignedPreKeyStore {
20
21 private final static Logger logger = LoggerFactory.getLogger(SignedPreKeyStore.class);
22
23 private final File signedPreKeysPath;
24
25 public SignedPreKeyStore(final File signedPreKeysPath) {
26 this.signedPreKeysPath = signedPreKeysPath;
27 }
28
29 @Override
30 public SignedPreKeyRecord loadSignedPreKey(int signedPreKeyId) throws InvalidKeyIdException {
31 final var file = getSignedPreKeyFile(signedPreKeyId);
32
33 if (!file.exists()) {
34 throw new InvalidKeyIdException("No such signed pre key record!");
35 }
36 return loadSignedPreKeyRecord(file);
37 }
38
39 final Pattern signedPreKeyFileNamePattern = Pattern.compile("([0-9]+)");
40
41 @Override
42 public List<SignedPreKeyRecord> loadSignedPreKeys() {
43 final var files = signedPreKeysPath.listFiles();
44 if (files == null) {
45 return List.of();
46 }
47 return Arrays.stream(files)
48 .filter(f -> signedPreKeyFileNamePattern.matcher(f.getName()).matches())
49 .map(this::loadSignedPreKeyRecord)
50 .toList();
51 }
52
53 @Override
54 public void storeSignedPreKey(int signedPreKeyId, SignedPreKeyRecord record) {
55 final var file = getSignedPreKeyFile(signedPreKeyId);
56 try {
57 try (var outputStream = new FileOutputStream(file)) {
58 outputStream.write(record.serialize());
59 }
60 } catch (IOException e) {
61 logger.warn("Failed to store signed pre key, trying to delete file and retry: {}", e.getMessage());
62 try {
63 Files.delete(file.toPath());
64 try (var outputStream = new FileOutputStream(file)) {
65 outputStream.write(record.serialize());
66 }
67 } catch (IOException e2) {
68 logger.error("Failed to store signed pre key file {}: {}", file, e2.getMessage());
69 }
70 }
71 }
72
73 @Override
74 public boolean containsSignedPreKey(int signedPreKeyId) {
75 final var file = getSignedPreKeyFile(signedPreKeyId);
76
77 return file.exists();
78 }
79
80 @Override
81 public void removeSignedPreKey(int signedPreKeyId) {
82 final var file = getSignedPreKeyFile(signedPreKeyId);
83
84 if (!file.exists()) {
85 return;
86 }
87 try {
88 Files.delete(file.toPath());
89 } catch (IOException e) {
90 logger.error("Failed to delete signed pre key file {}: {}", file, e.getMessage());
91 }
92 }
93
94 public void removeAllSignedPreKeys() {
95 final var files = signedPreKeysPath.listFiles();
96 if (files == null) {
97 return;
98 }
99
100 for (var file : files) {
101 try {
102 Files.delete(file.toPath());
103 } catch (IOException e) {
104 logger.error("Failed to delete signed pre key file {}: {}", file, e.getMessage());
105 }
106 }
107 }
108
109 private File getSignedPreKeyFile(int signedPreKeyId) {
110 try {
111 IOUtils.createPrivateDirectories(signedPreKeysPath);
112 } catch (IOException e) {
113 throw new AssertionError("Failed to create signed pre keys path", e);
114 }
115 return new File(signedPreKeysPath, String.valueOf(signedPreKeyId));
116 }
117
118 private SignedPreKeyRecord loadSignedPreKeyRecord(final File file) {
119 try (var inputStream = new FileInputStream(file)) {
120 return new SignedPreKeyRecord(inputStream.readAllBytes());
121 } catch (IOException | InvalidMessageException e) {
122 logger.error("Failed to load signed pre key: {}", e.getMessage());
123 throw new AssertionError(e);
124 }
125 }
126 }