Add option to disable adding message to send log

This commit is contained in:
AsamK 2022-10-30 11:00:25 +01:00
parent 49aaff2bbe
commit 207764e0be
7 changed files with 60 additions and 31 deletions

View file

@ -21,7 +21,6 @@ import org.asamk.signal.manager.config.ServiceConfig;
import org.asamk.signal.manager.config.ServiceEnvironmentConfig; import org.asamk.signal.manager.config.ServiceEnvironmentConfig;
import org.asamk.signal.manager.storage.SignalAccount; import org.asamk.signal.manager.storage.SignalAccount;
import org.asamk.signal.manager.storage.accounts.AccountsStore; import org.asamk.signal.manager.storage.accounts.AccountsStore;
import org.asamk.signal.manager.storage.identities.TrustNewIdentity;
import org.asamk.signal.manager.util.KeyUtils; import org.asamk.signal.manager.util.KeyUtils;
import org.signal.libsignal.protocol.IdentityKeyPair; import org.signal.libsignal.protocol.IdentityKeyPair;
import org.signal.libsignal.protocol.util.KeyHelper; import org.signal.libsignal.protocol.util.KeyHelper;
@ -147,7 +146,7 @@ class ProvisioningManagerImpl implements ProvisioningManager {
registrationId, registrationId,
pniRegistrationId, pniRegistrationId,
profileKey, profileKey,
TrustNewIdentity.ON_FIRST_USE); Settings.DEFAULT);
ManagerImpl m = null; ManagerImpl m = null;
try { try {
@ -194,10 +193,7 @@ class ProvisioningManagerImpl implements ProvisioningManager {
private boolean canRelinkExistingAccount(final String accountPath) throws IOException { private boolean canRelinkExistingAccount(final String accountPath) throws IOException {
final SignalAccount signalAccount; final SignalAccount signalAccount;
try { try {
signalAccount = SignalAccount.load(pathConfig.dataPath(), signalAccount = SignalAccount.load(pathConfig.dataPath(), accountPath, false, Settings.DEFAULT);
accountPath,
false,
TrustNewIdentity.ON_FIRST_USE);
} catch (IOException e) { } catch (IOException e) {
logger.debug("Account in use or failed to load.", e); logger.debug("Account in use or failed to load.", e);
return false; return false;

View file

@ -0,0 +1,8 @@
package org.asamk.signal.manager;
import org.asamk.signal.manager.storage.identities.TrustNewIdentity;
public record Settings(TrustNewIdentity trustNewIdentity, boolean disableMessageSendLog) {
public static Settings DEFAULT = new Settings(TrustNewIdentity.ON_FIRST_USE, false);
}

View file

@ -7,7 +7,6 @@ import org.asamk.signal.manager.config.ServiceEnvironment;
import org.asamk.signal.manager.config.ServiceEnvironmentConfig; import org.asamk.signal.manager.config.ServiceEnvironmentConfig;
import org.asamk.signal.manager.storage.SignalAccount; import org.asamk.signal.manager.storage.SignalAccount;
import org.asamk.signal.manager.storage.accounts.AccountsStore; import org.asamk.signal.manager.storage.accounts.AccountsStore;
import org.asamk.signal.manager.storage.identities.TrustNewIdentity;
import org.asamk.signal.manager.util.KeyUtils; import org.asamk.signal.manager.util.KeyUtils;
import org.signal.libsignal.protocol.util.KeyHelper; import org.signal.libsignal.protocol.util.KeyHelper;
import org.slf4j.Logger; import org.slf4j.Logger;
@ -28,27 +27,27 @@ public class SignalAccountFiles {
private final ServiceEnvironment serviceEnvironment; private final ServiceEnvironment serviceEnvironment;
private final ServiceEnvironmentConfig serviceEnvironmentConfig; private final ServiceEnvironmentConfig serviceEnvironmentConfig;
private final String userAgent; private final String userAgent;
private final TrustNewIdentity trustNewIdentity; private final Settings settings;
private final AccountsStore accountsStore; private final AccountsStore accountsStore;
public SignalAccountFiles( public SignalAccountFiles(
final File settingsPath, final File settingsPath,
final ServiceEnvironment serviceEnvironment, final ServiceEnvironment serviceEnvironment,
final String userAgent, final String userAgent,
final TrustNewIdentity trustNewIdentity final Settings settings
) throws IOException { ) throws IOException {
this.pathConfig = PathConfig.createDefault(settingsPath); this.pathConfig = PathConfig.createDefault(settingsPath);
this.serviceEnvironment = serviceEnvironment; this.serviceEnvironment = serviceEnvironment;
this.serviceEnvironmentConfig = ServiceConfig.getServiceEnvironmentConfig(this.serviceEnvironment, userAgent); this.serviceEnvironmentConfig = ServiceConfig.getServiceEnvironmentConfig(this.serviceEnvironment, userAgent);
this.userAgent = userAgent; this.userAgent = userAgent;
this.trustNewIdentity = trustNewIdentity; this.settings = settings;
this.accountsStore = new AccountsStore(pathConfig.dataPath(), serviceEnvironment, accountPath -> { this.accountsStore = new AccountsStore(pathConfig.dataPath(), serviceEnvironment, accountPath -> {
if (accountPath == null || !SignalAccount.accountFileExists(pathConfig.dataPath(), accountPath)) { if (accountPath == null || !SignalAccount.accountFileExists(pathConfig.dataPath(), accountPath)) {
return null; return null;
} }
try { try {
return SignalAccount.load(pathConfig.dataPath(), accountPath, false, trustNewIdentity); return SignalAccount.load(pathConfig.dataPath(), accountPath, false, settings);
} catch (Exception e) { } catch (Exception e) {
return null; return null;
} }
@ -90,7 +89,7 @@ public class SignalAccountFiles {
throw new NotRegisteredException(); throw new NotRegisteredException();
} }
var account = SignalAccount.load(pathConfig.dataPath(), accountPath, true, trustNewIdentity); var account = SignalAccount.load(pathConfig.dataPath(), accountPath, true, settings);
if (!number.equals(account.getNumber())) { if (!number.equals(account.getNumber())) {
account.close(); account.close();
throw new IOException("Number in account file doesn't match expected number: " + account.getNumber()); throw new IOException("Number in account file doesn't match expected number: " + account.getNumber());
@ -168,7 +167,7 @@ public class SignalAccountFiles {
registrationId, registrationId,
pniRegistrationId, pniRegistrationId,
profileKey, profileKey,
trustNewIdentity); settings);
return new RegistrationManagerImpl(account, return new RegistrationManagerImpl(account,
pathConfig, pathConfig,
@ -178,7 +177,7 @@ public class SignalAccountFiles {
new AccountFileUpdaterImpl(accountsStore, newAccountPath)); new AccountFileUpdaterImpl(accountsStore, newAccountPath));
} }
var account = SignalAccount.load(pathConfig.dataPath(), accountPath, true, trustNewIdentity); var account = SignalAccount.load(pathConfig.dataPath(), accountPath, true, settings);
if (!number.equals(account.getNumber())) { if (!number.equals(account.getNumber())) {
account.close(); account.close();
throw new IOException("Number in account file doesn't match expected number: " + account.getNumber()); throw new IOException("Number in account file doesn't match expected number: " + account.getNumber());

View file

@ -3,6 +3,7 @@ package org.asamk.signal.manager.storage;
import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import org.asamk.signal.manager.Settings;
import org.asamk.signal.manager.api.Pair; import org.asamk.signal.manager.api.Pair;
import org.asamk.signal.manager.api.TrustLevel; import org.asamk.signal.manager.api.TrustLevel;
import org.asamk.signal.manager.config.ServiceEnvironment; import org.asamk.signal.manager.config.ServiceEnvironment;
@ -17,7 +18,6 @@ import org.asamk.signal.manager.storage.groups.LegacyGroupStore;
import org.asamk.signal.manager.storage.identities.IdentityKeyStore; import org.asamk.signal.manager.storage.identities.IdentityKeyStore;
import org.asamk.signal.manager.storage.identities.LegacyIdentityKeyStore; import org.asamk.signal.manager.storage.identities.LegacyIdentityKeyStore;
import org.asamk.signal.manager.storage.identities.SignalIdentityKeyStore; import org.asamk.signal.manager.storage.identities.SignalIdentityKeyStore;
import org.asamk.signal.manager.storage.identities.TrustNewIdentity;
import org.asamk.signal.manager.storage.messageCache.MessageCache; import org.asamk.signal.manager.storage.messageCache.MessageCache;
import org.asamk.signal.manager.storage.prekeys.LegacyPreKeyStore; import org.asamk.signal.manager.storage.prekeys.LegacyPreKeyStore;
import org.asamk.signal.manager.storage.prekeys.LegacySignedPreKeyStore; import org.asamk.signal.manager.storage.prekeys.LegacySignedPreKeyStore;
@ -136,7 +136,7 @@ public class SignalAccount implements Closeable {
private IdentityKeyPair pniIdentityKeyPair; private IdentityKeyPair pniIdentityKeyPair;
private int localRegistrationId; private int localRegistrationId;
private int localPniRegistrationId; private int localPniRegistrationId;
private TrustNewIdentity trustNewIdentity; private Settings settings;
private long lastReceiveTimestamp = 0; private long lastReceiveTimestamp = 0;
private boolean registered = false; private boolean registered = false;
@ -170,7 +170,7 @@ public class SignalAccount implements Closeable {
} }
public static SignalAccount load( public static SignalAccount load(
File dataPath, String accountPath, boolean waitForLock, final TrustNewIdentity trustNewIdentity File dataPath, String accountPath, boolean waitForLock, final Settings settings
) throws IOException { ) throws IOException {
logger.trace("Opening account file"); logger.trace("Opening account file");
final var fileName = getFileName(dataPath, accountPath); final var fileName = getFileName(dataPath, accountPath);
@ -178,7 +178,7 @@ public class SignalAccount implements Closeable {
try { try {
var signalAccount = new SignalAccount(pair.first(), pair.second()); var signalAccount = new SignalAccount(pair.first(), pair.second());
logger.trace("Loading account file"); logger.trace("Loading account file");
signalAccount.load(dataPath, accountPath, trustNewIdentity); signalAccount.load(dataPath, accountPath, settings);
logger.trace("Migrating legacy parts of account file"); logger.trace("Migrating legacy parts of account file");
signalAccount.migrateLegacyConfigs(); signalAccount.migrateLegacyConfigs();
@ -200,7 +200,7 @@ public class SignalAccount implements Closeable {
int registrationId, int registrationId,
int pniRegistrationId, int pniRegistrationId,
ProfileKey profileKey, ProfileKey profileKey,
final TrustNewIdentity trustNewIdentity final Settings settings
) throws IOException { ) throws IOException {
IOUtils.createPrivateDirectories(dataPath); IOUtils.createPrivateDirectories(dataPath);
var fileName = getFileName(dataPath, accountPath); var fileName = getFileName(dataPath, accountPath);
@ -221,7 +221,7 @@ public class SignalAccount implements Closeable {
signalAccount.pniIdentityKeyPair = pniIdentityKey; signalAccount.pniIdentityKeyPair = pniIdentityKey;
signalAccount.localRegistrationId = registrationId; signalAccount.localRegistrationId = registrationId;
signalAccount.localPniRegistrationId = pniRegistrationId; signalAccount.localPniRegistrationId = pniRegistrationId;
signalAccount.trustNewIdentity = trustNewIdentity; signalAccount.settings = settings;
signalAccount.configurationStore = new ConfigurationStore(signalAccount::saveConfigurationStore); signalAccount.configurationStore = new ConfigurationStore(signalAccount::saveConfigurationStore);
signalAccount.registered = false; signalAccount.registered = false;
@ -248,7 +248,7 @@ public class SignalAccount implements Closeable {
int registrationId, int registrationId,
int pniRegistrationId, int pniRegistrationId,
ProfileKey profileKey, ProfileKey profileKey,
final TrustNewIdentity trustNewIdentity final Settings settings
) throws IOException { ) throws IOException {
IOUtils.createPrivateDirectories(dataPath); IOUtils.createPrivateDirectories(dataPath);
var fileName = getFileName(dataPath, accountPath); var fileName = getFileName(dataPath, accountPath);
@ -267,10 +267,10 @@ public class SignalAccount implements Closeable {
registrationId, registrationId,
pniRegistrationId, pniRegistrationId,
profileKey, profileKey,
trustNewIdentity); settings);
} }
final var signalAccount = load(dataPath, accountPath, true, trustNewIdentity); final var signalAccount = load(dataPath, accountPath, true, settings);
signalAccount.setProvisioningData(number, signalAccount.setProvisioningData(number,
aci, aci,
pni, pni,
@ -318,7 +318,7 @@ public class SignalAccount implements Closeable {
int registrationId, int registrationId,
int pniRegistrationId, int pniRegistrationId,
ProfileKey profileKey, ProfileKey profileKey,
final TrustNewIdentity trustNewIdentity final Settings settings
) throws IOException { ) throws IOException {
var fileName = getFileName(dataPath, accountPath); var fileName = getFileName(dataPath, accountPath);
IOUtils.createPrivateFile(fileName); IOUtils.createPrivateFile(fileName);
@ -331,7 +331,7 @@ public class SignalAccount implements Closeable {
signalAccount.serviceEnvironment = serviceEnvironment; signalAccount.serviceEnvironment = serviceEnvironment;
signalAccount.localRegistrationId = registrationId; signalAccount.localRegistrationId = registrationId;
signalAccount.localPniRegistrationId = pniRegistrationId; signalAccount.localPniRegistrationId = pniRegistrationId;
signalAccount.trustNewIdentity = trustNewIdentity; signalAccount.settings = settings;
signalAccount.setProvisioningData(number, signalAccount.setProvisioningData(number,
aci, aci,
pni, pni,
@ -502,7 +502,7 @@ public class SignalAccount implements Closeable {
} }
private void load( private void load(
File dataPath, String accountPath, final TrustNewIdentity trustNewIdentity File dataPath, String accountPath, final Settings settings
) throws IOException { ) throws IOException {
this.dataPath = dataPath; this.dataPath = dataPath;
this.accountPath = accountPath; this.accountPath = accountPath;
@ -685,7 +685,7 @@ public class SignalAccount implements Closeable {
this.aciIdentityKeyPair = aciIdentityKeyPair; this.aciIdentityKeyPair = aciIdentityKeyPair;
this.localRegistrationId = registrationId; this.localRegistrationId = registrationId;
this.trustNewIdentity = trustNewIdentity; this.settings = settings;
migratedLegacyConfig = loadLegacyStores(rootNode, legacySignalProtocolStore) || migratedLegacyConfig; migratedLegacyConfig = loadLegacyStores(rootNode, legacySignalProtocolStore) || migratedLegacyConfig;
@ -1156,7 +1156,7 @@ public class SignalAccount implements Closeable {
public IdentityKeyStore getIdentityKeyStore() { public IdentityKeyStore getIdentityKeyStore() {
return getOrCreate(() -> identityKeyStore, return getOrCreate(() -> identityKeyStore,
() -> identityKeyStore = new IdentityKeyStore(getAccountDatabase(), trustNewIdentity)); () -> identityKeyStore = new IdentityKeyStore(getAccountDatabase(), settings.trustNewIdentity()));
} }
public SignalIdentityKeyStore getAciIdentityKeyStore() { public SignalIdentityKeyStore getAciIdentityKeyStore() {
@ -1242,7 +1242,8 @@ public class SignalAccount implements Closeable {
public MessageSendLogStore getMessageSendLogStore() { public MessageSendLogStore getMessageSendLogStore() {
return getOrCreate(() -> messageSendLogStore, return getOrCreate(() -> messageSendLogStore,
() -> messageSendLogStore = new MessageSendLogStore(getAccountDatabase())); () -> messageSendLogStore = new MessageSendLogStore(getAccountDatabase(),
settings.disableMessageSendLog()));
} }
public CredentialsProvider getCredentialsProvider() { public CredentialsProvider getCredentialsProvider() {

View file

@ -33,9 +33,11 @@ public class MessageSendLogStore implements AutoCloseable {
private final Database database; private final Database database;
private final Thread cleanupThread; private final Thread cleanupThread;
private final boolean sendLogDisabled;
public MessageSendLogStore(final Database database) { public MessageSendLogStore(final Database database, final boolean disableMessageSendLog) {
this.database = database; this.database = database;
this.sendLogDisabled = disableMessageSendLog;
this.cleanupThread = new Thread(() -> { this.cleanupThread = new Thread(() -> {
try { try {
final var interval = Duration.ofHours(1).toMillis(); final var interval = Duration.ofHours(1).toMillis();
@ -43,6 +45,7 @@ public class MessageSendLogStore implements AutoCloseable {
try (final var connection = database.getConnection()) { try (final var connection = database.getConnection()) {
deleteOutdatedEntries(connection); deleteOutdatedEntries(connection);
} catch (SQLException e) { } catch (SQLException e) {
logger.debug("MSL", e);
logger.warn("Deleting outdated entries failed"); logger.warn("Deleting outdated entries failed");
break; break;
} }
@ -113,6 +116,9 @@ public class MessageSendLogStore implements AutoCloseable {
public long insertIfPossible( public long insertIfPossible(
long sentTimestamp, SendMessageResult sendMessageResult, ContentHint contentHint, boolean urgent long sentTimestamp, SendMessageResult sendMessageResult, ContentHint contentHint, boolean urgent
) { ) {
if (sendLogDisabled) {
return -1;
}
final RecipientDevices recipientDevice = getRecipientDevices(sendMessageResult); final RecipientDevices recipientDevice = getRecipientDevices(sendMessageResult);
if (recipientDevice == null) { if (recipientDevice == null) {
return -1; return -1;
@ -128,6 +134,9 @@ public class MessageSendLogStore implements AutoCloseable {
public long insertIfPossible( public long insertIfPossible(
long sentTimestamp, List<SendMessageResult> sendMessageResults, ContentHint contentHint, boolean urgent long sentTimestamp, List<SendMessageResult> sendMessageResults, ContentHint contentHint, boolean urgent
) { ) {
if (sendLogDisabled) {
return -1;
}
final var recipientDevices = sendMessageResults.stream() final var recipientDevices = sendMessageResults.stream()
.map(this::getRecipientDevices) .map(this::getRecipientDevices)
.filter(Objects::nonNull) .filter(Objects::nonNull)
@ -146,6 +155,9 @@ public class MessageSendLogStore implements AutoCloseable {
} }
public void addRecipientToExistingEntryIfPossible(final long contentId, final SendMessageResult sendMessageResult) { public void addRecipientToExistingEntryIfPossible(final long contentId, final SendMessageResult sendMessageResult) {
if (sendLogDisabled) {
return;
}
final RecipientDevices recipientDevice = getRecipientDevices(sendMessageResult); final RecipientDevices recipientDevice = getRecipientDevices(sendMessageResult);
if (recipientDevice == null) { if (recipientDevice == null) {
return; return;
@ -157,6 +169,9 @@ public class MessageSendLogStore implements AutoCloseable {
public void addRecipientToExistingEntryIfPossible( public void addRecipientToExistingEntryIfPossible(
final long contentId, final List<SendMessageResult> sendMessageResults final long contentId, final List<SendMessageResult> sendMessageResults
) { ) {
if (sendLogDisabled) {
return;
}
final var recipientDevices = sendMessageResults.stream() final var recipientDevices = sendMessageResults.stream()
.map(this::getRecipientDevices) .map(this::getRecipientDevices)
.filter(Objects::nonNull) .filter(Objects::nonNull)

View file

@ -79,6 +79,9 @@ Choose when to trust new identities:
- `always`: Trust any new identity key without verification - `always`: Trust any new identity key without verification
- `never`: Don't trust any unknown identity key, every key must be verified manually - `never`: Don't trust any unknown identity key, every key must be verified manually
*--disable-send-log*::
Disable message send log (for resending messages that recipient couldn't decrypt).
== Commands == Commands
=== register === register

View file

@ -23,6 +23,7 @@ import org.asamk.signal.dbus.DbusProvisioningManagerImpl;
import org.asamk.signal.dbus.DbusRegistrationManagerImpl; import org.asamk.signal.dbus.DbusRegistrationManagerImpl;
import org.asamk.signal.manager.Manager; import org.asamk.signal.manager.Manager;
import org.asamk.signal.manager.RegistrationManager; import org.asamk.signal.manager.RegistrationManager;
import org.asamk.signal.manager.Settings;
import org.asamk.signal.manager.SignalAccountFiles; import org.asamk.signal.manager.SignalAccountFiles;
import org.asamk.signal.manager.api.AccountCheckException; import org.asamk.signal.manager.api.AccountCheckException;
import org.asamk.signal.manager.api.NotRegisteredException; import org.asamk.signal.manager.api.NotRegisteredException;
@ -101,6 +102,10 @@ public class App {
.type(Arguments.enumStringType(TrustNewIdentityCli.class)) .type(Arguments.enumStringType(TrustNewIdentityCli.class))
.setDefault(TrustNewIdentityCli.ON_FIRST_USE); .setDefault(TrustNewIdentityCli.ON_FIRST_USE);
parser.addArgument("--disable-send-log")
.help("Disable message send log (for resending messages that recipient couldn't decrypt)")
.action(Arguments.storeTrue());
var subparsers = parser.addSubparsers().title("subcommands").dest("command"); var subparsers = parser.addSubparsers().title("subcommands").dest("command");
Commands.getCommandSubparserAttachers().forEach((key, value) -> { Commands.getCommandSubparserAttachers().forEach((key, value) -> {
@ -167,12 +172,14 @@ public class App {
? TrustNewIdentity.ON_FIRST_USE ? TrustNewIdentity.ON_FIRST_USE
: trustNewIdentityCli == TrustNewIdentityCli.ALWAYS ? TrustNewIdentity.ALWAYS : TrustNewIdentity.NEVER; : trustNewIdentityCli == TrustNewIdentityCli.ALWAYS ? TrustNewIdentity.ALWAYS : TrustNewIdentity.NEVER;
final var disableSendLog = Boolean.TRUE.equals(ns.getBoolean("disable-send-log"));
final SignalAccountFiles signalAccountFiles; final SignalAccountFiles signalAccountFiles;
try { try {
signalAccountFiles = new SignalAccountFiles(configPath, signalAccountFiles = new SignalAccountFiles(configPath,
serviceEnvironment, serviceEnvironment,
BaseConfig.USER_AGENT, BaseConfig.USER_AGENT,
trustNewIdentity); new Settings(trustNewIdentity, disableSendLog));
} catch (IOException e) { } catch (IOException e) {
throw new IOErrorException("Failed to read local accounts list", e); throw new IOErrorException("Failed to read local accounts list", e);
} }