Refactor resolve recipient

This commit is contained in:
AsamK 2022-10-08 17:41:42 +02:00
parent 7ab013cee9
commit 51fef48016
4 changed files with 181 additions and 59 deletions

View file

@ -1179,38 +1179,11 @@ public class SignalAccount implements Closeable {
} }
public RecipientResolver getRecipientResolver() { public RecipientResolver getRecipientResolver() {
return new RecipientResolver() { return new RecipientResolver.RecipientResolverWrapper(this::getRecipientStore);
@Override
public RecipientId resolveRecipient(final RecipientAddress address) {
return getRecipientStore().resolveRecipient(address);
}
@Override
public RecipientId resolveRecipient(final long recipientId) {
return getRecipientStore().resolveRecipient(recipientId);
}
};
} }
public RecipientTrustedResolver getRecipientTrustedResolver() { public RecipientTrustedResolver getRecipientTrustedResolver() {
return new RecipientTrustedResolver() { return new RecipientTrustedResolver.RecipientTrustedResolverWrapper(this::getRecipientStore);
@Override
public RecipientId resolveSelfRecipientTrusted(final RecipientAddress address) {
return getRecipientStore().resolveSelfRecipientTrusted(address);
}
@Override
public RecipientId resolveRecipientTrusted(final SignalServiceAddress address) {
return getRecipientStore().resolveRecipientTrusted(address);
}
@Override
public RecipientId resolveRecipientTrusted(
final Optional<ACI> aci, final Optional<PNI> pni, final Optional<String> number
) {
return getRecipientStore().resolveRecipientTrusted(aci, pni, number);
}
};
} }
public RecipientAddressResolver getRecipientAddressResolver() { public RecipientAddressResolver getRecipientAddressResolver() {

View file

@ -1,24 +1,50 @@
package org.asamk.signal.manager.storage.recipients; package org.asamk.signal.manager.storage.recipients;
import org.asamk.signal.manager.storage.Utils;
import org.whispersystems.signalservice.api.push.ServiceId; import org.whispersystems.signalservice.api.push.ServiceId;
import org.whispersystems.signalservice.api.push.SignalServiceAddress; import org.whispersystems.signalservice.api.push.SignalServiceAddress;
import java.util.function.Supplier;
public interface RecipientResolver { public interface RecipientResolver {
RecipientId resolveRecipient(RecipientAddress address); RecipientId resolveRecipient(RecipientAddress address);
RecipientId resolveRecipient(long recipientId); RecipientId resolveRecipient(long recipientId);
default RecipientId resolveRecipient(String identifier) { RecipientId resolveRecipient(String identifier);
return resolveRecipient(Utils.getRecipientAddressFromIdentifier(identifier));
}
default RecipientId resolveRecipient(SignalServiceAddress address) { default RecipientId resolveRecipient(SignalServiceAddress address) {
return resolveRecipient(new RecipientAddress(address)); return resolveRecipient(new RecipientAddress(address));
} }
default RecipientId resolveRecipient(ServiceId serviceId) { RecipientId resolveRecipient(ServiceId serviceId);
return resolveRecipient(new RecipientAddress(serviceId));
class RecipientResolverWrapper implements RecipientResolver {
private final Supplier<RecipientResolver> recipientResolverSupplier;
public RecipientResolverWrapper(final Supplier<RecipientResolver> recipientResolverSupplier) {
this.recipientResolverSupplier = recipientResolverSupplier;
}
@Override
public RecipientId resolveRecipient(final RecipientAddress address) {
return recipientResolverSupplier.get().resolveRecipient(address);
}
@Override
public RecipientId resolveRecipient(final long recipientId) {
return recipientResolverSupplier.get().resolveRecipient(recipientId);
}
@Override
public RecipientId resolveRecipient(final String identifier) {
return recipientResolverSupplier.get().resolveRecipient(identifier);
}
@Override
public RecipientId resolveRecipient(final ServiceId serviceId) {
return recipientResolverSupplier.get().resolveRecipient(serviceId);
}
} }
} }

View file

@ -145,6 +145,44 @@ public class RecipientStore implements RecipientIdCreator, RecipientResolver, Re
} }
} }
@Override
public RecipientId resolveRecipient(final String identifier) {
if (UuidUtil.isUuid(identifier)) {
return resolveRecipient(ServiceId.parseOrThrow(identifier));
} else {
return resolveRecipientByNumber(identifier);
}
}
private RecipientId resolveRecipientByNumber(final String number) {
synchronized (recipientsLock) {
final RecipientId recipientId;
try (final var connection = database.getConnection()) {
connection.setAutoCommit(false);
recipientId = resolveRecipientLocked(connection, number);
connection.commit();
} catch (SQLException e) {
throw new RuntimeException("Failed read recipient store", e);
}
return recipientId;
}
}
@Override
public RecipientId resolveRecipient(final ServiceId serviceId) {
synchronized (recipientsLock) {
final RecipientId recipientId;
try (final var connection = database.getConnection()) {
connection.setAutoCommit(false);
recipientId = resolveRecipientLocked(connection, serviceId);
connection.commit();
} catch (SQLException e) {
throw new RuntimeException("Failed read recipient store", e);
}
return recipientId;
}
}
/** /**
* Should only be used for recipientIds from the database. * Should only be used for recipientIds from the database.
* Where the foreign key relations ensure a valid recipientId. * Where the foreign key relations ensure a valid recipientId.
@ -170,27 +208,37 @@ public class RecipientStore implements RecipientIdCreator, RecipientResolver, Re
number)); number));
} }
return resolveRecipient(new RecipientAddress(serviceId, number), false, false); return resolveRecipient(serviceId);
} }
return byNumber.get().id(); return byNumber.get().id();
} }
public RecipientId resolveRecipient(RecipientAddress address) { public RecipientId resolveRecipient(RecipientAddress address) {
return resolveRecipient(address, false, false); synchronized (recipientsLock) {
final RecipientId recipientId;
try (final var connection = database.getConnection()) {
connection.setAutoCommit(false);
recipientId = resolveRecipientLocked(connection, address);
connection.commit();
} catch (SQLException e) {
throw new RuntimeException("Failed read recipient store", e);
}
return recipientId;
}
} }
@Override @Override
public RecipientId resolveSelfRecipientTrusted(RecipientAddress address) { public RecipientId resolveSelfRecipientTrusted(RecipientAddress address) {
return resolveRecipient(address, true, true); return resolveRecipientTrusted(address, true);
} }
public RecipientId resolveRecipientTrusted(RecipientAddress address) { public RecipientId resolveRecipientTrusted(RecipientAddress address) {
return resolveRecipient(address, true, false); return resolveRecipientTrusted(address, false);
} }
@Override @Override
public RecipientId resolveRecipientTrusted(SignalServiceAddress address) { public RecipientId resolveRecipientTrusted(SignalServiceAddress address) {
return resolveRecipient(new RecipientAddress(address), true, false); return resolveRecipientTrusted(new RecipientAddress(address), false);
} }
@Override @Override
@ -198,7 +246,7 @@ public class RecipientStore implements RecipientIdCreator, RecipientResolver, Re
final Optional<ACI> aci, final Optional<PNI> pni, final Optional<String> number final Optional<ACI> aci, final Optional<PNI> pni, final Optional<String> number
) { ) {
final var serviceId = aci.map(a -> (ServiceId) a).or(() -> pni); final var serviceId = aci.map(a -> (ServiceId) a).or(() -> pni);
return resolveRecipient(new RecipientAddress(serviceId, number), true, false); return resolveRecipientTrusted(new RecipientAddress(serviceId, number), false);
} }
@Override @Override
@ -552,16 +600,12 @@ public class RecipientStore implements RecipientIdCreator, RecipientResolver, Re
} }
} }
/** private RecipientId resolveRecipientTrusted(RecipientAddress address, boolean isSelf) {
* @param isHighTrust true, if the number/uuid connection was obtained from a trusted source.
* Has no effect, if the address contains only a number or a uuid.
*/
private RecipientId resolveRecipient(RecipientAddress address, boolean isHighTrust, boolean isSelf) {
final Pair<RecipientId, Optional<RecipientId>> pair; final Pair<RecipientId, Optional<RecipientId>> pair;
synchronized (recipientsLock) { synchronized (recipientsLock) {
try (final var connection = database.getConnection()) { try (final var connection = database.getConnection()) {
connection.setAutoCommit(false); connection.setAutoCommit(false);
pair = resolveRecipientLocked(connection, address, isHighTrust, isSelf); pair = resolveRecipientTrustedLocked(connection, address, isSelf);
connection.commit(); connection.commit();
} catch (SQLException e) { } catch (SQLException e) {
throw new RuntimeException("Failed update recipient store", e); throw new RuntimeException("Failed update recipient store", e);
@ -579,12 +623,12 @@ public class RecipientStore implements RecipientIdCreator, RecipientResolver, Re
return pair.first(); return pair.first();
} }
private Pair<RecipientId, Optional<RecipientId>> resolveRecipientLocked( private Pair<RecipientId, Optional<RecipientId>> resolveRecipientTrustedLocked(
Connection connection, RecipientAddress address, boolean isHighTrust, boolean isSelf Connection connection, RecipientAddress address, boolean isSelf
) throws SQLException { ) throws SQLException {
if (isHighTrust && !isSelf) { if (!isSelf) {
if (selfAddressProvider.getSelfAddress().matches(address)) { if (selfAddressProvider.getSelfAddress().matches(address)) {
isHighTrust = false; return new Pair<>(resolveRecipientLocked(connection, address), Optional.empty());
} }
} }
final var byNumber = address.number().isEmpty() final var byNumber = address.number().isEmpty()
@ -596,16 +640,10 @@ public class RecipientStore implements RecipientIdCreator, RecipientResolver, Re
if (byNumber.isEmpty() && byUuid.isEmpty()) { if (byNumber.isEmpty() && byUuid.isEmpty()) {
logger.debug("Got new recipient, both uuid and number are unknown"); logger.debug("Got new recipient, both uuid and number are unknown");
if (isHighTrust || address.serviceId().isEmpty() || address.number().isEmpty()) {
return new Pair<>(addNewRecipient(connection, address), Optional.empty()); return new Pair<>(addNewRecipient(connection, address), Optional.empty());
} }
return new Pair<>(addNewRecipient(connection, new RecipientAddress(address.serviceId().get())), if (address.serviceId().isEmpty() || address.number().isEmpty() || byNumber.equals(byUuid)) {
Optional.empty());
}
if (!isHighTrust || address.serviceId().isEmpty() || address.number().isEmpty() || byNumber.equals(byUuid)) {
return new Pair<>(byUuid.or(() -> byNumber).map(RecipientWithAddress::id).get(), Optional.empty()); return new Pair<>(byUuid.or(() -> byNumber).map(RecipientWithAddress::id).get(), Optional.empty());
} }
@ -661,6 +699,64 @@ public class RecipientStore implements RecipientIdCreator, RecipientResolver, Re
return new Pair<>(byUuidRecipient.id(), Optional.of(toBeMergedRecipientId)); return new Pair<>(byUuidRecipient.id(), Optional.of(toBeMergedRecipientId));
} }
private RecipientId resolveRecipientLocked(
Connection connection, RecipientAddress address
) throws SQLException {
final var byServiceId = address.serviceId().isEmpty()
? Optional.<RecipientWithAddress>empty()
: findByServiceId(connection, address.serviceId().get());
if (byServiceId.isPresent()) {
return byServiceId.get().id();
}
final var byPni = address.pni().isEmpty()
? Optional.<RecipientWithAddress>empty()
: findByServiceId(connection, address.pni().get());
if (byPni.isPresent()) {
return byPni.get().id();
}
final var byNumber = address.number().isEmpty()
? Optional.<RecipientWithAddress>empty()
: findByNumber(connection, address.number().get());
if (byNumber.isPresent()) {
return byNumber.get().id();
}
logger.debug("Got new recipient, both serviceId and number are unknown");
if (address.serviceId().isEmpty()) {
return addNewRecipient(connection, address);
}
return addNewRecipient(connection, new RecipientAddress(address.serviceId().get()));
}
private RecipientId resolveRecipientLocked(Connection connection, ServiceId serviceId) throws SQLException {
final var recipient = findByServiceId(connection, serviceId);
if (recipient.isEmpty()) {
logger.debug("Got new recipient, serviceId is unknown");
return addNewRecipient(connection, new RecipientAddress(serviceId));
}
return recipient.get().id();
}
private RecipientId resolveRecipientLocked(Connection connection, String number) throws SQLException {
final var recipient = findByNumber(connection, number);
if (recipient.isEmpty()) {
logger.debug("Got new recipient, number is unknown");
return addNewRecipient(connection, new RecipientAddress(null, number));
}
return recipient.get().id();
}
private RecipientId addNewRecipient( private RecipientId addNewRecipient(
final Connection connection, final RecipientAddress address final Connection connection, final RecipientAddress address
) throws SQLException { ) throws SQLException {

View file

@ -5,6 +5,7 @@ import org.whispersystems.signalservice.api.push.PNI;
import org.whispersystems.signalservice.api.push.SignalServiceAddress; import org.whispersystems.signalservice.api.push.SignalServiceAddress;
import java.util.Optional; import java.util.Optional;
import java.util.function.Supplier;
public interface RecipientTrustedResolver { public interface RecipientTrustedResolver {
@ -13,4 +14,30 @@ public interface RecipientTrustedResolver {
RecipientId resolveRecipientTrusted(SignalServiceAddress address); RecipientId resolveRecipientTrusted(SignalServiceAddress address);
RecipientId resolveRecipientTrusted(Optional<ACI> aci, Optional<PNI> pni, Optional<String> number); RecipientId resolveRecipientTrusted(Optional<ACI> aci, Optional<PNI> pni, Optional<String> number);
class RecipientTrustedResolverWrapper implements RecipientTrustedResolver {
private final Supplier<RecipientTrustedResolver> recipientTrustedResolverSupplier;
public RecipientTrustedResolverWrapper(final Supplier<RecipientTrustedResolver> recipientTrustedResolverSupplier) {
this.recipientTrustedResolverSupplier = recipientTrustedResolverSupplier;
}
@Override
public RecipientId resolveSelfRecipientTrusted(final RecipientAddress address) {
return recipientTrustedResolverSupplier.get().resolveSelfRecipientTrusted(address);
}
@Override
public RecipientId resolveRecipientTrusted(final SignalServiceAddress address) {
return recipientTrustedResolverSupplier.get().resolveRecipientTrusted(address);
}
@Override
public RecipientId resolveRecipientTrusted(
final Optional<ACI> aci, final Optional<PNI> pni, final Optional<String> number
) {
return recipientTrustedResolverSupplier.get().resolveRecipientTrusted(aci, pni, number);
}
}
} }