mirror of
https://github.com/AsamK/signal-cli
synced 2025-08-29 02:20:39 +00:00
Use CDSI for contact discovery in compat mode
This commit is contained in:
parent
60ed2c292f
commit
ed3992d993
7 changed files with 120 additions and 11 deletions
|
@ -95,6 +95,10 @@ class LiveConfig {
|
|||
return CDS_MRENCLAVE;
|
||||
}
|
||||
|
||||
static String getCdsiMrenclave() {
|
||||
return CDSI_MRENCLAVE;
|
||||
}
|
||||
|
||||
private LiveConfig() {
|
||||
}
|
||||
}
|
||||
|
|
|
@ -89,13 +89,15 @@ public class ServiceConfig {
|
|||
LiveConfig.getUnidentifiedSenderTrustRoot(),
|
||||
LiveConfig.createKeyBackupConfig(),
|
||||
LiveConfig.createFallbackKeyBackupConfigs(),
|
||||
LiveConfig.getCdsMrenclave());
|
||||
LiveConfig.getCdsMrenclave(),
|
||||
LiveConfig.getCdsiMrenclave());
|
||||
case STAGING -> new ServiceEnvironmentConfig(serviceEnvironment,
|
||||
StagingConfig.createDefaultServiceConfiguration(interceptors),
|
||||
StagingConfig.getUnidentifiedSenderTrustRoot(),
|
||||
StagingConfig.createKeyBackupConfig(),
|
||||
StagingConfig.createFallbackKeyBackupConfigs(),
|
||||
StagingConfig.getCdsMrenclave());
|
||||
StagingConfig.getCdsMrenclave(),
|
||||
StagingConfig.getCdsiMrenclave());
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,6 +16,7 @@ public class ServiceEnvironmentConfig {
|
|||
private final Collection<KeyBackupConfig> fallbackKeyBackupConfigs;
|
||||
|
||||
private final String cdsMrenclave;
|
||||
private final String cdsiMrenclave;
|
||||
|
||||
public ServiceEnvironmentConfig(
|
||||
final ServiceEnvironment type,
|
||||
|
@ -23,7 +24,8 @@ public class ServiceEnvironmentConfig {
|
|||
final ECPublicKey unidentifiedSenderTrustRoot,
|
||||
final KeyBackupConfig keyBackupConfig,
|
||||
final Collection<KeyBackupConfig> fallbackKeyBackupConfigs,
|
||||
final String cdsMrenclave
|
||||
final String cdsMrenclave,
|
||||
final String cdsiMrenclave
|
||||
) {
|
||||
this.type = type;
|
||||
this.signalServiceConfiguration = signalServiceConfiguration;
|
||||
|
@ -31,6 +33,7 @@ public class ServiceEnvironmentConfig {
|
|||
this.keyBackupConfig = keyBackupConfig;
|
||||
this.fallbackKeyBackupConfigs = fallbackKeyBackupConfigs;
|
||||
this.cdsMrenclave = cdsMrenclave;
|
||||
this.cdsiMrenclave = cdsiMrenclave;
|
||||
}
|
||||
|
||||
public ServiceEnvironment getType() {
|
||||
|
@ -56,4 +59,8 @@ public class ServiceEnvironmentConfig {
|
|||
public String getCdsMrenclave() {
|
||||
return cdsMrenclave;
|
||||
}
|
||||
|
||||
public String getCdsiMrenclave() {
|
||||
return cdsiMrenclave;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -95,6 +95,10 @@ class StagingConfig {
|
|||
return CDS_MRENCLAVE;
|
||||
}
|
||||
|
||||
static String getCdsiMrenclave() {
|
||||
return CDSI_MRENCLAVE;
|
||||
}
|
||||
|
||||
private StagingConfig() {
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,6 +14,7 @@ import org.slf4j.LoggerFactory;
|
|||
import org.whispersystems.signalservice.api.push.ACI;
|
||||
import org.whispersystems.signalservice.api.push.ServiceId;
|
||||
import org.whispersystems.signalservice.api.push.SignalServiceAddress;
|
||||
import org.whispersystems.signalservice.api.services.CdsiV2Service;
|
||||
import org.whispersystems.signalservice.internal.contacts.crypto.Quote;
|
||||
import org.whispersystems.signalservice.internal.contacts.crypto.UnauthenticatedQuoteException;
|
||||
import org.whispersystems.signalservice.internal.contacts.crypto.UnauthenticatedResponseException;
|
||||
|
@ -21,8 +22,10 @@ import org.whispersystems.signalservice.internal.contacts.crypto.Unauthenticated
|
|||
import java.io.IOException;
|
||||
import java.security.SignatureException;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
|
||||
public class RecipientHelper {
|
||||
|
@ -104,15 +107,12 @@ public class RecipientHelper {
|
|||
}
|
||||
|
||||
public Map<String, ACI> getRegisteredUsers(final Set<String> numbers) throws IOException {
|
||||
final Map<String, ACI> registeredUsers;
|
||||
Map<String, ACI> registeredUsers;
|
||||
try {
|
||||
registeredUsers = dependencies.getAccountManager()
|
||||
.getRegisteredUsers(ServiceConfig.getIasKeyStore(),
|
||||
numbers,
|
||||
serviceEnvironmentConfig.getCdsMrenclave());
|
||||
} catch (Quote.InvalidQuoteFormatException | UnauthenticatedQuoteException | SignatureException |
|
||||
UnauthenticatedResponseException | InvalidKeyException | NumberFormatException e) {
|
||||
throw new IOException(e);
|
||||
registeredUsers = getRegisteredUsersV2(numbers, true);
|
||||
} catch (IOException e) {
|
||||
logger.warn("CDSI request failed, trying fallback to CDS", e);
|
||||
registeredUsers = getRegisteredUsersV1(numbers);
|
||||
}
|
||||
|
||||
// Store numbers as recipients, so we have the number/uuid association
|
||||
|
@ -136,6 +136,48 @@ public class RecipientHelper {
|
|||
return uuid;
|
||||
}
|
||||
|
||||
private Map<String, ACI> getRegisteredUsersV1(final Set<String> numbers) throws IOException {
|
||||
final Map<String, ACI> registeredUsers;
|
||||
try {
|
||||
registeredUsers = dependencies.getAccountManager()
|
||||
.getRegisteredUsers(ServiceConfig.getIasKeyStore(),
|
||||
numbers,
|
||||
serviceEnvironmentConfig.getCdsMrenclave());
|
||||
} catch (Quote.InvalidQuoteFormatException | UnauthenticatedQuoteException | SignatureException |
|
||||
UnauthenticatedResponseException | InvalidKeyException | NumberFormatException e) {
|
||||
throw new IOException(e);
|
||||
}
|
||||
return registeredUsers;
|
||||
}
|
||||
|
||||
private Map<String, ACI> getRegisteredUsersV2(final Set<String> numbers, boolean useCompat) throws IOException {
|
||||
// Only partial refresh is implemented here
|
||||
final CdsiV2Service.Response response;
|
||||
try {
|
||||
response = dependencies.getAccountManager()
|
||||
.getRegisteredUsersWithCdsi(Set.of(),
|
||||
numbers,
|
||||
account.getRecipientStore().getServiceIdToProfileKeyMap(),
|
||||
useCompat,
|
||||
Optional.empty(),
|
||||
serviceEnvironmentConfig.getCdsiMrenclave(),
|
||||
token -> {
|
||||
// Not storing for partial refresh
|
||||
});
|
||||
} catch (NumberFormatException e) {
|
||||
throw new IOException(e);
|
||||
}
|
||||
logger.debug("CDSI request successful, quota used by this request: {}", response.getQuotaUsedDebugOnly());
|
||||
|
||||
final var registeredUsers = new HashMap<String, ACI>();
|
||||
response.getResults().forEach((key, value) -> {
|
||||
if (value.getAci().isPresent()) {
|
||||
registeredUsers.put(key, value.getAci().get());
|
||||
}
|
||||
});
|
||||
return registeredUsers;
|
||||
}
|
||||
|
||||
private ACI getRegisteredUserByUsername(String username) throws IOException {
|
||||
return dependencies.getAccountManager().getAciByUsername(username);
|
||||
}
|
||||
|
|
|
@ -12,6 +12,7 @@ import org.signal.libsignal.zkgroup.profiles.ProfileKey;
|
|||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.whispersystems.signalservice.api.push.ACI;
|
||||
import org.whispersystems.signalservice.api.push.ServiceId;
|
||||
import org.whispersystems.signalservice.api.push.SignalServiceAddress;
|
||||
import org.whispersystems.signalservice.api.util.UuidUtil;
|
||||
|
||||
|
@ -274,6 +275,27 @@ public class RecipientStore implements RecipientIdCreator, RecipientResolver, Re
|
|||
}
|
||||
}
|
||||
|
||||
public Map<ServiceId, ProfileKey> getServiceIdToProfileKeyMap() {
|
||||
final var sql = (
|
||||
"""
|
||||
SELECT r.uuid, r.profile_key
|
||||
FROM %s r
|
||||
WHERE r.uuid IS NOT NULL AND r.profile_key IS NOT NULL
|
||||
"""
|
||||
).formatted(TABLE_RECIPIENT);
|
||||
try (final var connection = database.getConnection()) {
|
||||
try (final var statement = connection.prepareStatement(sql)) {
|
||||
return Utils.executeQueryForStream(statement, resultSet -> {
|
||||
final var serviceId = ServiceId.parseOrThrow(resultSet.getBytes("uuid"));
|
||||
final var profileKey = getProfileKeyFromResultSet(resultSet);
|
||||
return new Pair<>(serviceId, profileKey);
|
||||
}).filter(Objects::nonNull).collect(Collectors.toMap(Pair::first, Pair::second));
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
throw new RuntimeException("Failed read from recipient store", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteContact(RecipientId recipientId) {
|
||||
storeContact(recipientId, null);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue