Add new --trust-new-identities global parameter

Closes #360
This commit is contained in:
AsamK 2021-08-23 15:50:03 +02:00
parent 6dd1a21606
commit 6c3106db5d
10 changed files with 132 additions and 35 deletions

View file

@ -43,6 +43,7 @@ import org.asamk.signal.manager.storage.groups.GroupInfo;
import org.asamk.signal.manager.storage.groups.GroupInfoV1;
import org.asamk.signal.manager.storage.groups.GroupInfoV2;
import org.asamk.signal.manager.storage.identities.IdentityInfo;
import org.asamk.signal.manager.storage.identities.TrustNewIdentity;
import org.asamk.signal.manager.storage.messageCache.CachedMessage;
import org.asamk.signal.manager.storage.recipients.Contact;
import org.asamk.signal.manager.storage.recipients.Profile;
@ -270,7 +271,11 @@ public class Manager implements Closeable {
}
public static Manager init(
String username, File settingsPath, ServiceEnvironment serviceEnvironment, String userAgent
String username,
File settingsPath,
ServiceEnvironment serviceEnvironment,
String userAgent,
final TrustNewIdentity trustNewIdentity
) throws IOException, NotRegisteredException {
var pathConfig = PathConfig.createDefault(settingsPath);
@ -278,7 +283,7 @@ public class Manager implements Closeable {
throw new NotRegisteredException();
}
var account = SignalAccount.load(pathConfig.getDataPath(), username, true);
var account = SignalAccount.load(pathConfig.getDataPath(), username, true, trustNewIdentity);
if (!account.isRegistered()) {
throw new NotRegisteredException();

View file

@ -20,6 +20,7 @@ import org.asamk.signal.manager.config.ServiceConfig;
import org.asamk.signal.manager.config.ServiceEnvironment;
import org.asamk.signal.manager.config.ServiceEnvironmentConfig;
import org.asamk.signal.manager.storage.SignalAccount;
import org.asamk.signal.manager.storage.identities.TrustNewIdentity;
import org.asamk.signal.manager.util.KeyUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -121,7 +122,8 @@ public class ProvisioningManager {
deviceId,
ret.getIdentity(),
registrationId,
profileKey);
profileKey,
TrustNewIdentity.ON_FIRST_USE);
Manager m = null;
try {
@ -161,7 +163,7 @@ public class ProvisioningManager {
private boolean canRelinkExistingAccount(final String number) throws IOException {
final SignalAccount signalAccount;
try {
signalAccount = SignalAccount.load(pathConfig.getDataPath(), number, false);
signalAccount = SignalAccount.load(pathConfig.getDataPath(), number, false, TrustNewIdentity.ON_FIRST_USE);
} catch (IOException e) {
logger.debug("Account in use or failed to load.", e);
return false;

View file

@ -21,6 +21,7 @@ import org.asamk.signal.manager.config.ServiceEnvironment;
import org.asamk.signal.manager.config.ServiceEnvironmentConfig;
import org.asamk.signal.manager.helper.PinHelper;
import org.asamk.signal.manager.storage.SignalAccount;
import org.asamk.signal.manager.storage.identities.TrustNewIdentity;
import org.asamk.signal.manager.util.KeyUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -102,12 +103,13 @@ public class RegistrationManager implements Closeable {
username,
identityKey,
registrationId,
profileKey);
profileKey,
TrustNewIdentity.ON_FIRST_USE);
return new RegistrationManager(account, pathConfig, serviceConfiguration, userAgent);
}
var account = SignalAccount.load(pathConfig.getDataPath(), username, true);
var account = SignalAccount.load(pathConfig.getDataPath(), username, true, TrustNewIdentity.ON_FIRST_USE);
return new RegistrationManager(account, pathConfig, serviceConfiguration, userAgent);
}

View file

@ -10,6 +10,7 @@ import org.asamk.signal.manager.storage.contacts.LegacyJsonContactsStore;
import org.asamk.signal.manager.storage.groups.GroupInfoV1;
import org.asamk.signal.manager.storage.groups.GroupStore;
import org.asamk.signal.manager.storage.identities.IdentityKeyStore;
import org.asamk.signal.manager.storage.identities.TrustNewIdentity;
import org.asamk.signal.manager.storage.messageCache.MessageCache;
import org.asamk.signal.manager.storage.prekeys.PreKeyStore;
import org.asamk.signal.manager.storage.prekeys.SignedPreKeyStore;
@ -106,12 +107,14 @@ public class SignalAccount implements Closeable {
this.lock = lock;
}
public static SignalAccount load(File dataPath, String username, boolean waitForLock) throws IOException {
public static SignalAccount load(
File dataPath, String username, boolean waitForLock, final TrustNewIdentity trustNewIdentity
) throws IOException {
final var fileName = getFileName(dataPath, username);
final var pair = openFileChannel(fileName, waitForLock);
try {
var account = new SignalAccount(pair.first(), pair.second());
account.load(dataPath);
account.load(dataPath, trustNewIdentity);
account.migrateLegacyConfigs();
if (!username.equals(account.getUsername())) {
@ -128,7 +131,12 @@ public class SignalAccount implements Closeable {
}
public static SignalAccount create(
File dataPath, String username, IdentityKeyPair identityKey, int registrationId, ProfileKey profileKey
File dataPath,
String username,
IdentityKeyPair identityKey,
int registrationId,
ProfileKey profileKey,
final TrustNewIdentity trustNewIdentity
) throws IOException {
IOUtils.createPrivateDirectories(dataPath);
var fileName = getFileName(dataPath, username);
@ -142,7 +150,7 @@ public class SignalAccount implements Closeable {
account.username = username;
account.profileKey = profileKey;
account.initStores(dataPath, identityKey, registrationId);
account.initStores(dataPath, identityKey, registrationId, trustNewIdentity);
account.groupStore = new GroupStore(getGroupCachePath(dataPath, username),
account.recipientStore::resolveRecipient,
account::saveGroupStore);
@ -157,7 +165,10 @@ public class SignalAccount implements Closeable {
}
private void initStores(
final File dataPath, final IdentityKeyPair identityKey, final int registrationId
final File dataPath,
final IdentityKeyPair identityKey,
final int registrationId,
final TrustNewIdentity trustNewIdentity
) throws IOException {
recipientStore = RecipientStore.load(getRecipientsStoreFile(dataPath, username), this::mergeRecipients);
@ -167,7 +178,8 @@ public class SignalAccount implements Closeable {
identityKeyStore = new IdentityKeyStore(getIdentitiesPath(dataPath, username),
recipientStore::resolveRecipient,
identityKey,
registrationId);
registrationId,
trustNewIdentity);
signalProtocolStore = new SignalProtocolStore(preKeyStore,
signedPreKeyStore,
sessionStore,
@ -186,7 +198,8 @@ public class SignalAccount implements Closeable {
int deviceId,
IdentityKeyPair identityKey,
int registrationId,
ProfileKey profileKey
ProfileKey profileKey,
final TrustNewIdentity trustNewIdentity
) throws IOException {
IOUtils.createPrivateDirectories(dataPath);
var fileName = getFileName(dataPath, username);
@ -199,10 +212,11 @@ public class SignalAccount implements Closeable {
deviceId,
identityKey,
registrationId,
profileKey);
profileKey,
trustNewIdentity);
}
final var account = load(dataPath, username, true);
final var account = load(dataPath, username, true, trustNewIdentity);
account.setProvisioningData(username, uuid, password, encryptedDeviceName, deviceId, profileKey);
account.recipientStore.resolveRecipientTrusted(account.getSelfAddress());
account.sessionStore.archiveAllSessions();
@ -227,7 +241,8 @@ public class SignalAccount implements Closeable {
int deviceId,
IdentityKeyPair identityKey,
int registrationId,
ProfileKey profileKey
ProfileKey profileKey,
final TrustNewIdentity trustNewIdentity
) throws IOException {
var fileName = getFileName(dataPath, username);
IOUtils.createPrivateFile(fileName);
@ -237,7 +252,7 @@ public class SignalAccount implements Closeable {
account.setProvisioningData(username, uuid, password, encryptedDeviceName, deviceId, profileKey);
account.initStores(dataPath, identityKey, registrationId);
account.initStores(dataPath, identityKey, registrationId, trustNewIdentity);
account.groupStore = new GroupStore(getGroupCachePath(dataPath, username),
account.recipientStore::resolveRecipient,
account::saveGroupStore);
@ -339,7 +354,9 @@ public class SignalAccount implements Closeable {
return !(!f.exists() || f.isDirectory());
}
private void load(File dataPath) throws IOException {
private void load(
File dataPath, final TrustNewIdentity trustNewIdentity
) throws IOException {
JsonNode rootNode;
synchronized (fileChannel) {
fileChannel.position(0);
@ -428,7 +445,7 @@ public class SignalAccount implements Closeable {
migratedLegacyConfig = true;
}
initStores(dataPath, identityKeyPair, registrationId);
initStores(dataPath, identityKeyPair, registrationId, trustNewIdentity);
migratedLegacyConfig = loadLegacyStores(rootNode, legacySignalProtocolStore) || migratedLegacyConfig;

View file

@ -42,17 +42,20 @@ public class IdentityKeyStore implements org.whispersystems.libsignal.state.Iden
private final RecipientResolver resolver;
private final IdentityKeyPair identityKeyPair;
private final int localRegistrationId;
private final TrustNewIdentity trustNewIdentity;
public IdentityKeyStore(
final File identitiesPath,
final RecipientResolver resolver,
final IdentityKeyPair identityKeyPair,
final int localRegistrationId
final int localRegistrationId,
final TrustNewIdentity trustNewIdentity
) {
this.identitiesPath = identitiesPath;
this.resolver = resolver;
this.identityKeyPair = identityKeyPair;
this.localRegistrationId = localRegistrationId;
this.trustNewIdentity = trustNewIdentity;
}
@Override
@ -80,7 +83,10 @@ public class IdentityKeyStore implements org.whispersystems.libsignal.state.Iden
return false;
}
final var trustLevel = identityInfo == null ? TrustLevel.TRUSTED_UNVERIFIED : TrustLevel.UNTRUSTED;
final var trustLevel = trustNewIdentity == TrustNewIdentity.ALWAYS || (
trustNewIdentity == TrustNewIdentity.ON_FIRST_USE && identityInfo == null
) ? TrustLevel.TRUSTED_UNVERIFIED : TrustLevel.UNTRUSTED;
logger.debug("Storing new identity for recipient {} with trust {}", recipientId, trustLevel);
final var newIdentityInfo = new IdentityInfo(recipientId, identityKey, trustLevel, added);
storeIdentityLocked(recipientId, newIdentityInfo);
return true;
@ -108,13 +114,17 @@ public class IdentityKeyStore implements org.whispersystems.libsignal.state.Iden
@Override
public boolean isTrustedIdentity(SignalProtocolAddress address, IdentityKey identityKey, Direction direction) {
if (trustNewIdentity == TrustNewIdentity.ALWAYS) {
return true;
}
var recipientId = resolveRecipient(address.getName());
synchronized (cachedIdentities) {
final var identityInfo = loadIdentityLocked(recipientId);
if (identityInfo == null) {
// Identity not found
return true;
return trustNewIdentity == TrustNewIdentity.ON_FIRST_USE;
}
// TODO implement possibility for different handling of incoming/outgoing trust decisions

View file

@ -0,0 +1,7 @@
package org.asamk.signal.manager.storage.identities;
public enum TrustNewIdentity {
ALWAYS,
ON_FIRST_USE,
NEVER
}