mirror of
https://github.com/AsamK/signal-cli
synced 2025-08-29 18:40:39 +00:00
Refactor creating linked account files
This commit is contained in:
parent
dd3326f038
commit
400dcf2899
3 changed files with 64 additions and 140 deletions
|
@ -14,7 +14,6 @@ import org.asamk.signal.manager.internal.RegistrationManagerImpl;
|
||||||
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.util.KeyUtils;
|
import org.asamk.signal.manager.util.KeyUtils;
|
||||||
import org.signal.libsignal.protocol.util.KeyHelper;
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.whispersystems.signalservice.api.push.exceptions.DeprecatedVersionException;
|
import org.whispersystems.signalservice.api.push.exceptions.DeprecatedVersionException;
|
||||||
|
@ -160,8 +159,6 @@ public class SignalAccountFiles {
|
||||||
final var newAccountPath = accountPath == null ? accountsStore.addAccount(number, null) : accountPath;
|
final var newAccountPath = accountPath == null ? accountsStore.addAccount(number, null) : accountPath;
|
||||||
var aciIdentityKey = KeyUtils.generateIdentityKeyPair();
|
var aciIdentityKey = KeyUtils.generateIdentityKeyPair();
|
||||||
var pniIdentityKey = KeyUtils.generateIdentityKeyPair();
|
var pniIdentityKey = KeyUtils.generateIdentityKeyPair();
|
||||||
var registrationId = KeyHelper.generateRegistrationId(false);
|
|
||||||
var pniRegistrationId = KeyHelper.generateRegistrationId(false);
|
|
||||||
|
|
||||||
var profileKey = KeyUtils.createProfileKey();
|
var profileKey = KeyUtils.createProfileKey();
|
||||||
var account = SignalAccount.create(pathConfig.dataPath(),
|
var account = SignalAccount.create(pathConfig.dataPath(),
|
||||||
|
@ -170,8 +167,6 @@ public class SignalAccountFiles {
|
||||||
serviceEnvironment,
|
serviceEnvironment,
|
||||||
aciIdentityKey,
|
aciIdentityKey,
|
||||||
pniIdentityKey,
|
pniIdentityKey,
|
||||||
registrationId,
|
|
||||||
pniRegistrationId,
|
|
||||||
profileKey,
|
profileKey,
|
||||||
settings);
|
settings);
|
||||||
|
|
||||||
|
|
|
@ -27,12 +27,12 @@ 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.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.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.whispersystems.signalservice.api.SignalServiceAccountManager;
|
import org.whispersystems.signalservice.api.SignalServiceAccountManager;
|
||||||
import org.whispersystems.signalservice.api.groupsv2.ClientZkOperations;
|
import org.whispersystems.signalservice.api.groupsv2.ClientZkOperations;
|
||||||
import org.whispersystems.signalservice.api.groupsv2.GroupsV2Operations;
|
import org.whispersystems.signalservice.api.groupsv2.GroupsV2Operations;
|
||||||
|
import org.whispersystems.signalservice.api.push.ServiceIdType;
|
||||||
import org.whispersystems.signalservice.api.push.SignalServiceAddress;
|
import org.whispersystems.signalservice.api.push.SignalServiceAddress;
|
||||||
import org.whispersystems.signalservice.api.push.exceptions.AuthorizationFailedException;
|
import org.whispersystems.signalservice.api.push.exceptions.AuthorizationFailedException;
|
||||||
import org.whispersystems.signalservice.api.util.DeviceNameUtil;
|
import org.whispersystems.signalservice.api.util.DeviceNameUtil;
|
||||||
|
@ -59,8 +59,6 @@ public class ProvisioningManagerImpl implements ProvisioningManager {
|
||||||
|
|
||||||
private final SignalServiceAccountManager accountManager;
|
private final SignalServiceAccountManager accountManager;
|
||||||
private final IdentityKeyPair tempIdentityKey;
|
private final IdentityKeyPair tempIdentityKey;
|
||||||
private final int registrationId;
|
|
||||||
private final int pniRegistrationId;
|
|
||||||
private final String password;
|
private final String password;
|
||||||
|
|
||||||
public ProvisioningManagerImpl(
|
public ProvisioningManagerImpl(
|
||||||
|
@ -77,8 +75,6 @@ public class ProvisioningManagerImpl implements ProvisioningManager {
|
||||||
this.accountsStore = accountsStore;
|
this.accountsStore = accountsStore;
|
||||||
|
|
||||||
tempIdentityKey = KeyUtils.generateIdentityKeyPair();
|
tempIdentityKey = KeyUtils.generateIdentityKeyPair();
|
||||||
registrationId = KeyHelper.generateRegistrationId(false);
|
|
||||||
pniRegistrationId = KeyHelper.generateRegistrationId(false);
|
|
||||||
password = KeyUtils.createPassword();
|
password = KeyUtils.createPassword();
|
||||||
GroupsV2Operations groupsV2Operations;
|
GroupsV2Operations groupsV2Operations;
|
||||||
try {
|
try {
|
||||||
|
@ -114,9 +110,9 @@ public class ProvisioningManagerImpl implements ProvisioningManager {
|
||||||
if (accountPath == null) {
|
if (accountPath == null) {
|
||||||
accountPath = accountsStore.getPathByNumber(number);
|
accountPath = accountsStore.getPathByNumber(number);
|
||||||
}
|
}
|
||||||
if (accountPath != null
|
final var accountExists = accountPath != null && SignalAccount.accountFileExists(pathConfig.dataPath(),
|
||||||
&& SignalAccount.accountFileExists(pathConfig.dataPath(), accountPath)
|
accountPath);
|
||||||
&& !canRelinkExistingAccount(accountPath)) {
|
if (accountExists && !canRelinkExistingAccount(accountPath)) {
|
||||||
throw new UserAlreadyExistsException(number, SignalAccount.getFileName(pathConfig.dataPath(), accountPath));
|
throw new UserAlreadyExistsException(number, SignalAccount.getFileName(pathConfig.dataPath(), accountPath));
|
||||||
}
|
}
|
||||||
if (accountPath == null) {
|
if (accountPath == null) {
|
||||||
|
@ -128,38 +124,42 @@ public class ProvisioningManagerImpl implements ProvisioningManager {
|
||||||
var encryptedDeviceName = deviceName == null
|
var encryptedDeviceName = deviceName == null
|
||||||
? null
|
? null
|
||||||
: DeviceNameUtil.encryptDeviceName(deviceName, ret.getAciIdentity().getPrivateKey());
|
: DeviceNameUtil.encryptDeviceName(deviceName, ret.getAciIdentity().getPrivateKey());
|
||||||
|
|
||||||
logger.debug("Finishing new device registration");
|
|
||||||
var deviceId = accountManager.finishNewDeviceRegistration(ret.getProvisioningCode(),
|
|
||||||
new ConfirmCodeMessage(false,
|
|
||||||
true,
|
|
||||||
registrationId,
|
|
||||||
pniRegistrationId,
|
|
||||||
encryptedDeviceName,
|
|
||||||
getCapabilities(false)));
|
|
||||||
|
|
||||||
// Create new account with the synced identity
|
// Create new account with the synced identity
|
||||||
var profileKey = ret.getProfileKey() == null ? KeyUtils.createProfileKey() : ret.getProfileKey();
|
var profileKey = ret.getProfileKey() == null ? KeyUtils.createProfileKey() : ret.getProfileKey();
|
||||||
|
|
||||||
SignalAccount account = null;
|
SignalAccount account = null;
|
||||||
try {
|
try {
|
||||||
account = SignalAccount.createOrUpdateLinkedAccount(pathConfig.dataPath(),
|
if (!accountExists) {
|
||||||
|
account = SignalAccount.createLinkedAccount(pathConfig.dataPath(),
|
||||||
accountPath,
|
accountPath,
|
||||||
number,
|
|
||||||
serviceEnvironmentConfig.type(),
|
serviceEnvironmentConfig.type(),
|
||||||
|
Settings.DEFAULT);
|
||||||
|
} else {
|
||||||
|
account = SignalAccount.load(pathConfig.dataPath(), accountPath, true, Settings.DEFAULT);
|
||||||
|
}
|
||||||
|
|
||||||
|
account.setProvisioningData(number,
|
||||||
aci,
|
aci,
|
||||||
pni,
|
pni,
|
||||||
password,
|
password,
|
||||||
encryptedDeviceName,
|
encryptedDeviceName,
|
||||||
deviceId,
|
|
||||||
ret.getAciIdentity(),
|
ret.getAciIdentity(),
|
||||||
ret.getPniIdentity(),
|
ret.getPniIdentity(),
|
||||||
registrationId,
|
profileKey);
|
||||||
pniRegistrationId,
|
|
||||||
profileKey,
|
|
||||||
Settings.DEFAULT);
|
|
||||||
account.getConfigurationStore().setReadReceipts(ret.isReadReceipts());
|
account.getConfigurationStore().setReadReceipts(ret.isReadReceipts());
|
||||||
|
|
||||||
|
logger.debug("Finishing new device registration");
|
||||||
|
var deviceId = accountManager.finishNewDeviceRegistration(ret.getProvisioningCode(),
|
||||||
|
new ConfirmCodeMessage(false,
|
||||||
|
true,
|
||||||
|
account.getAccountData(ServiceIdType.ACI).getLocalRegistrationId(),
|
||||||
|
account.getAccountData(ServiceIdType.PNI).getLocalRegistrationId(),
|
||||||
|
encryptedDeviceName,
|
||||||
|
getCapabilities(false)));
|
||||||
|
|
||||||
|
account.finishLinking(deviceId);
|
||||||
|
|
||||||
ManagerImpl m = null;
|
ManagerImpl m = null;
|
||||||
try {
|
try {
|
||||||
m = new ManagerImpl(account,
|
m = new ManagerImpl(account,
|
||||||
|
|
|
@ -130,7 +130,7 @@ public class SignalAccount implements Closeable {
|
||||||
private String number;
|
private String number;
|
||||||
private String username;
|
private String username;
|
||||||
private String encryptedDeviceName;
|
private String encryptedDeviceName;
|
||||||
private int deviceId = SignalServiceAddress.DEFAULT_DEVICE_ID;
|
private int deviceId = 0;
|
||||||
private String password;
|
private String password;
|
||||||
private String registrationLockPin;
|
private String registrationLockPin;
|
||||||
private MasterKey pinMasterKey;
|
private MasterKey pinMasterKey;
|
||||||
|
@ -204,8 +204,6 @@ public class SignalAccount implements Closeable {
|
||||||
ServiceEnvironment serviceEnvironment,
|
ServiceEnvironment serviceEnvironment,
|
||||||
IdentityKeyPair aciIdentityKey,
|
IdentityKeyPair aciIdentityKey,
|
||||||
IdentityKeyPair pniIdentityKey,
|
IdentityKeyPair pniIdentityKey,
|
||||||
int registrationId,
|
|
||||||
int pniRegistrationId,
|
|
||||||
ProfileKey profileKey,
|
ProfileKey profileKey,
|
||||||
final Settings settings
|
final Settings settings
|
||||||
) throws IOException {
|
) throws IOException {
|
||||||
|
@ -223,160 +221,91 @@ public class SignalAccount implements Closeable {
|
||||||
signalAccount.serviceEnvironment = serviceEnvironment;
|
signalAccount.serviceEnvironment = serviceEnvironment;
|
||||||
signalAccount.profileKey = profileKey;
|
signalAccount.profileKey = profileKey;
|
||||||
signalAccount.password = KeyUtils.createPassword();
|
signalAccount.password = KeyUtils.createPassword();
|
||||||
|
signalAccount.deviceId = SignalServiceAddress.DEFAULT_DEVICE_ID;
|
||||||
|
|
||||||
signalAccount.dataPath = dataPath;
|
signalAccount.dataPath = dataPath;
|
||||||
signalAccount.aciAccountData.setIdentityKeyPair(aciIdentityKey);
|
signalAccount.aciAccountData.setIdentityKeyPair(aciIdentityKey);
|
||||||
signalAccount.pniAccountData.setIdentityKeyPair(pniIdentityKey);
|
signalAccount.pniAccountData.setIdentityKeyPair(pniIdentityKey);
|
||||||
signalAccount.aciAccountData.setLocalRegistrationId(registrationId);
|
signalAccount.aciAccountData.setLocalRegistrationId(KeyHelper.generateRegistrationId(false));
|
||||||
signalAccount.pniAccountData.setLocalRegistrationId(pniRegistrationId);
|
signalAccount.pniAccountData.setLocalRegistrationId(KeyHelper.generateRegistrationId(false));
|
||||||
signalAccount.settings = settings;
|
signalAccount.settings = settings;
|
||||||
|
|
||||||
signalAccount.registered = false;
|
signalAccount.registered = false;
|
||||||
|
|
||||||
signalAccount.previousStorageVersion = CURRENT_STORAGE_VERSION;
|
signalAccount.previousStorageVersion = CURRENT_STORAGE_VERSION;
|
||||||
signalAccount.migrateLegacyConfigs();
|
signalAccount.migrateLegacyConfigs();
|
||||||
signalAccount.clearAllPreKeys();
|
|
||||||
signalAccount.save();
|
signalAccount.save();
|
||||||
|
|
||||||
return signalAccount;
|
return signalAccount;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static SignalAccount createLinkedAccount(
|
public static SignalAccount createLinkedAccount(
|
||||||
File dataPath,
|
final File dataPath,
|
||||||
String accountPath,
|
final String accountPath,
|
||||||
String number,
|
final ServiceEnvironment serviceEnvironment,
|
||||||
ServiceEnvironment serviceEnvironment,
|
|
||||||
ACI aci,
|
|
||||||
PNI pni,
|
|
||||||
String password,
|
|
||||||
String encryptedDeviceName,
|
|
||||||
int deviceId,
|
|
||||||
IdentityKeyPair aciIdentityKey,
|
|
||||||
IdentityKeyPair pniIdentityKey,
|
|
||||||
int registrationId,
|
|
||||||
int pniRegistrationId,
|
|
||||||
ProfileKey profileKey,
|
|
||||||
final Settings settings
|
|
||||||
) throws IOException {
|
|
||||||
var fileName = getFileName(dataPath, accountPath);
|
|
||||||
IOUtils.createPrivateFile(fileName);
|
|
||||||
|
|
||||||
final var pair = openFileChannel(fileName, true);
|
|
||||||
var signalAccount = new SignalAccount(pair.first(), pair.second());
|
|
||||||
|
|
||||||
signalAccount.dataPath = dataPath;
|
|
||||||
signalAccount.accountPath = accountPath;
|
|
||||||
signalAccount.serviceEnvironment = serviceEnvironment;
|
|
||||||
signalAccount.aciAccountData.setLocalRegistrationId(registrationId);
|
|
||||||
signalAccount.pniAccountData.setLocalRegistrationId(pniRegistrationId);
|
|
||||||
signalAccount.settings = settings;
|
|
||||||
signalAccount.setProvisioningData(number,
|
|
||||||
aci,
|
|
||||||
pni,
|
|
||||||
password,
|
|
||||||
encryptedDeviceName,
|
|
||||||
deviceId,
|
|
||||||
aciIdentityKey,
|
|
||||||
pniIdentityKey,
|
|
||||||
profileKey);
|
|
||||||
|
|
||||||
signalAccount.getRecipientTrustedResolver()
|
|
||||||
.resolveSelfRecipientTrusted(signalAccount.getSelfRecipientAddress());
|
|
||||||
signalAccount.previousStorageVersion = CURRENT_STORAGE_VERSION;
|
|
||||||
signalAccount.migrateLegacyConfigs();
|
|
||||||
signalAccount.clearAllPreKeys();
|
|
||||||
signalAccount.save();
|
|
||||||
|
|
||||||
return signalAccount;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static SignalAccount createOrUpdateLinkedAccount(
|
|
||||||
File dataPath,
|
|
||||||
String accountPath,
|
|
||||||
String number,
|
|
||||||
ServiceEnvironment serviceEnvironment,
|
|
||||||
ACI aci,
|
|
||||||
PNI pni,
|
|
||||||
String password,
|
|
||||||
String encryptedDeviceName,
|
|
||||||
int deviceId,
|
|
||||||
IdentityKeyPair aciIdentityKey,
|
|
||||||
IdentityKeyPair pniIdentityKey,
|
|
||||||
int registrationId,
|
|
||||||
int pniRegistrationId,
|
|
||||||
ProfileKey profileKey,
|
|
||||||
final Settings settings
|
final Settings settings
|
||||||
) throws IOException {
|
) throws IOException {
|
||||||
IOUtils.createPrivateDirectories(dataPath);
|
IOUtils.createPrivateDirectories(dataPath);
|
||||||
var fileName = getFileName(dataPath, accountPath);
|
var fileName = getFileName(dataPath, accountPath);
|
||||||
if (!fileName.exists()) {
|
IOUtils.createPrivateFile(fileName);
|
||||||
return createLinkedAccount(dataPath,
|
|
||||||
accountPath,
|
final var pair = openFileChannel(fileName, true);
|
||||||
number,
|
final var signalAccount = new SignalAccount(pair.first(), pair.second());
|
||||||
serviceEnvironment,
|
|
||||||
aci,
|
signalAccount.dataPath = dataPath;
|
||||||
pni,
|
signalAccount.accountPath = accountPath;
|
||||||
password,
|
signalAccount.serviceEnvironment = serviceEnvironment;
|
||||||
encryptedDeviceName,
|
signalAccount.aciAccountData.setLocalRegistrationId(KeyHelper.generateRegistrationId(false));
|
||||||
deviceId,
|
signalAccount.pniAccountData.setLocalRegistrationId(KeyHelper.generateRegistrationId(false));
|
||||||
aciIdentityKey,
|
signalAccount.settings = settings;
|
||||||
pniIdentityKey,
|
|
||||||
registrationId,
|
signalAccount.previousStorageVersion = CURRENT_STORAGE_VERSION;
|
||||||
pniRegistrationId,
|
|
||||||
profileKey,
|
|
||||||
settings);
|
|
||||||
}
|
|
||||||
|
|
||||||
final var signalAccount = load(dataPath, accountPath, true, settings);
|
|
||||||
signalAccount.setProvisioningData(number,
|
|
||||||
aci,
|
|
||||||
pni,
|
|
||||||
password,
|
|
||||||
encryptedDeviceName,
|
|
||||||
deviceId,
|
|
||||||
aciIdentityKey,
|
|
||||||
pniIdentityKey,
|
|
||||||
profileKey);
|
|
||||||
signalAccount.getRecipientTrustedResolver()
|
|
||||||
.resolveSelfRecipientTrusted(signalAccount.getSelfRecipientAddress());
|
|
||||||
signalAccount.aciAccountData.getSessionStore().archiveAllSessions();
|
|
||||||
signalAccount.pniAccountData.getSessionStore().archiveAllSessions();
|
|
||||||
signalAccount.getSenderKeyStore().deleteAll();
|
|
||||||
signalAccount.clearAllPreKeys();
|
|
||||||
return signalAccount;
|
return signalAccount;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setProvisioningData(
|
public void setProvisioningData(
|
||||||
final String number,
|
final String number,
|
||||||
final ACI aci,
|
final ACI aci,
|
||||||
final PNI pni,
|
final PNI pni,
|
||||||
final String password,
|
final String password,
|
||||||
final String encryptedDeviceName,
|
final String encryptedDeviceName,
|
||||||
final int deviceId,
|
|
||||||
final IdentityKeyPair aciIdentity,
|
final IdentityKeyPair aciIdentity,
|
||||||
final IdentityKeyPair pniIdentity,
|
final IdentityKeyPair pniIdentity,
|
||||||
final ProfileKey profileKey
|
final ProfileKey profileKey
|
||||||
) {
|
) {
|
||||||
|
this.deviceId = 0;
|
||||||
this.number = number;
|
this.number = number;
|
||||||
this.aciAccountData.setServiceId(aci);
|
this.aciAccountData.setServiceId(aci);
|
||||||
this.pniAccountData.setServiceId(pni);
|
this.pniAccountData.setServiceId(pni);
|
||||||
|
getRecipientTrustedResolver().resolveSelfRecipientTrusted(getSelfRecipientAddress());
|
||||||
this.password = password;
|
this.password = password;
|
||||||
this.profileKey = profileKey;
|
this.profileKey = profileKey;
|
||||||
getProfileStore().storeSelfProfileKey(getSelfRecipientId(), getProfileKey());
|
getProfileStore().storeSelfProfileKey(getSelfRecipientId(), getProfileKey());
|
||||||
this.encryptedDeviceName = encryptedDeviceName;
|
this.encryptedDeviceName = encryptedDeviceName;
|
||||||
this.deviceId = deviceId;
|
|
||||||
this.aciAccountData.setIdentityKeyPair(aciIdentity);
|
this.aciAccountData.setIdentityKeyPair(aciIdentity);
|
||||||
this.pniAccountData.setIdentityKeyPair(pniIdentity);
|
this.pniAccountData.setIdentityKeyPair(pniIdentity);
|
||||||
this.registered = true;
|
this.registered = false;
|
||||||
this.isMultiDevice = true;
|
this.isMultiDevice = true;
|
||||||
getKeyValueStore().storeEntry(lastReceiveTimestamp, 0L);
|
getKeyValueStore().storeEntry(lastReceiveTimestamp, 0L);
|
||||||
this.pinMasterKey = null;
|
this.pinMasterKey = null;
|
||||||
getKeyValueStore().storeEntry(storageManifestVersion, -1L);
|
getKeyValueStore().storeEntry(storageManifestVersion, -1L);
|
||||||
this.setStorageManifest(null);
|
this.setStorageManifest(null);
|
||||||
this.storageKey = null;
|
this.storageKey = null;
|
||||||
|
getSenderKeyStore().deleteAll();
|
||||||
trustSelfIdentity(ServiceIdType.ACI);
|
trustSelfIdentity(ServiceIdType.ACI);
|
||||||
trustSelfIdentity(ServiceIdType.PNI);
|
trustSelfIdentity(ServiceIdType.PNI);
|
||||||
|
aciAccountData.getSessionStore().archiveAllSessions();
|
||||||
|
pniAccountData.getSessionStore().archiveAllSessions();
|
||||||
|
clearAllPreKeys();
|
||||||
getKeyValueStore().storeEntry(lastRecipientsRefresh, null);
|
getKeyValueStore().storeEntry(lastRecipientsRefresh, null);
|
||||||
|
save();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void finishLinking(final int deviceId) {
|
||||||
|
this.registered = true;
|
||||||
|
this.deviceId = deviceId;
|
||||||
|
save();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void finishRegistration(
|
public void finishRegistration(
|
||||||
|
@ -476,7 +405,7 @@ public class SignalAccount implements Closeable {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
var f = getFileName(dataPath, account);
|
var f = getFileName(dataPath, account);
|
||||||
return !(!f.exists() || f.isDirectory());
|
return f.exists() && !f.isDirectory() && f.length() > 0L;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void load(
|
private void load(
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue