1 package org
.asamk
.signal
.manager
.helper
;
3 import org
.asamk
.signal
.manager
.config
.ServiceConfig
;
4 import org
.asamk
.signal
.manager
.internal
.SignalDependencies
;
5 import org
.asamk
.signal
.manager
.storage
.SignalAccount
;
6 import org
.asamk
.signal
.manager
.util
.KeyUtils
;
7 import org
.signal
.libsignal
.protocol
.IdentityKeyPair
;
8 import org
.signal
.libsignal
.protocol
.state
.KyberPreKeyRecord
;
9 import org
.signal
.libsignal
.protocol
.state
.PreKeyRecord
;
10 import org
.signal
.libsignal
.protocol
.state
.SignedPreKeyRecord
;
11 import org
.slf4j
.Logger
;
12 import org
.slf4j
.LoggerFactory
;
13 import org
.whispersystems
.signalservice
.api
.account
.PreKeyUpload
;
14 import org
.whispersystems
.signalservice
.api
.push
.ServiceIdType
;
16 import java
.io
.IOException
;
17 import java
.util
.List
;
19 public class PreKeyHelper
{
21 private final static Logger logger
= LoggerFactory
.getLogger(PreKeyHelper
.class);
23 private final SignalAccount account
;
24 private final SignalDependencies dependencies
;
27 final SignalAccount account
, final SignalDependencies dependencies
29 this.account
= account
;
30 this.dependencies
= dependencies
;
33 public void refreshPreKeysIfNecessary() throws IOException
{
34 refreshPreKeysIfNecessary(ServiceIdType
.ACI
);
35 refreshPreKeysIfNecessary(ServiceIdType
.PNI
);
38 public void refreshPreKeysIfNecessary(ServiceIdType serviceIdType
) throws IOException
{
39 final var preKeyCounts
= dependencies
.getAccountManager().getPreKeyCounts(serviceIdType
);
40 if (preKeyCounts
.getEcCount() < ServiceConfig
.PREKEY_MINIMUM_COUNT
) {
41 refreshPreKeys(serviceIdType
);
43 if (preKeyCounts
.getKyberCount() < ServiceConfig
.PREKEY_MINIMUM_COUNT
) {
44 refreshKyberPreKeys(serviceIdType
);
48 public void refreshPreKeys() throws IOException
{
49 refreshPreKeys(ServiceIdType
.ACI
);
50 refreshPreKeys(ServiceIdType
.PNI
);
53 private void refreshPreKeys(ServiceIdType serviceIdType
) throws IOException
{
54 final var identityKeyPair
= account
.getIdentityKeyPair(serviceIdType
);
55 if (identityKeyPair
== null) {
58 final var accountId
= account
.getAccountId(serviceIdType
);
59 if (accountId
== null) {
63 refreshPreKeys(serviceIdType
, identityKeyPair
);
64 } catch (Exception e
) {
65 logger
.warn("Failed to store new pre keys, resetting preKey id offset", e
);
66 account
.resetPreKeyOffsets(serviceIdType
);
67 refreshPreKeys(serviceIdType
, identityKeyPair
);
71 private void refreshPreKeys(
72 final ServiceIdType serviceIdType
, final IdentityKeyPair identityKeyPair
73 ) throws IOException
{
74 final var oneTimePreKeys
= generatePreKeys(serviceIdType
);
75 final var signedPreKeyRecord
= generateSignedPreKey(serviceIdType
, identityKeyPair
);
77 final var preKeyUpload
= new PreKeyUpload(serviceIdType
,
78 identityKeyPair
.getPublicKey(),
83 dependencies
.getAccountManager().setPreKeys(preKeyUpload
);
86 private List
<PreKeyRecord
> generatePreKeys(ServiceIdType serviceIdType
) {
87 final var offset
= account
.getPreKeyIdOffset(serviceIdType
);
89 var records
= KeyUtils
.generatePreKeyRecords(offset
, ServiceConfig
.PREKEY_BATCH_SIZE
);
90 account
.addPreKeys(serviceIdType
, records
);
95 private SignedPreKeyRecord
generateSignedPreKey(ServiceIdType serviceIdType
, IdentityKeyPair identityKeyPair
) {
96 final var signedPreKeyId
= account
.getNextSignedPreKeyId(serviceIdType
);
98 var record = KeyUtils
.generateSignedPreKeyRecord(identityKeyPair
, signedPreKeyId
);
99 account
.addSignedPreKey(serviceIdType
, record);
104 private void refreshKyberPreKeys(ServiceIdType serviceIdType
) throws IOException
{
105 final var identityKeyPair
= account
.getIdentityKeyPair(serviceIdType
);
106 if (identityKeyPair
== null) {
109 final var accountId
= account
.getAccountId(serviceIdType
);
110 if (accountId
== null) {
114 refreshKyberPreKeys(serviceIdType
, identityKeyPair
);
115 } catch (Exception e
) {
116 logger
.warn("Failed to store new pre keys, resetting preKey id offset", e
);
117 account
.resetKyberPreKeyOffsets(serviceIdType
);
118 refreshKyberPreKeys(serviceIdType
, identityKeyPair
);
122 private void refreshKyberPreKeys(
123 final ServiceIdType serviceIdType
, final IdentityKeyPair identityKeyPair
124 ) throws IOException
{
125 final var oneTimePreKeys
= generateKyberPreKeys(serviceIdType
, identityKeyPair
);
126 final var lastResortPreKeyRecord
= generateLastResortKyberPreKey(serviceIdType
, identityKeyPair
);
128 final var preKeyUpload
= new PreKeyUpload(serviceIdType
,
129 identityKeyPair
.getPublicKey(),
132 lastResortPreKeyRecord
,
134 dependencies
.getAccountManager().setPreKeys(preKeyUpload
);
137 private List
<KyberPreKeyRecord
> generateKyberPreKeys(
138 ServiceIdType serviceIdType
, final IdentityKeyPair identityKeyPair
140 final var offset
= account
.getKyberPreKeyIdOffset(serviceIdType
);
142 var records
= KeyUtils
.generateKyberPreKeyRecords(offset
,
143 ServiceConfig
.PREKEY_BATCH_SIZE
,
144 identityKeyPair
.getPrivateKey());
145 account
.addKyberPreKeys(serviceIdType
, records
);
150 private KyberPreKeyRecord
generateLastResortKyberPreKey(
151 ServiceIdType serviceIdType
, IdentityKeyPair identityKeyPair
153 final var signedPreKeyId
= account
.getKyberPreKeyIdOffset(serviceIdType
);
155 var record = KeyUtils
.generateKyberPreKeyRecord(signedPreKeyId
, identityKeyPair
.getPrivateKey());
156 account
.addLastResortKyberPreKey(serviceIdType
, record);