diff --git a/lib/src/main/java/org/asamk/signal/manager/Manager.java b/lib/src/main/java/org/asamk/signal/manager/Manager.java index cde2714f..cc57e061 100644 --- a/lib/src/main/java/org/asamk/signal/manager/Manager.java +++ b/lib/src/main/java/org/asamk/signal/manager/Manager.java @@ -81,6 +81,9 @@ import org.whispersystems.libsignal.IdentityKeyPair; import org.whispersystems.libsignal.InvalidKeyException; import org.whispersystems.libsignal.InvalidMessageException; import org.whispersystems.libsignal.ecc.ECPublicKey; +import org.whispersystems.libsignal.fingerprint.Fingerprint; +import org.whispersystems.libsignal.fingerprint.FingerprintParsingException; +import org.whispersystems.libsignal.fingerprint.FingerprintVersionMismatchException; import org.whispersystems.libsignal.state.PreKeyRecord; import org.whispersystems.libsignal.state.SignedPreKeyRecord; import org.whispersystems.libsignal.util.Pair; @@ -2668,6 +2671,25 @@ public class Manager implements Closeable { TrustLevel.TRUSTED_VERIFIED); } + /** + * Trust this the identity with this scannable safety number + * + * @param name username of the identity + * @param safetyNumber Scannable safety number + */ + public boolean trustIdentityVerifiedSafetyNumber(String name, byte[] safetyNumber) throws InvalidNumberException { + var recipientId = canonicalizeAndResolveRecipient(name); + var address = account.getRecipientStore().resolveServiceAddress(recipientId); + return trustIdentity(recipientId, identityKey -> { + final var fingerprint = computeSafetyNumberFingerprint(address, identityKey); + try { + return fingerprint != null && fingerprint.getScannableFingerprint().compareTo(safetyNumber); + } catch (FingerprintVersionMismatchException | FingerprintParsingException e) { + return false; + } + }, TrustLevel.TRUSTED_VERIFIED); + } + /** * Trust all keys of this identity without verification * @@ -2717,21 +2739,23 @@ public class Manager implements Closeable { } public String computeSafetyNumber(SignalServiceAddress theirAddress, IdentityKey theirIdentityKey) { - final var fingerprint = Utils.computeSafetyNumber(capabilities.isUuid(), - account.getSelfAddress(), - getIdentityKeyPair().getPublicKey(), - theirAddress, - theirIdentityKey); + final Fingerprint fingerprint = computeSafetyNumberFingerprint(theirAddress, theirIdentityKey); return fingerprint == null ? null : fingerprint.getDisplayableFingerprint().getDisplayText(); } public byte[] computeSafetyNumberForScanning(SignalServiceAddress theirAddress, IdentityKey theirIdentityKey) { - final var fingerprint = Utils.computeSafetyNumber(capabilities.isUuid(), + final Fingerprint fingerprint = computeSafetyNumberFingerprint(theirAddress, theirIdentityKey); + return fingerprint == null ? null : fingerprint.getScannableFingerprint().getSerialized(); + } + + private Fingerprint computeSafetyNumberFingerprint( + final SignalServiceAddress theirAddress, final IdentityKey theirIdentityKey + ) { + return Utils.computeSafetyNumber(capabilities.isUuid(), account.getSelfAddress(), getIdentityKeyPair().getPublicKey(), theirAddress, theirIdentityKey); - return fingerprint == null ? null : fingerprint.getScannableFingerprint().getSerialized(); } @Deprecated diff --git a/src/main/java/org/asamk/signal/commands/TrustCommand.java b/src/main/java/org/asamk/signal/commands/TrustCommand.java index 78f22c19..65487ba7 100644 --- a/src/main/java/org/asamk/signal/commands/TrustCommand.java +++ b/src/main/java/org/asamk/signal/commands/TrustCommand.java @@ -11,6 +11,7 @@ import org.asamk.signal.manager.Manager; import org.asamk.signal.util.Hex; import org.whispersystems.signalservice.api.util.InvalidNumberException; +import java.util.Base64; import java.util.Locale; public class TrustCommand implements JsonRpcLocalCommand { @@ -49,44 +50,59 @@ public class TrustCommand implements JsonRpcLocalCommand { } } else { var safetyNumber = ns.getString("verified-safety-number"); - if (safetyNumber != null) { - safetyNumber = safetyNumber.replaceAll(" ", ""); - if (safetyNumber.length() == 66) { - byte[] fingerprintBytes; - try { - fingerprintBytes = Hex.toByteArray(safetyNumber.toLowerCase(Locale.ROOT)); - } catch (Exception e) { - throw new UserErrorException( - "Failed to parse the fingerprint, make sure the fingerprint is a correctly encoded hex string without additional characters."); - } - boolean res; - try { - res = m.trustIdentityVerified(number, fingerprintBytes); - } catch (InvalidNumberException e) { - throw new UserErrorException("Failed to parse recipient: " + e.getMessage()); - } - if (!res) { - throw new UserErrorException( - "Failed to set the trust for the fingerprint of this number, make sure the number and the fingerprint are correct."); - } - } else if (safetyNumber.length() == 60) { - boolean res; - try { - res = m.trustIdentityVerifiedSafetyNumber(number, safetyNumber); - } catch (InvalidNumberException e) { - throw new UserErrorException("Failed to parse recipient: " + e.getMessage()); - } - if (!res) { - throw new UserErrorException( - "Failed to set the trust for the safety number of this phone number, make sure the phone number and the safety number are correct."); - } - } else { + if (safetyNumber == null) { + throw new UserErrorException( + "You need to specify the fingerprint/safety number you have verified with -v SAFETY_NUMBER"); + } + + safetyNumber = safetyNumber.replaceAll(" ", ""); + if (safetyNumber.length() == 66) { + byte[] fingerprintBytes; + try { + fingerprintBytes = Hex.toByteArray(safetyNumber.toLowerCase(Locale.ROOT)); + } catch (Exception e) { + throw new UserErrorException( + "Failed to parse the fingerprint, make sure the fingerprint is a correctly encoded hex string without additional characters."); + } + boolean res; + try { + res = m.trustIdentityVerified(number, fingerprintBytes); + } catch (InvalidNumberException e) { + throw new UserErrorException("Failed to parse recipient: " + e.getMessage()); + } + if (!res) { + throw new UserErrorException( + "Failed to set the trust for the fingerprint of this number, make sure the number and the fingerprint are correct."); + } + } else if (safetyNumber.length() == 60) { + boolean res; + try { + res = m.trustIdentityVerifiedSafetyNumber(number, safetyNumber); + } catch (InvalidNumberException e) { + throw new UserErrorException("Failed to parse recipient: " + e.getMessage()); + } + if (!res) { + throw new UserErrorException( + "Failed to set the trust for the safety number of this phone number, make sure the phone number and the safety number are correct."); + } + } else { + final byte[] scannableSafetyNumber; + try { + scannableSafetyNumber = Base64.getDecoder().decode(safetyNumber); + } catch (IllegalArgumentException e) { throw new UserErrorException( "Safety number has invalid format, either specify the old hex fingerprint or the new safety number"); } - } else { - throw new UserErrorException( - "You need to specify the fingerprint/safety number you have verified with -v SAFETY_NUMBER"); + boolean res; + try { + res = m.trustIdentityVerifiedSafetyNumber(number, scannableSafetyNumber); + } catch (InvalidNumberException e) { + throw new UserErrorException("Failed to parse recipient: " + e.getMessage()); + } + if (!res) { + throw new UserErrorException( + "Failed to set the trust for the safety number of this phone number, make sure the phone number and the safety number are correct."); + } } } }