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 logger
.debug("Refreshing {} ec pre keys, because only {} of {} pre keys remain",
43 preKeyCounts
.getEcCount(),
44 ServiceConfig
.PREKEY_MINIMUM_COUNT
);
45 refreshPreKeys(serviceIdType
);
47 if (preKeyCounts
.getKyberCount() < ServiceConfig
.PREKEY_MINIMUM_COUNT
) {
48 logger
.debug("Refreshing {} kyber pre keys, because only {} of {} pre keys remain",
50 preKeyCounts
.getEcCount(),
51 ServiceConfig
.PREKEY_MINIMUM_COUNT
);
52 refreshKyberPreKeys(serviceIdType
);
56 private void refreshPreKeys(ServiceIdType serviceIdType
) throws IOException
{
57 final var identityKeyPair
= account
.getIdentityKeyPair(serviceIdType
);
58 if (identityKeyPair
== null) {
61 final var accountId
= account
.getAccountId(serviceIdType
);
62 if (accountId
== null) {
66 refreshPreKeys(serviceIdType
, identityKeyPair
);
67 } catch (Exception e
) {
68 logger
.warn("Failed to store new pre keys, resetting preKey id offset", e
);
69 account
.resetPreKeyOffsets(serviceIdType
);
70 refreshPreKeys(serviceIdType
, identityKeyPair
);
74 private void refreshPreKeys(
75 final ServiceIdType serviceIdType
, final IdentityKeyPair identityKeyPair
76 ) throws IOException
{
77 final var oneTimePreKeys
= generatePreKeys(serviceIdType
);
78 final var signedPreKeyRecord
= generateSignedPreKey(serviceIdType
, identityKeyPair
);
80 final var preKeyUpload
= new PreKeyUpload(serviceIdType
,
81 identityKeyPair
.getPublicKey(),
86 dependencies
.getAccountManager().setPreKeys(preKeyUpload
);
89 private List
<PreKeyRecord
> generatePreKeys(ServiceIdType serviceIdType
) {
90 final var offset
= account
.getPreKeyIdOffset(serviceIdType
);
92 var records
= KeyUtils
.generatePreKeyRecords(offset
);
93 account
.addPreKeys(serviceIdType
, records
);
98 private SignedPreKeyRecord
generateSignedPreKey(ServiceIdType serviceIdType
, IdentityKeyPair identityKeyPair
) {
99 final var signedPreKeyId
= account
.getNextSignedPreKeyId(serviceIdType
);
101 var record = KeyUtils
.generateSignedPreKeyRecord(signedPreKeyId
, identityKeyPair
);
102 account
.addSignedPreKey(serviceIdType
, record);
107 private void refreshKyberPreKeys(ServiceIdType serviceIdType
) throws IOException
{
108 final var identityKeyPair
= account
.getIdentityKeyPair(serviceIdType
);
109 if (identityKeyPair
== null) {
112 final var accountId
= account
.getAccountId(serviceIdType
);
113 if (accountId
== null) {
117 refreshKyberPreKeys(serviceIdType
, identityKeyPair
);
118 } catch (Exception e
) {
119 logger
.warn("Failed to store new pre keys, resetting preKey id offset", e
);
120 account
.resetKyberPreKeyOffsets(serviceIdType
);
121 refreshKyberPreKeys(serviceIdType
, identityKeyPair
);
125 private void refreshKyberPreKeys(
126 final ServiceIdType serviceIdType
, final IdentityKeyPair identityKeyPair
127 ) throws IOException
{
128 final var oneTimePreKeys
= generateKyberPreKeys(serviceIdType
, identityKeyPair
);
129 final var lastResortPreKeyRecord
= generateLastResortKyberPreKey(serviceIdType
, identityKeyPair
);
131 final var preKeyUpload
= new PreKeyUpload(serviceIdType
,
132 identityKeyPair
.getPublicKey(),
135 lastResortPreKeyRecord
,
137 dependencies
.getAccountManager().setPreKeys(preKeyUpload
);
140 private List
<KyberPreKeyRecord
> generateKyberPreKeys(
141 ServiceIdType serviceIdType
, final IdentityKeyPair identityKeyPair
143 final var offset
= account
.getKyberPreKeyIdOffset(serviceIdType
);
145 var records
= KeyUtils
.generateKyberPreKeyRecords(offset
, identityKeyPair
.getPrivateKey());
146 account
.addKyberPreKeys(serviceIdType
, records
);
151 private KyberPreKeyRecord
generateLastResortKyberPreKey(
152 ServiceIdType serviceIdType
, IdentityKeyPair identityKeyPair
154 final var signedPreKeyId
= account
.getKyberPreKeyIdOffset(serviceIdType
);
156 var record = KeyUtils
.generateKyberPreKeyRecord(signedPreKeyId
, identityKeyPair
.getPrivateKey());
157 account
.addLastResortKyberPreKey(serviceIdType
, record);