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
;
15 import org
.whispersystems
.signalservice
.api
.push
.exceptions
.AuthorizationFailedException
;
16 import org
.whispersystems
.signalservice
.internal
.push
.OneTimePreKeyCounts
;
18 import java
.io
.IOException
;
19 import java
.util
.List
;
21 public class PreKeyHelper
{
23 private final static Logger logger
= LoggerFactory
.getLogger(PreKeyHelper
.class);
25 private final SignalAccount account
;
26 private final SignalDependencies dependencies
;
29 final SignalAccount account
, final SignalDependencies dependencies
31 this.account
= account
;
32 this.dependencies
= dependencies
;
35 public void refreshPreKeysIfNecessary() throws IOException
{
36 refreshPreKeysIfNecessary(ServiceIdType
.ACI
);
37 refreshPreKeysIfNecessary(ServiceIdType
.PNI
);
40 public void refreshPreKeysIfNecessary(ServiceIdType serviceIdType
) throws IOException
{
41 OneTimePreKeyCounts preKeyCounts
;
43 preKeyCounts
= dependencies
.getAccountManager().getPreKeyCounts(serviceIdType
);
44 } catch (AuthorizationFailedException e
) {
45 logger
.debug("Failed to get pre key count, ignoring: " + e
.getClass().getSimpleName());
46 preKeyCounts
= new OneTimePreKeyCounts(0, 0);
48 if (preKeyCounts
.getEcCount() < ServiceConfig
.PREKEY_MINIMUM_COUNT
) {
49 logger
.debug("Refreshing {} ec pre keys, because only {} of min {} pre keys remain",
51 preKeyCounts
.getEcCount(),
52 ServiceConfig
.PREKEY_MINIMUM_COUNT
);
53 refreshPreKeys(serviceIdType
);
55 if (preKeyCounts
.getKyberCount() < ServiceConfig
.PREKEY_MINIMUM_COUNT
) {
56 logger
.debug("Refreshing {} kyber pre keys, because only {} of min {} pre keys remain",
58 preKeyCounts
.getKyberCount(),
59 ServiceConfig
.PREKEY_MINIMUM_COUNT
);
60 refreshKyberPreKeys(serviceIdType
);
64 private void refreshPreKeys(ServiceIdType serviceIdType
) throws IOException
{
65 final var identityKeyPair
= account
.getIdentityKeyPair(serviceIdType
);
66 if (identityKeyPair
== null) {
69 final var accountId
= account
.getAccountId(serviceIdType
);
70 if (accountId
== null) {
74 refreshPreKeys(serviceIdType
, identityKeyPair
);
75 } catch (Exception e
) {
76 logger
.warn("Failed to store new pre keys, resetting preKey id offset", e
);
77 account
.resetPreKeyOffsets(serviceIdType
);
78 refreshPreKeys(serviceIdType
, identityKeyPair
);
82 private void refreshPreKeys(
83 final ServiceIdType serviceIdType
, final IdentityKeyPair identityKeyPair
84 ) throws IOException
{
85 final var oneTimePreKeys
= generatePreKeys(serviceIdType
);
86 final var signedPreKeyRecord
= generateSignedPreKey(serviceIdType
, identityKeyPair
);
88 final var preKeyUpload
= new PreKeyUpload(serviceIdType
,
89 identityKeyPair
.getPublicKey(),
94 dependencies
.getAccountManager().setPreKeys(preKeyUpload
);
97 private List
<PreKeyRecord
> generatePreKeys(ServiceIdType serviceIdType
) {
98 final var offset
= account
.getPreKeyIdOffset(serviceIdType
);
100 var records
= KeyUtils
.generatePreKeyRecords(offset
);
101 account
.addPreKeys(serviceIdType
, records
);
106 private SignedPreKeyRecord
generateSignedPreKey(ServiceIdType serviceIdType
, IdentityKeyPair identityKeyPair
) {
107 final var signedPreKeyId
= account
.getNextSignedPreKeyId(serviceIdType
);
109 var record = KeyUtils
.generateSignedPreKeyRecord(signedPreKeyId
, identityKeyPair
);
110 account
.addSignedPreKey(serviceIdType
, record);
115 private void refreshKyberPreKeys(ServiceIdType serviceIdType
) throws IOException
{
116 final var identityKeyPair
= account
.getIdentityKeyPair(serviceIdType
);
117 if (identityKeyPair
== null) {
120 final var accountId
= account
.getAccountId(serviceIdType
);
121 if (accountId
== null) {
125 refreshKyberPreKeys(serviceIdType
, identityKeyPair
);
126 } catch (Exception e
) {
127 logger
.warn("Failed to store new pre keys, resetting preKey id offset", e
);
128 account
.resetKyberPreKeyOffsets(serviceIdType
);
129 refreshKyberPreKeys(serviceIdType
, identityKeyPair
);
133 private void refreshKyberPreKeys(
134 final ServiceIdType serviceIdType
, final IdentityKeyPair identityKeyPair
135 ) throws IOException
{
136 final var oneTimePreKeys
= generateKyberPreKeys(serviceIdType
, identityKeyPair
);
137 final var lastResortPreKeyRecord
= generateLastResortKyberPreKey(serviceIdType
, identityKeyPair
);
139 final var preKeyUpload
= new PreKeyUpload(serviceIdType
,
140 identityKeyPair
.getPublicKey(),
143 lastResortPreKeyRecord
,
145 dependencies
.getAccountManager().setPreKeys(preKeyUpload
);
148 private List
<KyberPreKeyRecord
> generateKyberPreKeys(
149 ServiceIdType serviceIdType
, final IdentityKeyPair identityKeyPair
151 final var offset
= account
.getKyberPreKeyIdOffset(serviceIdType
);
153 var records
= KeyUtils
.generateKyberPreKeyRecords(offset
, identityKeyPair
.getPrivateKey());
154 account
.addKyberPreKeys(serviceIdType
, records
);
159 private KyberPreKeyRecord
generateLastResortKyberPreKey(
160 ServiceIdType serviceIdType
, IdentityKeyPair identityKeyPair
162 final var signedPreKeyId
= account
.getKyberPreKeyIdOffset(serviceIdType
);
164 var record = KeyUtils
.generateKyberPreKeyRecord(signedPreKeyId
, identityKeyPair
.getPrivateKey());
165 account
.addLastResortKyberPreKey(serviceIdType
, record);