mirror of
https://github.com/AsamK/signal-cli
synced 2025-08-29 10:30:38 +00:00
Handle PniChangeNumber
This commit is contained in:
parent
94d79692df
commit
45a5795c9c
7 changed files with 89 additions and 9 deletions
|
@ -14,7 +14,7 @@ repositories {
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation("com.github.turasa", "signal-service-java", "2.15.3_unofficial_61")
|
implementation("com.github.turasa", "signal-service-java", "2.15.3_unofficial_62")
|
||||||
implementation("com.fasterxml.jackson.core", "jackson-databind", "2.13.4")
|
implementation("com.fasterxml.jackson.core", "jackson-databind", "2.13.4")
|
||||||
implementation("com.google.protobuf", "protobuf-javalite", "3.21.6")
|
implementation("com.google.protobuf", "protobuf-javalite", "3.21.6")
|
||||||
implementation("org.bouncycastle", "bcprov-jdk15on", "1.70")
|
implementation("org.bouncycastle", "bcprov-jdk15on", "1.70")
|
||||||
|
|
|
@ -11,12 +11,15 @@ import org.asamk.signal.manager.config.ServiceConfig;
|
||||||
import org.asamk.signal.manager.storage.SignalAccount;
|
import org.asamk.signal.manager.storage.SignalAccount;
|
||||||
import org.asamk.signal.manager.util.KeyUtils;
|
import org.asamk.signal.manager.util.KeyUtils;
|
||||||
import org.asamk.signal.manager.util.NumberVerificationUtils;
|
import org.asamk.signal.manager.util.NumberVerificationUtils;
|
||||||
|
import org.signal.libsignal.protocol.IdentityKeyPair;
|
||||||
import org.signal.libsignal.protocol.InvalidKeyException;
|
import org.signal.libsignal.protocol.InvalidKeyException;
|
||||||
|
import org.signal.libsignal.protocol.state.SignedPreKeyRecord;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.whispersystems.signalservice.api.account.ChangePhoneNumberRequest;
|
import org.whispersystems.signalservice.api.account.ChangePhoneNumberRequest;
|
||||||
import org.whispersystems.signalservice.api.push.ACI;
|
import org.whispersystems.signalservice.api.push.ACI;
|
||||||
import org.whispersystems.signalservice.api.push.PNI;
|
import org.whispersystems.signalservice.api.push.PNI;
|
||||||
|
import org.whispersystems.signalservice.api.push.ServiceIdType;
|
||||||
import org.whispersystems.signalservice.api.push.SignedPreKeyEntity;
|
import org.whispersystems.signalservice.api.push.SignedPreKeyEntity;
|
||||||
import org.whispersystems.signalservice.api.push.exceptions.AuthorizationFailedException;
|
import org.whispersystems.signalservice.api.push.exceptions.AuthorizationFailedException;
|
||||||
import org.whispersystems.signalservice.api.push.exceptions.DeprecatedVersionException;
|
import org.whispersystems.signalservice.api.push.exceptions.DeprecatedVersionException;
|
||||||
|
@ -111,6 +114,19 @@ public class AccountHelper {
|
||||||
context.getAccountFileUpdater().updateAccountIdentifiers(account.getNumber(), account.getAci());
|
context.getAccountFileUpdater().updateAccountIdentifiers(account.getNumber(), account.getAci());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setPni(
|
||||||
|
final PNI updatedPni,
|
||||||
|
final IdentityKeyPair pniIdentityKeyPair,
|
||||||
|
final SignedPreKeyRecord pniSignedPreKey,
|
||||||
|
final int localPniRegistrationId
|
||||||
|
) throws IOException {
|
||||||
|
account.setPni(updatedPni, pniIdentityKeyPair, pniSignedPreKey, localPniRegistrationId);
|
||||||
|
context.getPreKeyHelper().refreshPreKeysIfNecessary(ServiceIdType.PNI);
|
||||||
|
if (account.getPni() == null || !account.getPni().equals(updatedPni)) {
|
||||||
|
context.getGroupV2Helper().clearAuthCredentialCache();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void startChangeNumber(
|
public void startChangeNumber(
|
||||||
String newNumber, String captcha, boolean voiceVerification
|
String newNumber, String captcha, boolean voiceVerification
|
||||||
) throws IOException, CaptchaRequiredException, NonNormalizedPhoneNumberException {
|
) throws IOException, CaptchaRequiredException, NonNormalizedPhoneNumberException {
|
||||||
|
|
|
@ -77,6 +77,10 @@ class GroupV2Helper {
|
||||||
this.context = context;
|
this.context = context;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void clearAuthCredentialCache() {
|
||||||
|
groupApiCredentials = null;
|
||||||
|
}
|
||||||
|
|
||||||
DecryptedGroup getDecryptedGroup(final GroupSecretParams groupSecretParams) throws NotAGroupMemberException {
|
DecryptedGroup getDecryptedGroup(final GroupSecretParams groupSecretParams) throws NotAGroupMemberException {
|
||||||
try {
|
try {
|
||||||
final var groupsV2AuthorizationString = getGroupAuthForToday(groupSecretParams);
|
final var groupsV2AuthorizationString = getGroupAuthForToday(groupSecretParams);
|
||||||
|
|
|
@ -42,8 +42,10 @@ import org.signal.libsignal.metadata.ProtocolInvalidMessageException;
|
||||||
import org.signal.libsignal.metadata.ProtocolNoSessionException;
|
import org.signal.libsignal.metadata.ProtocolNoSessionException;
|
||||||
import org.signal.libsignal.metadata.ProtocolUntrustedIdentityException;
|
import org.signal.libsignal.metadata.ProtocolUntrustedIdentityException;
|
||||||
import org.signal.libsignal.metadata.SelfSendException;
|
import org.signal.libsignal.metadata.SelfSendException;
|
||||||
|
import org.signal.libsignal.protocol.IdentityKeyPair;
|
||||||
import org.signal.libsignal.protocol.InvalidMessageException;
|
import org.signal.libsignal.protocol.InvalidMessageException;
|
||||||
import org.signal.libsignal.protocol.message.DecryptionErrorMessage;
|
import org.signal.libsignal.protocol.message.DecryptionErrorMessage;
|
||||||
|
import org.signal.libsignal.protocol.state.SignedPreKeyRecord;
|
||||||
import org.signal.libsignal.zkgroup.InvalidInputException;
|
import org.signal.libsignal.zkgroup.InvalidInputException;
|
||||||
import org.signal.libsignal.zkgroup.profiles.ProfileKey;
|
import org.signal.libsignal.zkgroup.profiles.ProfileKey;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
|
@ -58,6 +60,7 @@ import org.whispersystems.signalservice.api.messages.SignalServiceReceiptMessage
|
||||||
import org.whispersystems.signalservice.api.messages.SignalServiceStoryMessage;
|
import org.whispersystems.signalservice.api.messages.SignalServiceStoryMessage;
|
||||||
import org.whispersystems.signalservice.api.messages.multidevice.SignalServiceSyncMessage;
|
import org.whispersystems.signalservice.api.messages.multidevice.SignalServiceSyncMessage;
|
||||||
import org.whispersystems.signalservice.api.messages.multidevice.StickerPackOperationMessage;
|
import org.whispersystems.signalservice.api.messages.multidevice.StickerPackOperationMessage;
|
||||||
|
import org.whispersystems.signalservice.api.push.PNI;
|
||||||
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;
|
||||||
|
|
||||||
|
@ -304,7 +307,10 @@ public final class IncomingMessageHandler {
|
||||||
|
|
||||||
if (content.getSyncMessage().isPresent()) {
|
if (content.getSyncMessage().isPresent()) {
|
||||||
var syncMessage = content.getSyncMessage().get();
|
var syncMessage = content.getSyncMessage().get();
|
||||||
actions.addAll(handleSyncMessage(syncMessage, senderDeviceAddress, receiveConfig.ignoreAttachments()));
|
actions.addAll(handleSyncMessage(envelope,
|
||||||
|
syncMessage,
|
||||||
|
senderDeviceAddress,
|
||||||
|
receiveConfig.ignoreAttachments()));
|
||||||
}
|
}
|
||||||
|
|
||||||
return actions;
|
return actions;
|
||||||
|
@ -364,7 +370,10 @@ public final class IncomingMessageHandler {
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<HandleAction> handleSyncMessage(
|
private List<HandleAction> handleSyncMessage(
|
||||||
final SignalServiceSyncMessage syncMessage, final DeviceAddress sender, final boolean ignoreAttachments
|
final SignalServiceEnvelope envelope,
|
||||||
|
final SignalServiceSyncMessage syncMessage,
|
||||||
|
final DeviceAddress sender,
|
||||||
|
final boolean ignoreAttachments
|
||||||
) {
|
) {
|
||||||
var actions = new ArrayList<HandleAction>();
|
var actions = new ArrayList<HandleAction>();
|
||||||
account.setMultiDevice(true);
|
account.setMultiDevice(true);
|
||||||
|
@ -519,7 +528,26 @@ public final class IncomingMessageHandler {
|
||||||
pniIdentity.getPrivateKey().toByteArray()));
|
pniIdentity.getPrivateKey().toByteArray()));
|
||||||
actions.add(RefreshPreKeysAction.create());
|
actions.add(RefreshPreKeysAction.create());
|
||||||
}
|
}
|
||||||
// TODO handle PniChangeNumber
|
if (syncMessage.getPniChangeNumber().isPresent()) {
|
||||||
|
final var pniChangeNumber = syncMessage.getPniChangeNumber().get();
|
||||||
|
logger.debug("Received PNI change number sync message, applying.");
|
||||||
|
if (pniChangeNumber.hasIdentityKeyPair()
|
||||||
|
&& pniChangeNumber.hasRegistrationId()
|
||||||
|
&& pniChangeNumber.hasSignedPreKey()
|
||||||
|
&& !envelope.getUpdatedPni().isEmpty()) {
|
||||||
|
logger.debug("New PNI: {}", envelope.getUpdatedPni());
|
||||||
|
try {
|
||||||
|
final var updatedPni = PNI.parseOrThrow(envelope.getUpdatedPni());
|
||||||
|
context.getAccountHelper()
|
||||||
|
.setPni(updatedPni,
|
||||||
|
new IdentityKeyPair(pniChangeNumber.getIdentityKeyPair().toByteArray()),
|
||||||
|
new SignedPreKeyRecord(pniChangeNumber.getSignedPreKey().toByteArray()),
|
||||||
|
pniChangeNumber.getRegistrationId());
|
||||||
|
} catch (Exception e) {
|
||||||
|
logger.warn("Failed to handle change number message", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
return actions;
|
return actions;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -352,7 +352,8 @@ public class SendHelper {
|
||||||
contentHint,
|
contentHint,
|
||||||
message,
|
message,
|
||||||
SignalServiceMessageSender.SenderKeyGroupEvents.EMPTY,
|
SignalServiceMessageSender.SenderKeyGroupEvents.EMPTY,
|
||||||
urgent);
|
urgent,
|
||||||
|
false);
|
||||||
synchronized (entryId) {
|
synchronized (entryId) {
|
||||||
if (entryId.get() == -1) {
|
if (entryId.get() == -1) {
|
||||||
final var newId = messageSendLogStore.insertIfPossible(message.getTimestamp(),
|
final var newId = messageSendLogStore.insertIfPossible(message.getTimestamp(),
|
||||||
|
|
|
@ -1297,11 +1297,31 @@ public class SignalAccount implements Closeable {
|
||||||
return pni;
|
return pni;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setPni(final PNI pni) {
|
public void setPni(final PNI updatedPni) {
|
||||||
this.pni = pni;
|
if (this.pni != null && !this.pni.equals(updatedPni)) {
|
||||||
|
// Clear data for old PNI
|
||||||
|
identityKeyStore.deleteIdentity(this.pni);
|
||||||
|
getPniPreKeyStore().removeAllPreKeys();
|
||||||
|
getPniSignedPreKeyStore().removeAllSignedPreKeys();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.pni = updatedPni;
|
||||||
save();
|
save();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setPni(
|
||||||
|
final PNI updatedPni,
|
||||||
|
final IdentityKeyPair pniIdentityKeyPair,
|
||||||
|
final SignedPreKeyRecord pniSignedPreKey,
|
||||||
|
final int localPniRegistrationId
|
||||||
|
) {
|
||||||
|
setPni(updatedPni);
|
||||||
|
|
||||||
|
setPniIdentityKeyPair(pniIdentityKeyPair);
|
||||||
|
addPniSignedPreKey(pniSignedPreKey);
|
||||||
|
setLocalPniRegistrationId(localPniRegistrationId);
|
||||||
|
}
|
||||||
|
|
||||||
public SignalServiceAddress getSelfAddress() {
|
public SignalServiceAddress getSelfAddress() {
|
||||||
return new SignalServiceAddress(aci, number);
|
return new SignalServiceAddress(aci, number);
|
||||||
}
|
}
|
||||||
|
@ -1359,6 +1379,11 @@ public class SignalAccount implements Closeable {
|
||||||
return localPniRegistrationId;
|
return localPniRegistrationId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setLocalPniRegistrationId(final int localPniRegistrationId) {
|
||||||
|
this.localPniRegistrationId = localPniRegistrationId;
|
||||||
|
save();
|
||||||
|
}
|
||||||
|
|
||||||
public String getPassword() {
|
public String getPassword() {
|
||||||
return password;
|
return password;
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,7 +19,7 @@ public class MessageCacheUtils {
|
||||||
try (var f = new FileInputStream(file)) {
|
try (var f = new FileInputStream(file)) {
|
||||||
var in = new DataInputStream(f);
|
var in = new DataInputStream(f);
|
||||||
var version = in.readInt();
|
var version = in.readInt();
|
||||||
if (version > 7) {
|
if (version > 8) {
|
||||||
// Unsupported envelope version
|
// Unsupported envelope version
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -71,6 +71,10 @@ public class MessageCacheUtils {
|
||||||
if (version >= 7) {
|
if (version >= 7) {
|
||||||
isStory = in.readBoolean();
|
isStory = in.readBoolean();
|
||||||
}
|
}
|
||||||
|
String updatedPni = null;
|
||||||
|
if (version >= 8) {
|
||||||
|
updatedPni = in.readUTF();
|
||||||
|
}
|
||||||
Optional<SignalServiceAddress> addressOptional = sourceServiceId == null
|
Optional<SignalServiceAddress> addressOptional = sourceServiceId == null
|
||||||
? Optional.empty()
|
? Optional.empty()
|
||||||
: Optional.of(new SignalServiceAddress(sourceServiceId, source));
|
: Optional.of(new SignalServiceAddress(sourceServiceId, source));
|
||||||
|
@ -84,6 +88,7 @@ public class MessageCacheUtils {
|
||||||
uuid,
|
uuid,
|
||||||
destinationUuid == null ? UuidUtil.UNKNOWN_UUID.toString() : destinationUuid,
|
destinationUuid == null ? UuidUtil.UNKNOWN_UUID.toString() : destinationUuid,
|
||||||
isUrgent,
|
isUrgent,
|
||||||
|
updatedPni == null ? "" : updatedPni,
|
||||||
isStory);
|
isStory);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -91,7 +96,7 @@ public class MessageCacheUtils {
|
||||||
public static void storeEnvelope(SignalServiceEnvelope envelope, File file) throws IOException {
|
public static void storeEnvelope(SignalServiceEnvelope envelope, File file) throws IOException {
|
||||||
try (var f = new FileOutputStream(file)) {
|
try (var f = new FileOutputStream(file)) {
|
||||||
try (var out = new DataOutputStream(f)) {
|
try (var out = new DataOutputStream(f)) {
|
||||||
out.writeInt(7); // version
|
out.writeInt(8); // version
|
||||||
out.writeInt(envelope.getType());
|
out.writeInt(envelope.getType());
|
||||||
out.writeUTF(""); // legacy number
|
out.writeUTF(""); // legacy number
|
||||||
out.writeUTF(envelope.getSourceUuid().isPresent() ? envelope.getSourceUuid().get() : "");
|
out.writeUTF(envelope.getSourceUuid().isPresent() ? envelope.getSourceUuid().get() : "");
|
||||||
|
@ -111,6 +116,7 @@ public class MessageCacheUtils {
|
||||||
out.writeLong(envelope.getServerDeliveredTimestamp());
|
out.writeLong(envelope.getServerDeliveredTimestamp());
|
||||||
out.writeBoolean(envelope.isUrgent());
|
out.writeBoolean(envelope.isUrgent());
|
||||||
out.writeBoolean(envelope.isStory());
|
out.writeBoolean(envelope.isStory());
|
||||||
|
out.writeUTF(envelope.getUpdatedPni() == null ? "" : envelope.getUpdatedPni());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue