1 package org
.asamk
.signal
.manager
.storage
.prekeys
;
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
;
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
;
19 public class SignedPreKeyStore
implements org
.signal
.libsignal
.protocol
.state
.SignedPreKeyStore
{
21 private final static Logger logger
= LoggerFactory
.getLogger(SignedPreKeyStore
.class);
23 private final File signedPreKeysPath
;
25 public SignedPreKeyStore(final File signedPreKeysPath
) {
26 this.signedPreKeysPath
= signedPreKeysPath
;
30 public SignedPreKeyRecord
loadSignedPreKey(int signedPreKeyId
) throws InvalidKeyIdException
{
31 final var file
= getSignedPreKeyFile(signedPreKeyId
);
34 throw new InvalidKeyIdException("No such signed pre key record!");
36 return loadSignedPreKeyRecord(file
);
39 final Pattern signedPreKeyFileNamePattern
= Pattern
.compile("([0-9]+)");
42 public List
<SignedPreKeyRecord
> loadSignedPreKeys() {
43 final var files
= signedPreKeysPath
.listFiles();
47 return Arrays
.stream(files
)
48 .filter(f
-> signedPreKeyFileNamePattern
.matcher(f
.getName()).matches())
49 .map(this::loadSignedPreKeyRecord
)
54 public void storeSignedPreKey(int signedPreKeyId
, SignedPreKeyRecord
record) {
55 final var file
= getSignedPreKeyFile(signedPreKeyId
);
57 try (var outputStream
= new FileOutputStream(file
)) {
58 outputStream
.write(record.serialize());
60 } catch (IOException e
) {
61 logger
.warn("Failed to store signed pre key, trying to delete file and retry: {}", e
.getMessage());
63 Files
.delete(file
.toPath());
64 try (var outputStream
= new FileOutputStream(file
)) {
65 outputStream
.write(record.serialize());
67 } catch (IOException e2
) {
68 logger
.error("Failed to store signed pre key file {}: {}", file
, e2
.getMessage());
74 public boolean containsSignedPreKey(int signedPreKeyId
) {
75 final var file
= getSignedPreKeyFile(signedPreKeyId
);
81 public void removeSignedPreKey(int signedPreKeyId
) {
82 final var file
= getSignedPreKeyFile(signedPreKeyId
);
88 Files
.delete(file
.toPath());
89 } catch (IOException e
) {
90 logger
.error("Failed to delete signed pre key file {}: {}", file
, e
.getMessage());
94 public void removeAllSignedPreKeys() {
95 final var files
= signedPreKeysPath
.listFiles();
100 for (var file
: files
) {
102 Files
.delete(file
.toPath());
103 } catch (IOException e
) {
104 logger
.error("Failed to delete signed pre key file {}: {}", file
, e
.getMessage());
109 private File
getSignedPreKeyFile(int signedPreKeyId
) {
111 IOUtils
.createPrivateDirectories(signedPreKeysPath
);
112 } catch (IOException e
) {
113 throw new AssertionError("Failed to create signed pre keys path", e
);
115 return new File(signedPreKeysPath
, String
.valueOf(signedPreKeyId
));
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
);